diff --git a/NetEvent/Server/Data/SystemSettings/ISystemSetttingsManager.cs b/NetEvent/Server/Data/SystemSettings/ISystemSetttingsManager.cs new file mode 100644 index 00000000..7c76fe90 --- /dev/null +++ b/NetEvent/Server/Data/SystemSettings/ISystemSetttingsManager.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; + +using NetEvent.Server.Models; + +namespace NetEvent.Server.Data.SystemSettings +{ + public interface ISystemSettingsManager + { + Task UpdateAsync(SystemSettingValue systemSettingValueToUpdate); + + } +} diff --git a/NetEvent/Server/Data/SystemSettings/SystemSettingsError.cs b/NetEvent/Server/Data/SystemSettings/SystemSettingsError.cs new file mode 100644 index 00000000..77dc841d --- /dev/null +++ b/NetEvent/Server/Data/SystemSettings/SystemSettingsError.cs @@ -0,0 +1,16 @@ +namespace NetEvent.Server.Data.SystemSettings +{ + /// + /// Encapsulates an error from the event subsystem. + /// + public class SystemSettingsError + { + /// + /// Gets or sets the description for this error. + /// + /// + /// The description for this error. + /// + public string? Description { get; set; } + } +} diff --git a/NetEvent/Server/Data/SystemSettings/SystemSettingsManager.cs b/NetEvent/Server/Data/SystemSettings/SystemSettingsManager.cs new file mode 100644 index 00000000..9931ab82 --- /dev/null +++ b/NetEvent/Server/Data/SystemSettings/SystemSettingsManager.cs @@ -0,0 +1,65 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using NetEvent.Server.Models; +using System.Globalization; +using Slugify; + +namespace NetEvent.Server.Data.SystemSettings +{ + public class SystemSettingsManager : ISystemSettingsManager + { + private readonly ApplicationDbContext _DbContext; + private readonly ILogger _Logger; + private readonly ISlugHelper _SlugHelper; + + public SystemSettingsManager(ApplicationDbContext dbContext, ILogger logger, ISlugHelper slugHelper) + { + _DbContext = dbContext; + _Logger = logger; + _SlugHelper = slugHelper; + } + + protected CancellationToken CancellationToken => CancellationToken.None; + + + public async Task UpdateAsync(SystemSettingValue systemSettingValueToUpdate) + { + + if (systemSettingValueToUpdate?.Key == null) + { + _Logger.LogError("Empty key is not allowed"); + return SystemSettingsResult.Failed(new SystemSettingsError { Description = "Empty key is not allowed" }); + } + + + var result = _DbContext.SystemSettingValues.Update(systemSettingValueToUpdate); + + if (result.State == EntityState.Modified) + { + await _DbContext.SaveChangesAsync(); + CheckForCultureChange(systemSettingValueToUpdate); + _Logger.LogInformation("Successfully updated Systemsetting {name}", systemSettingValueToUpdate.Key); + return SystemSettingsResult.Success; + } + + _Logger.LogError("Error updating Systemsetting {name}", systemSettingValueToUpdate.Key); + return SystemSettingsResult.Failed(new SystemSettingsError()); + + + } + + + private void CheckForCultureChange(SystemSettingValue systemSettingValueToUpdate) + { + if (systemSettingValueToUpdate?.Key == NetEvent.Shared.Config.SystemSettings.OrganizationData.DataCultureInfo && systemSettingValueToUpdate.SerializedValue != null) + { + var cultureInfo = new CultureInfo(systemSettingValueToUpdate.SerializedValue); + CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + } + } + + } +} diff --git a/NetEvent/Server/Data/SystemSettings/SystemSettingsResult.cs b/NetEvent/Server/Data/SystemSettings/SystemSettingsResult.cs new file mode 100644 index 00000000..c4fb38cb --- /dev/null +++ b/NetEvent/Server/Data/SystemSettings/SystemSettingsResult.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace NetEvent.Server.Data.SystemSettings +{ + /// + /// Represents the result of an Event operation. + /// + public class SystemSettingsResult + { + private static readonly SystemSettingsResult _Success = new() { Succeeded = true }; + private readonly List _Errors = new(); + + /// + /// Flag indicating whether if the operation succeeded or not. + /// + /// True if the operation succeeded, otherwise false. + public bool Succeeded { get; protected set; } + + /// + /// An of instances containing errors + /// that occurred during the Event operation. + /// + /// An of instances. + public IEnumerable Errors => _Errors; + + /// + /// Returns an indicating a successful Event operation. + /// + /// An indicating a successful operation. + public static SystemSettingsResult Success => _Success; + + /// + /// Creates an indicating a failed Event operation, with a list of if applicable. + /// + /// An optional array of s which caused the operation to fail. + /// An indicating a failed Event operation, with a list of if applicable. + public static SystemSettingsResult Failed(params SystemSettingsError[] errors) + { + var result = new SystemSettingsResult { Succeeded = false }; + if (errors != null) + { + result._Errors.AddRange(errors); + } + + return result; + } + + /// + /// Converts the value of the current object to its equivalent string representation. + /// + /// A string representation of the current object. + /// + /// If the operation was successful the ToString() will return "Succeeded" otherwise it returned + /// "Failed : " followed by a comma delimited list of error codes from its collection, if any. + /// + public override string ToString() + { + return Succeeded ? + "Succeeded" : + string.Format(CultureInfo.InvariantCulture, "{0} : {1}", "Failed", string.Join(",", Errors.Select(x => x.Description).ToList())); + } + } +} diff --git a/NetEvent/Server/Extensions/DefaultCultureExtension.cs b/NetEvent/Server/Extensions/DefaultCultureExtension.cs new file mode 100644 index 00000000..d02db782 --- /dev/null +++ b/NetEvent/Server/Extensions/DefaultCultureExtension.cs @@ -0,0 +1,46 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; +using NetEvent.Server.Data; +using NetEvent.Shared.Config; + +namespace NetEvent.Server.Extensions; + +public static class DefaultCultureExtension +{ + public static async Task SetDefaultCulture(this WebApplication app) + { + var logger = app.Services.GetRequiredService>(); + + try + { + using (var scope = app.Services.GetRequiredService().CreateScope()) + { + using (var context = scope.ServiceProvider.GetRequiredService()) + { + + var organizationCulture = await context.SystemSettingValues.Where(s => s.Key == SystemSettings.OrganizationData.DataCultureInfo).FirstAsync().ConfigureAwait(false); + + if (organizationCulture?.SerializedValue == null) + { + return; + } + + var cultureInfo = new CultureInfo(organizationCulture.SerializedValue); + CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + } + } + } + catch (Exception ex) + { + logger.LogError(ex, "Unable to get Culture"); + } + + } +} diff --git a/NetEvent/Server/Localize.cs b/NetEvent/Server/Localize.cs new file mode 100644 index 00000000..4c553da8 --- /dev/null +++ b/NetEvent/Server/Localize.cs @@ -0,0 +1,6 @@ +namespace NetEvent.Server +{ + public class Localize + { + } +} diff --git a/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs b/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs index b1f9beec..901ffee1 100644 --- a/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs +++ b/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs @@ -1,71 +1,80 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using MediatR; -using NetEvent.Shared.Dto; - -namespace NetEvent.Server.Modules.System.Endpoints -{ - public static class GetSystemInfo - { - public sealed class Handler : IRequestHandler - { - public Handler() - { - } - - public Task Handle(Request request, CancellationToken cancellationToken) - { - var systeminfocomponents = new List(); - var systeminfohealth = new List(); - var systeminfoversions = new List(); - - AppDomain currentDomain = AppDomain.CurrentDomain; - Assembly[] assems = currentDomain.GetAssemblies(); - foreach (Assembly assem in assems) - { - systeminfocomponents.Add(new SystemInfoComponentEntryDto(assem.ManifestModule.Name, assem.ToString())); - } - - systeminfoversions.Add(new SystemInfoVersionEntryDto("NETEVENT", Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion)); - systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("BUILDNODE")); - systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("BUILDID")); - systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("BUILDNUMBER")); - systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("SOURCE_COMMIT")); - - // TODO: think about healthchecks and healthcheck modularity (to perform checks on various services like game servers, the mail server, payment apis ...) and remove dummy services - systeminfohealth.Add(new SystemInfoHealthEntryDto("NETEVENT Server", string.Empty, true)); - systeminfohealth.Add(new SystemInfoHealthEntryDto("Email Service", "servername", false)); - - var systeminfo = new SystemInfoDto(systeminfocomponents, systeminfohealth, systeminfoversions); - - return Task.FromResult(new Response(systeminfo)); - } - - private static SystemInfoVersionEntryDto CreateSystemInfoVersionEntryFromEnv(string envName) - { - return new SystemInfoVersionEntryDto(envName, string.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName)) ? "dev" : Environment.GetEnvironmentVariable(envName)); - } - } - - public sealed class Request : IRequest - { - public Request() - { - } - } - - public sealed class Response : ResponseBase - { - public Response(SystemInfoDto value) : base(value) - { - } - - public Response(ReturnType returnType, string error) : base(returnType, error) - { - } - } - } -} +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using Microsoft.Extensions.Localization; +using NetEvent.Shared.Dto; + +namespace NetEvent.Server.Modules.System.Endpoints +{ + public static class GetSystemInfo + { + public sealed class Handler : IRequestHandler + { + // TODO: remove localizer as soon as it is implemented somewhere where it makes sense + private IStringLocalizer Localizer { get; set; } + + // TODO: remove localizer as soon as it is implemented somewhere where it makes sense + public Handler(IStringLocalizer localizer) + { + Localizer = localizer; + } + + public Task Handle(Request request, CancellationToken cancellationToken) + { + var systeminfocomponents = new List(); + var systeminfohealth = new List(); + var systeminfoversions = new List(); + + AppDomain currentDomain = AppDomain.CurrentDomain; + Assembly[] assems = currentDomain.GetAssemblies(); + foreach (Assembly assem in assems) + { + systeminfocomponents.Add(new SystemInfoComponentEntryDto(assem.ManifestModule.Name, assem.ToString())); + } + + systeminfoversions.Add(new SystemInfoVersionEntryDto("NETEVENT", Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion)); + systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("BUILDNODE")); + systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("BUILDID")); + systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("BUILDNUMBER")); + systeminfoversions.Add(CreateSystemInfoVersionEntryFromEnv("SOURCE_COMMIT")); + + // TODO: think about healthchecks and healthcheck modularity (to perform checks on various services like game servers, the mail server, payment apis ...) and remove dummy services + systeminfohealth.Add(new SystemInfoHealthEntryDto("NETEVENT Server", string.Empty, true)); + systeminfohealth.Add(new SystemInfoHealthEntryDto("Email Service", "servername", false)); + + var systeminfo = new SystemInfoDto(systeminfocomponents, systeminfohealth, systeminfoversions); + + // TODO: remove localizer as soon as it is implemented somewhere where it makes sense + Console.WriteLine(Localizer["test.test"]); + + return Task.FromResult(new Response(systeminfo)); + } + + private static SystemInfoVersionEntryDto CreateSystemInfoVersionEntryFromEnv(string envName) + { + return new SystemInfoVersionEntryDto(envName, string.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName)) ? "dev" : Environment.GetEnvironmentVariable(envName)); + } + } + + public sealed class Request : IRequest + { + public Request() + { + } + } + + public sealed class Response : ResponseBase + { + public Response(SystemInfoDto value) : base(value) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs index cf5b59c5..5e707f48 100644 --- a/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs +++ b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs @@ -1,71 +1,64 @@ -using System.Threading; -using System.Threading.Tasks; -using MediatR; -using NetEvent.Server.Data; -using NetEvent.Server.Models; -using NetEvent.Shared; -using NetEvent.Shared.Config; -using NetEvent.Shared.Dto; - -namespace NetEvent.Server.Modules.System.Endpoints -{ - public static class PostSystemSetting - { - public sealed class Handler : IRequestHandler - { - private readonly ApplicationDbContext _ApplicationDbContext; - - public Handler(ApplicationDbContext applicationDbContext) - { - _ApplicationDbContext = applicationDbContext; - } - - public async Task Handle(Request request, CancellationToken cancellationToken) - { - if (request.SystemSettingValue?.Key == null) - { - return new Response(ReturnType.Error, "Empty key is not allowed"); - } - - var data = await _ApplicationDbContext.FindAsync(new object[] { request.SystemSettingValue.Key }, cancellationToken); - if (data != null) - { - data.SerializedValue = request.SystemSettingValue.Value; - } - else - { - var serverData = request.SystemSettingValue.ToSystemSettingValue(); - await _ApplicationDbContext.AddAsync(serverData, cancellationToken); - } - - await _ApplicationDbContext.SaveChangesAsync(cancellationToken); - - return new Response(); - } - } - - public sealed class Request : IRequest - { - public Request(SystemSettingGroup systemSettingGroup, SystemSettingValueDto systemSettingValue) - { - SystemSettingGroup = systemSettingGroup; - SystemSettingValue = systemSettingValue; - } - - public SystemSettingGroup SystemSettingGroup { get; } - - public SystemSettingValueDto SystemSettingValue { get; } - } - - public sealed class Response : ResponseBase - { - public Response() - { - } - - public Response(ReturnType returnType, string error) : base(returnType, error) - { - } - } - } -} +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Shared; +using NetEvent.Shared.Config; +using NetEvent.Shared.Dto; +using NetEvent.Server.Data.SystemSettings; +using System; + +namespace NetEvent.Server.Modules.System.Endpoints +{ + public static class PostSystemSetting + { + public sealed class Handler : IRequestHandler + { + private readonly ISystemSettingsManager _SystemSettingsManager; + + public Handler(ISystemSettingsManager systemSettingsManager) + { + _SystemSettingsManager = systemSettingsManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + + var newSystemSettingValue = request.SystemSettingValue.ToSystemSettingValue(); + var result = await _SystemSettingsManager.UpdateAsync(newSystemSettingValue).ConfigureAwait(false); + if (!result.Succeeded) + { + return new Response(ReturnType.Error, string.Join(Environment.NewLine, result.Errors)); + } + + return new Response(newSystemSettingValue.ToSystemSettingValueDto()); + + } + } + + public sealed class Request : IRequest + { + public Request(SystemSettingGroup systemSettingGroup, SystemSettingValueDto systemSettingValue) + { + SystemSettingGroup = systemSettingGroup; + SystemSettingValue = systemSettingValue; + } + + public SystemSettingGroup SystemSettingGroup { get; } + + public SystemSettingValueDto SystemSettingValue { get; } + } + + + public sealed class Response : ResponseBase + { + public Response(SystemSettingValueDto updatedSystemSetting) : base(updatedSystemSetting) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + + } +} diff --git a/NetEvent/Server/NetEvent.Server.csproj b/NetEvent/Server/NetEvent.Server.csproj index 96b71197..061aef07 100644 --- a/NetEvent/Server/NetEvent.Server.csproj +++ b/NetEvent/Server/NetEvent.Server.csproj @@ -52,4 +52,10 @@ + + + Designer + + + diff --git a/NetEvent/Server/Program.cs b/NetEvent/Server/Program.cs index 358d871e..360cec37 100644 --- a/NetEvent/Server/Program.cs +++ b/NetEvent/Server/Program.cs @@ -1,179 +1,186 @@ -using System; -using System.Globalization; -using System.Net; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; -using NetEvent.Server.Configuration; -using NetEvent.Server.Data; -using NetEvent.Server.Data.Events; -using NetEvent.Server.Middleware; -using NetEvent.Server.Models; -using NetEvent.Server.Modules; -using NetEvent.Server.Services; -using NetEvent.Shared.Policy; -using Slugify; - -const int _DefaultPort = 5001; - -var builder = WebApplication.CreateBuilder(args); - -if (builder.Configuration == null) -{ - return; -} - -builder.WebHost.ConfigureKestrel((context, options) => -{ - options.ListenAnyIP(_DefaultPort, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; - listenOptions.UseHttps(); - }); -}); - -switch (builder.Configuration["DBProvider"]?.ToLower(CultureInfo.InvariantCulture)) -{ - case "sqlite": - { - builder.Services.AddDbContext(); - builder.Services.AddHealthChecks().AddDbContextCheck(); - } - - break; - case "psql": - { - builder.Services.AddDbContext(); - builder.Services.AddHealthChecks().AddDbContextCheck(); - } - - break; - default: - { - throw new NotSupportedException($"DbProvider not recognized: {builder.Configuration["DBProvider"]}"); - } -} - -builder.Services.AddDefaultIdentity(options => - { - options.SignIn.RequireConfirmedAccount = true; - options.User.AllowedUserNameCharacters = string.Empty; - }) - .AddRoles() - .AddEntityFrameworkStores() - .AddUserManager() - .AddRoleManager() - .AddDefaultTokenProviders(); - -builder.Services.ConfigureApplicationCookie(options => -{ - options.Cookie.HttpOnly = false; - options.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, options.Events.OnRedirectToAccessDenied); - options.Events.OnRedirectToLogin = context => - { - context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; - return Task.CompletedTask; - }; -}); - -builder.Services.AddAuthentication().AddSteam(options => -{ - options.ApplicationKey = builder.Configuration?.GetSection("SteamConfig").Get()?.ApplicationKey; -}); -builder.Services.AddAuthorization(config => -{ - config.AddPolicies(); -}); - -builder.Services.RegisterModules(); - -builder.Services.AddRouting(options => options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer)); - -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); - -builder.Services.AddSingleton(); - -var emailConfig = builder.Configuration.GetSection("EmailConfig").Get(); - -if (emailConfig?.SendGridConfig != null) -{ - builder.Services.TryAddSingleton(emailConfig.SendGridConfig); - builder.Services.TryAddScoped(); -} -else if (emailConfig?.SmtpConfig != null) -{ - builder.Services.TryAddSingleton(emailConfig.SmtpConfig); - builder.Services.TryAddScoped(); -} -else -{ - builder.Services.TryAddScoped(); -} - -builder.WebHost.UseStaticWebAssets(); - -var app = builder.Build(); - -using (var scope = app.Services.GetRequiredService().CreateScope()) -{ - using var context = scope.ServiceProvider.GetRequiredService(); - if (context.Database.IsRelational()) - { - context.Database.Migrate(); - } -} - -if (app.Environment.IsDevelopment()) -{ - app.UseWebAssemblyDebugging(); - - app.UseSwagger(); - app.UseSwaggerUI(); -} -else -{ - app.UseHealthChecks("/healthz"); - app.UseHsts(); -} - -app.UseHttpsRedirection(); -app.UseBlazorFrameworkFiles(); -app.UseStaticFiles(); - -app.UseRouting(); -app.UseWebSockets(); - -app.UseAuthentication(); -app.UseAuthorization(); - -app.MapFallbackToFile("index.html"); - -app.MapEndpoints(); - -await app.RunAsync(); - -static Func, Task> ReplaceRedirector(HttpStatusCode statusCode, Func, Task> existingRedirector) => - context => - { - if (context.Request.Path.StartsWithSegments("/api")) - { - context.Response.StatusCode = (int)statusCode; - return Task.CompletedTask; - } - - return existingRedirector(context); - }; +using System; +using System.Globalization; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using NetEvent.Server.Configuration; +using NetEvent.Server.Data; +using NetEvent.Server.Data.Events; +using NetEvent.Server.Data.SystemSettings; +using NetEvent.Server.Extensions; +using NetEvent.Server.Middleware; +using NetEvent.Server.Models; +using NetEvent.Server.Modules; +using NetEvent.Server.Services; +using NetEvent.Shared.Policy; +using Slugify; + +const int _DefaultPort = 5001; + +var builder = WebApplication.CreateBuilder(args); + +if (builder.Configuration == null) +{ + return; +} + +builder.WebHost.ConfigureKestrel((context, options) => +{ + options.ListenAnyIP(_DefaultPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; + listenOptions.UseHttps(); + }); +}); + +builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); + +switch (builder.Configuration["DBProvider"]?.ToLower(CultureInfo.InvariantCulture)) +{ + case "sqlite": + { + builder.Services.AddDbContext(); + builder.Services.AddHealthChecks().AddDbContextCheck(); + } + + break; + case "psql": + { + builder.Services.AddDbContext(); + builder.Services.AddHealthChecks().AddDbContextCheck(); + } + + break; + default: + { + throw new NotSupportedException($"DbProvider not recognized: {builder.Configuration["DBProvider"]}"); + } +} + +builder.Services.AddDefaultIdentity(options => + { + options.SignIn.RequireConfirmedAccount = true; + options.User.AllowedUserNameCharacters = string.Empty; + }) + .AddRoles() + .AddEntityFrameworkStores() + .AddUserManager() + .AddRoleManager() + .AddDefaultTokenProviders(); + +builder.Services.ConfigureApplicationCookie(options => +{ + options.Cookie.HttpOnly = false; + options.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, options.Events.OnRedirectToAccessDenied); + options.Events.OnRedirectToLogin = context => + { + context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + return Task.CompletedTask; + }; +}); + +builder.Services.AddAuthentication().AddSteam(options => +{ + options.ApplicationKey = builder.Configuration?.GetSection("SteamConfig").Get()?.ApplicationKey; +}); +builder.Services.AddAuthorization(config => +{ + config.AddPolicies(); +}); + +builder.Services.RegisterModules(); + +builder.Services.AddRouting(options => options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer)); + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddSingleton(); + +var emailConfig = builder.Configuration.GetSection("EmailConfig").Get(); + +if (emailConfig?.SendGridConfig != null) +{ + builder.Services.TryAddSingleton(emailConfig.SendGridConfig); + builder.Services.TryAddScoped(); +} +else if (emailConfig?.SmtpConfig != null) +{ + builder.Services.TryAddSingleton(emailConfig.SmtpConfig); + builder.Services.TryAddScoped(); +} +else +{ + builder.Services.TryAddScoped(); +} + +builder.WebHost.UseStaticWebAssets(); + +var app = builder.Build(); + +using (var scope = app.Services.GetRequiredService().CreateScope()) +{ + using var context = scope.ServiceProvider.GetRequiredService(); + if (context.Database.IsRelational()) + { + context.Database.Migrate(); + } +} + +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); + + app.UseSwagger(); + app.UseSwaggerUI(); +} +else +{ + app.UseHealthChecks("/healthz"); + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseBlazorFrameworkFiles(); +app.UseStaticFiles(); + +app.UseRouting(); +app.UseWebSockets(); + +app.UseAuthentication(); +app.UseAuthorization(); + +app.MapFallbackToFile("index.html"); + +app.MapEndpoints(); + +await app.SetDefaultCulture(); + +await app.RunAsync(); + +static Func, Task> ReplaceRedirector(HttpStatusCode statusCode, Func, Task> existingRedirector) => + context => + { + if (context.Request.Path.StartsWithSegments("/api")) + { + context.Response.StatusCode = (int)statusCode; + return Task.CompletedTask; + } + + return existingRedirector(context); + }; diff --git a/NetEvent/Server/Resources/Localize.de.resx b/NetEvent/Server/Resources/Localize.de.resx new file mode 100644 index 00000000..1a72c1d9 --- /dev/null +++ b/NetEvent/Server/Resources/Localize.de.resx @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + testde + + \ No newline at end of file diff --git a/NetEvent/Server/Resources/Localize.fr.resx b/NetEvent/Server/Resources/Localize.fr.resx new file mode 100644 index 00000000..07ed03c2 --- /dev/null +++ b/NetEvent/Server/Resources/Localize.fr.resx @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + testfr + + \ No newline at end of file diff --git a/NetEvent/Server/Resources/Localize.resx b/NetEvent/Server/Resources/Localize.resx new file mode 100644 index 00000000..c84f86a5 --- /dev/null +++ b/NetEvent/Server/Resources/Localize.resx @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + test + + \ No newline at end of file