Improved Wave startup logging
This commit is contained in:
parent
eded7f08d5
commit
452c93fca0
140
Wave/Program.cs
140
Wave/Program.cs
|
@ -6,8 +6,6 @@
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.Metrics;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StackExchange.Redis;
|
||||
using Tomlyn.Extensions.Configuration;
|
||||
|
@ -17,31 +15,33 @@
|
|||
using Wave.Services;
|
||||
using Wave.Utilities;
|
||||
|
||||
var logMessages = new List<string>();
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Configuration
|
||||
.AddJsonFile("/configuration/config.json", true, false)
|
||||
.AddYamlFile("/configuration/config.yml", true, false)
|
||||
.AddTomlFile("/configuration/config.toml", true, false)
|
||||
.AddIniFile( "/configuration/config.ini", true, false)
|
||||
.AddXmlFile( "/configuration/config.xml", true, false)
|
||||
.AddEnvironmentVariables("WAVE_");
|
||||
.AddJsonFile("/configuration/config.json", true, false)
|
||||
.AddYamlFile("/configuration/config.yml", true, false)
|
||||
.AddTomlFile("/configuration/config.toml", true, false)
|
||||
.AddIniFile( "/configuration/config.ini", true, false)
|
||||
.AddXmlFile( "/configuration/config.xml", true, false)
|
||||
.AddEnvironmentVariables("WAVE_");
|
||||
|
||||
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
|
||||
builder.Services.AddControllers(options => {
|
||||
options.OutputFormatters.Add(new SyndicationFeedFormatter());
|
||||
options.OutputFormatters.Add(new SyndicationFeedFormatter());
|
||||
});
|
||||
builder.Services.AddOutputCache();
|
||||
|
||||
#region Data Protection & Redis
|
||||
|
||||
if (builder.Configuration.GetConnectionString("Redis") is { } redisUri) {
|
||||
var redis = ConnectionMultiplexer.Connect(redisUri);
|
||||
builder.Services.AddDataProtection()
|
||||
.PersistKeysToStackExchangeRedis(redis)
|
||||
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() {
|
||||
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
|
||||
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
|
||||
});
|
||||
var redis = ConnectionMultiplexer.Connect(redisUri);
|
||||
builder.Services.AddDataProtection()
|
||||
.PersistKeysToStackExchangeRedis(redis)
|
||||
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() {
|
||||
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
|
||||
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
|
||||
});
|
||||
builder.Services.AddStackExchangeRedisCache(options => {
|
||||
options.Configuration = redisUri;
|
||||
options.InstanceName = "WaveDistributedCache";
|
||||
|
@ -51,12 +51,12 @@
|
|||
options.InstanceName = "WaveOutputCache";
|
||||
});
|
||||
} else {
|
||||
builder.Services.AddDataProtection()
|
||||
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() {
|
||||
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
|
||||
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
|
||||
});
|
||||
Console.WriteLine("No Redis connection string found.");
|
||||
builder.Services.AddDataProtection()
|
||||
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() {
|
||||
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
|
||||
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
|
||||
});
|
||||
logMessages.Add("No Redis connection string found.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -73,56 +73,56 @@
|
|||
// Moderators: Can delete Articles / take them Offline
|
||||
// Admins: Can do anything, and assign roles to other users
|
||||
builder.Services.AddAuthorizationBuilder()
|
||||
.AddPolicy("ArticleEditPermissions", p => p.RequireRole("Author", "Admin"))
|
||||
.AddPolicy("ArticleReviewPermissions", p => p.RequireRole("Reviewer", "Admin"))
|
||||
.AddPolicy("ArticleDeletePermissions", p => p.RequireRole("Moderator", "Admin"))
|
||||
.AddPolicy("CategoryManagePermissions", p => p.RequireRole("Admin"))
|
||||
.AddPolicy("RoleAssignPermissions", p => p.RequireRole("Admin"))
|
||||
.AddPolicy("ArticleEditPermissions", p => p.RequireRole("Author", "Admin"))
|
||||
.AddPolicy("ArticleReviewPermissions", p => p.RequireRole("Reviewer", "Admin"))
|
||||
.AddPolicy("ArticleDeletePermissions", p => p.RequireRole("Moderator", "Admin"))
|
||||
.AddPolicy("CategoryManagePermissions", p => p.RequireRole("Admin"))
|
||||
.AddPolicy("RoleAssignPermissions", p => p.RequireRole("Admin"))
|
||||
|
||||
.AddPolicy("ArticleEditOrReviewPermissions", p => p.RequireRole("Author", "Reviewer", "Admin"));
|
||||
.AddPolicy("ArticleEditOrReviewPermissions", p => p.RequireRole("Author", "Reviewer", "Admin"));
|
||||
builder.Services.AddAuthentication(options => {
|
||||
options.DefaultScheme = IdentityConstants.ApplicationScheme;
|
||||
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
|
||||
}).AddIdentityCookies();
|
||||
options.DefaultScheme = IdentityConstants.ApplicationScheme;
|
||||
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
|
||||
}).AddIdentityCookies();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Identity
|
||||
|
||||
string connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
|
||||
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
||||
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
||||
builder.Services.AddDbContextFactory<ApplicationDbContext>(options =>
|
||||
options.UseNpgsql(connectionString));
|
||||
options.UseNpgsql(connectionString));
|
||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||
|
||||
builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddRoles<IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddSignInManager()
|
||||
.AddDefaultTokenProviders()
|
||||
.AddClaimsPrincipalFactory<UserClaimsFactory>();
|
||||
.AddRoles<IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddSignInManager()
|
||||
.AddDefaultTokenProviders()
|
||||
.AddClaimsPrincipalFactory<UserClaimsFactory>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Services
|
||||
|
||||
builder.Services.AddLocalization(options => {
|
||||
options.ResourcesPath = "Resources";
|
||||
options.ResourcesPath = "Resources";
|
||||
});
|
||||
builder.Services.AddScoped<ImageService>();
|
||||
builder.Services.AddHttpClient();
|
||||
|
||||
builder.Services.Configure<Customization>(builder.Configuration.GetSection(nameof(Customization)));
|
||||
builder.Services.AddCascadingValue("TitlePrefix",
|
||||
sf => (sf.GetService<IOptions<Customization>>()?.Value.AppName ?? "Wave") + " - ");
|
||||
sf => (sf.GetService<IOptions<Customization>>()?.Value.AppName ?? "Wave") + " - ");
|
||||
|
||||
var smtpConfig = builder.Configuration.GetSection("Email:Smtp");
|
||||
if (smtpConfig.Exists()) {
|
||||
builder.Services.Configure<SmtpConfiguration>(smtpConfig);
|
||||
builder.Services.AddScoped<IEmailSender<ApplicationUser>, SmtpEmailSender>();
|
||||
builder.Services.Configure<SmtpConfiguration>(smtpConfig);
|
||||
builder.Services.AddScoped<IEmailSender<ApplicationUser>, SmtpEmailSender>();
|
||||
} else {
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
Console.WriteLine("No Email provider configured.");
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
logMessages.Add("No Email provider configured.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -130,30 +130,30 @@
|
|||
|
||||
string[] cultures = ["en-US", "en-GB", "de-DE"];
|
||||
builder.Services.Configure<RequestLocalizationOptions>(options => {
|
||||
options.ApplyCurrentCultureToResponseHeaders = true;
|
||||
options.FallBackToParentCultures = true;
|
||||
options.FallBackToParentUICultures = true;
|
||||
options.SetDefaultCulture(cultures[0])
|
||||
.AddSupportedCultures(cultures)
|
||||
.AddSupportedUICultures(cultures);
|
||||
options.ApplyCurrentCultureToResponseHeaders = true;
|
||||
options.FallBackToParentCultures = true;
|
||||
options.FallBackToParentUICultures = true;
|
||||
options.SetDefaultCulture(cultures[0])
|
||||
.AddSupportedCultures(cultures)
|
||||
.AddSupportedUICultures(cultures);
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment()) {
|
||||
app.UseMigrationsEndPoint();
|
||||
app.UseMigrationsEndPoint();
|
||||
} else {
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
}
|
||||
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions {
|
||||
ContentTypeProvider = new FileExtensionContentTypeProvider {
|
||||
Mappings = {
|
||||
[".jxl"] = "image/jxl"
|
||||
}
|
||||
}
|
||||
ContentTypeProvider = new FileExtensionContentTypeProvider {
|
||||
Mappings = {
|
||||
[".jxl"] = "image/jxl"
|
||||
}
|
||||
}
|
||||
});
|
||||
app.UseAntiforgery();
|
||||
|
||||
|
@ -167,20 +167,22 @@
|
|||
|
||||
app.UseRequestLocalization();
|
||||
|
||||
foreach (string message in logMessages) {
|
||||
app.Logger.LogInformation("{message}", message);
|
||||
}
|
||||
|
||||
{
|
||||
using var scope = app.Services.CreateScope();
|
||||
using var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
context.Database.Migrate();
|
||||
using var scope = app.Services.CreateScope();
|
||||
using var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
context.Database.Migrate();
|
||||
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
|
||||
if (userManager.GetUsersInRoleAsync("Admin").Result.Any() is false) {
|
||||
string admin = Guid.NewGuid().ToString("N")[..16];
|
||||
Console.WriteLine(
|
||||
"There is currently no user in your installation with the admin role, " +
|
||||
"go to /Admin and use the following password to self promote your account: " + admin);
|
||||
File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "admin.txt"), admin);
|
||||
}
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
if (userManager.GetUsersInRoleAsync("Admin").Result.Any() is false) {
|
||||
string admin = Guid.NewGuid().ToString("N")[..16];
|
||||
app.Logger.LogWarning("There is currently no user in your installation with the admin role, " +
|
||||
"go to /Admin and use the following password to self promote your account: {admin}", admin);
|
||||
File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "admin.txt"), admin);
|
||||
}
|
||||
}
|
||||
|
||||
app.Run();
|
||||
|
|
Loading…
Reference in a new issue