From cd29af7040e1eea19f10265ae84db3fd2a36093c Mon Sep 17 00:00:00 2001 From: Alexander Volz Date: Wed, 11 Jan 2023 19:05:51 +0100 Subject: [PATCH 1/6] add basic serverside localisation --- .../Extensions/DefaultCultureExtension.cs | 49 +++ NetEvent/Server/Localize.cs | 6 + .../Modules/System/Endpoints/GetSystemInfo.cs | 153 ++++---- .../System/Endpoints/PostSystemSetting.cs | 151 ++++---- NetEvent/Server/NetEvent.Server.csproj | 6 + NetEvent/Server/Program.cs | 363 +++++++++--------- NetEvent/Server/Resources/Localize.de.resx | 122 ++++++ NetEvent/Server/Resources/Localize.fr.resx | 122 ++++++ NetEvent/Server/Resources/Localize.resx | 122 ++++++ 9 files changed, 773 insertions(+), 321 deletions(-) create mode 100644 NetEvent/Server/Extensions/DefaultCultureExtension.cs create mode 100644 NetEvent/Server/Localize.cs create mode 100644 NetEvent/Server/Resources/Localize.de.resx create mode 100644 NetEvent/Server/Resources/Localize.fr.resx create mode 100644 NetEvent/Server/Resources/Localize.resx diff --git a/NetEvent/Server/Extensions/DefaultCultureExtension.cs b/NetEvent/Server/Extensions/DefaultCultureExtension.cs new file mode 100644 index 00000000..877274ee --- /dev/null +++ b/NetEvent/Server/Extensions/DefaultCultureExtension.cs @@ -0,0 +1,49 @@ +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 NetEvent.Server.Data; +using NetEvent.Server.Models; +using NetEvent.Shared; +using NetEvent.Shared.Config; + +namespace NetEvent.Server.Extensions; + +public static class DefaultCultureExtension +{ + public static 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 = context.Set().Select(x => DtoMapper.Mapper.SystemSettingValueToSystemSettingValueDto(x)).ToList().Find(x => x.Key.Equals(SystemSettings.DataCultureInfo)); + + if (organizationCulture == null) + { + return Task.CompletedTask; + } + + var culture = organizationCulture.Value; + + var cultureInfo = new CultureInfo(culture); + CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + } + } + } + catch (Exception ex) + { + logger.LogError(ex, "Unable to get Culture"); + } + + return Task.CompletedTask; + } +} 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..0ea7497e 100644 --- a/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs +++ b/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs @@ -1,71 +1,82 @@ -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 NetEvent.Shared.Dto; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using NetEvent.Server; + +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..8cb04f7b 100644 --- a/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs +++ b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs @@ -1,71 +1,80 @@ -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.Server.Data; +using NetEvent.Server.Models; +using NetEvent.Shared; +using NetEvent.Shared.Config; +using NetEvent.Shared.Dto; +using System.Globalization; + +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); + + // TODO: move special serverside handling to service + if (request.SystemSettingValue?.Key == SystemSettings.OrganizationData.DataCultureInfo) + { + var cultureInfo = new CultureInfo(request.SystemSettingValue.Value); + CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + } + + 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) + { + } + } + } +} 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..601628ea 100644 --- a/NetEvent/Server/Program.cs +++ b/NetEvent/Server/Program.cs @@ -1,179 +1,184 @@ -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.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.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 From 9fd4d90e16401c26d2793c31500b1dadad094069 Mon Sep 17 00:00:00 2001 From: Alexander Volz Date: Wed, 11 Jan 2023 19:17:26 +0100 Subject: [PATCH 2/6] fix language getting --- NetEvent/Server/Extensions/DefaultCultureExtension.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/NetEvent/Server/Extensions/DefaultCultureExtension.cs b/NetEvent/Server/Extensions/DefaultCultureExtension.cs index 877274ee..775aaf6f 100644 --- a/NetEvent/Server/Extensions/DefaultCultureExtension.cs +++ b/NetEvent/Server/Extensions/DefaultCultureExtension.cs @@ -24,16 +24,13 @@ public static Task SetDefaultCulture(this WebApplication app) { using (var context = scope.ServiceProvider.GetRequiredService()) { - var organizationCulture = context.Set().Select(x => DtoMapper.Mapper.SystemSettingValueToSystemSettingValueDto(x)).ToList().Find(x => x.Key.Equals(SystemSettings.DataCultureInfo)); - + var organizationCulture = new SystemSettings.OrganizationData().Settings.Select(x => x.Key.Equals(SystemSettings.OrganizationData.DataCultureInfo)).ToString();; if (organizationCulture == null) { return Task.CompletedTask; } - var culture = organizationCulture.Value; - - var cultureInfo = new CultureInfo(culture); + var cultureInfo = new CultureInfo(organizationCulture); CultureInfo.DefaultThreadCurrentCulture = cultureInfo; CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; } From a303e75f87a93ba0c9d097d8eb7571051391ce47 Mon Sep 17 00:00:00 2001 From: Alexander Volz Date: Wed, 11 Jan 2023 19:28:06 +0100 Subject: [PATCH 3/6] fix smells --- NetEvent/Server/Extensions/DefaultCultureExtension.cs | 4 +--- .../Server/Modules/System/Endpoints/GetSystemInfo.cs | 10 ++++------ .../Modules/System/Endpoints/PostSystemSetting.cs | 4 ++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/NetEvent/Server/Extensions/DefaultCultureExtension.cs b/NetEvent/Server/Extensions/DefaultCultureExtension.cs index 775aaf6f..617201e0 100644 --- a/NetEvent/Server/Extensions/DefaultCultureExtension.cs +++ b/NetEvent/Server/Extensions/DefaultCultureExtension.cs @@ -6,8 +6,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NetEvent.Server.Data; -using NetEvent.Server.Models; -using NetEvent.Shared; using NetEvent.Shared.Config; namespace NetEvent.Server.Extensions; @@ -24,7 +22,7 @@ public static Task SetDefaultCulture(this WebApplication app) { using (var context = scope.ServiceProvider.GetRequiredService()) { - var organizationCulture = new SystemSettings.OrganizationData().Settings.Select(x => x.Key.Equals(SystemSettings.OrganizationData.DataCultureInfo)).ToString();; + var organizationCulture = new SystemSettings.OrganizationData().Settings.Select(x => x.Key.Equals(SystemSettings.OrganizationData.DataCultureInfo, StringComparison.OrdinalIgnoreCase)).ToString(); if (organizationCulture == null) { return Task.CompletedTask; diff --git a/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs b/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs index 0ea7497e..901ffee1 100644 --- a/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs +++ b/NetEvent/Server/Modules/System/Endpoints/GetSystemInfo.cs @@ -4,10 +4,8 @@ using System.Threading; using System.Threading.Tasks; using MediatR; -using NetEvent.Shared.Dto; -using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; -using NetEvent.Server; +using NetEvent.Shared.Dto; namespace NetEvent.Server.Modules.System.Endpoints { @@ -16,12 +14,12 @@ 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; } + 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; + Localizer = localizer; } public Task Handle(Request request, CancellationToken cancellationToken) @@ -50,7 +48,7 @@ public Task Handle(Request request, CancellationToken cancellationToke 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"]); + Console.WriteLine(Localizer["test.test"]); return Task.FromResult(new Response(systeminfo)); } diff --git a/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs index 8cb04f7b..628f8d86 100644 --- a/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs +++ b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System.Globalization; +using System.Threading; using System.Threading.Tasks; using MediatR; using NetEvent.Server.Data; @@ -6,7 +7,6 @@ using NetEvent.Shared; using NetEvent.Shared.Config; using NetEvent.Shared.Dto; -using System.Globalization; namespace NetEvent.Server.Modules.System.Endpoints { From 2d265c6badac63b5f2169d66b9df4286bc5c2ec1 Mon Sep 17 00:00:00 2001 From: Alexander Volz Date: Wed, 11 Jan 2023 21:33:07 +0100 Subject: [PATCH 4/6] repair --- .../Server/Extensions/DefaultCultureExtension.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/NetEvent/Server/Extensions/DefaultCultureExtension.cs b/NetEvent/Server/Extensions/DefaultCultureExtension.cs index 617201e0..1a1bab24 100644 --- a/NetEvent/Server/Extensions/DefaultCultureExtension.cs +++ b/NetEvent/Server/Extensions/DefaultCultureExtension.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; using NetEvent.Server.Data; using NetEvent.Shared.Config; @@ -12,7 +13,7 @@ namespace NetEvent.Server.Extensions; public static class DefaultCultureExtension { - public static Task SetDefaultCulture(this WebApplication app) + public static async Task SetDefaultCulture(this WebApplication app) { var logger = app.Services.GetRequiredService>(); @@ -22,13 +23,17 @@ public static Task SetDefaultCulture(this WebApplication app) { using (var context = scope.ServiceProvider.GetRequiredService()) { - var organizationCulture = new SystemSettings.OrganizationData().Settings.Select(x => x.Key.Equals(SystemSettings.OrganizationData.DataCultureInfo, StringComparison.OrdinalIgnoreCase)).ToString(); - if (organizationCulture == null) + + var organizationCulture = await context.SystemSettingValues.Where(s => s.Key == SystemSettings.OrganizationData.DataCultureInfo).FirstAsync().ConfigureAwait(false); + + Console.WriteLine($"Culture: {organizationCulture.SerializedValue}"); + + if (organizationCulture?.SerializedValue == null) { - return Task.CompletedTask; + return; } - var cultureInfo = new CultureInfo(organizationCulture); + var cultureInfo = new CultureInfo(organizationCulture.SerializedValue); CultureInfo.DefaultThreadCurrentCulture = cultureInfo; CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; } @@ -39,6 +44,5 @@ public static Task SetDefaultCulture(this WebApplication app) logger.LogError(ex, "Unable to get Culture"); } - return Task.CompletedTask; } } From fec8464f6446e9d3ea9e33ec5ddd9ec83e7fa1cc Mon Sep 17 00:00:00 2001 From: Alexander Volz Date: Wed, 11 Jan 2023 21:37:30 +0100 Subject: [PATCH 5/6] fixup --- NetEvent/Server/Extensions/DefaultCultureExtension.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/NetEvent/Server/Extensions/DefaultCultureExtension.cs b/NetEvent/Server/Extensions/DefaultCultureExtension.cs index 1a1bab24..d02db782 100644 --- a/NetEvent/Server/Extensions/DefaultCultureExtension.cs +++ b/NetEvent/Server/Extensions/DefaultCultureExtension.cs @@ -26,8 +26,6 @@ public static async Task SetDefaultCulture(this WebApplication app) var organizationCulture = await context.SystemSettingValues.Where(s => s.Key == SystemSettings.OrganizationData.DataCultureInfo).FirstAsync().ConfigureAwait(false); - Console.WriteLine($"Culture: {organizationCulture.SerializedValue}"); - if (organizationCulture?.SerializedValue == null) { return; From 6606578e6f75a1192beacc98ddc72fc8ddc1306b Mon Sep 17 00:00:00 2001 From: Alexander Volz Date: Wed, 11 Jan 2023 22:27:53 +0100 Subject: [PATCH 6/6] created systemsettingsmanager and moved post --- .../SystemSettings/ISystemSetttingsManager.cs | 12 ++++ .../SystemSettings/SystemSettingsError.cs | 16 +++++ .../SystemSettings/SystemSettingsManager.cs | 65 +++++++++++++++++++ .../SystemSettings/SystemSettingsResult.cs | 65 +++++++++++++++++++ .../System/Endpoints/PostSystemSetting.cs | 46 +++++-------- NetEvent/Server/Program.cs | 2 + 6 files changed, 175 insertions(+), 31 deletions(-) create mode 100644 NetEvent/Server/Data/SystemSettings/ISystemSetttingsManager.cs create mode 100644 NetEvent/Server/Data/SystemSettings/SystemSettingsError.cs create mode 100644 NetEvent/Server/Data/SystemSettings/SystemSettingsManager.cs create mode 100644 NetEvent/Server/Data/SystemSettings/SystemSettingsResult.cs 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/Modules/System/Endpoints/PostSystemSetting.cs b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs index 628f8d86..5e707f48 100644 --- a/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs +++ b/NetEvent/Server/Modules/System/Endpoints/PostSystemSetting.cs @@ -1,12 +1,11 @@ -using System.Globalization; -using System.Threading; +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; +using NetEvent.Server.Data.SystemSettings; +using System; namespace NetEvent.Server.Modules.System.Endpoints { @@ -14,42 +13,25 @@ public static class PostSystemSetting { public sealed class Handler : IRequestHandler { - private readonly ApplicationDbContext _ApplicationDbContext; + private readonly ISystemSettingsManager _SystemSettingsManager; - public Handler(ApplicationDbContext applicationDbContext) + public Handler(ISystemSettingsManager systemSettingsManager) { - _ApplicationDbContext = applicationDbContext; + _SystemSettingsManager = systemSettingsManager; } 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) + var newSystemSettingValue = request.SystemSettingValue.ToSystemSettingValue(); + var result = await _SystemSettingsManager.UpdateAsync(newSystemSettingValue).ConfigureAwait(false); + if (!result.Succeeded) { - data.SerializedValue = request.SystemSettingValue.Value; - } - else - { - var serverData = request.SystemSettingValue.ToSystemSettingValue(); - await _ApplicationDbContext.AddAsync(serverData, cancellationToken); + return new Response(ReturnType.Error, string.Join(Environment.NewLine, result.Errors)); } - await _ApplicationDbContext.SaveChangesAsync(cancellationToken); + return new Response(newSystemSettingValue.ToSystemSettingValueDto()); - // TODO: move special serverside handling to service - if (request.SystemSettingValue?.Key == SystemSettings.OrganizationData.DataCultureInfo) - { - var cultureInfo = new CultureInfo(request.SystemSettingValue.Value); - CultureInfo.DefaultThreadCurrentCulture = cultureInfo; - CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; - } - - return new Response(); } } @@ -66,9 +48,10 @@ public Request(SystemSettingGroup systemSettingGroup, SystemSettingValueDto syst public SystemSettingValueDto SystemSettingValue { get; } } - public sealed class Response : ResponseBase + + public sealed class Response : ResponseBase { - public Response() + public Response(SystemSettingValueDto updatedSystemSetting) : base(updatedSystemSetting) { } @@ -76,5 +59,6 @@ public Response(ReturnType returnType, string error) : base(returnType, error) { } } + } } diff --git a/NetEvent/Server/Program.cs b/NetEvent/Server/Program.cs index 601628ea..360cec37 100644 --- a/NetEvent/Server/Program.cs +++ b/NetEvent/Server/Program.cs @@ -16,6 +16,7 @@ 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; @@ -105,6 +106,7 @@ builder.Services.AddSwaggerGen(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped();