From 2c3166e5a1e7d4824e059d26193351b2585b0ae5 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sat, 21 Jan 2023 23:34:03 +0100 Subject: [PATCH 001/185] Format amount decimal --- src/Web/Components/Pages/Reviews/MutateReview.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Components/Pages/Reviews/MutateReview.razor b/src/Web/Components/Pages/Reviews/MutateReview.razor index f3bc0f12..8a07e20e 100644 --- a/src/Web/Components/Pages/Reviews/MutateReview.razor +++ b/src/Web/Components/Pages/Reviews/MutateReview.razor @@ -50,7 +50,7 @@ Src="_content/XClaim.Web.Components/vectors/money_savings.svg" Alt="review_image" /> - N @(Item.Amount) + N @($"{Item.Amount:N0}") @(Item.Notes) From 24c82735b862e9360764202c7fb6052e8d7dfc3d Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 00:00:50 +0100 Subject: [PATCH 002/185] Use string interpolation for currency format on app --- src/Mobile/Views/Claim/ClaimDetailView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mobile/Views/Claim/ClaimDetailView.cs b/src/Mobile/Views/Claim/ClaimDetailView.cs index 7835e40b..cfd12715 100644 --- a/src/Mobile/Views/Claim/ClaimDetailView.cs +++ b/src/Mobile/Views/Claim/ClaimDetailView.cs @@ -63,7 +63,7 @@ protected override void Build() { .Text("."), new Label { Padding = 1, Margin = 2 } .Font(size: 12) - .Text("Catgory") + .Text("Category") //.Bind(Label.TextProperty, "Item.Category") }, new Label().Bind(Label.TextProperty, "Item.Notes") @@ -72,7 +72,7 @@ protected override void Build() { }.Margins(0, 0, 0, 24) .CenterHorizontal(), new Label().Bind(Label.TextProperty, "Item.Amount", - convert: (decimal value) => AppConst.Naira + string.Format("{0:N0}", value)) + convert: (decimal value) => $"{AppConst.Naira}{value:N0}") .Font(size: 32, family: "RobotoMedium") .CenterHorizontal() } From 4e237bee96849f19fda169186f1b8f4442a1db27 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 10:13:02 +0100 Subject: [PATCH 003/185] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 90700a8f..86179b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -476,7 +476,6 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk .idea -.config .fleet *.sqlite3* StaticFiles From 759df74b12f1a77797d231630d292deef787c525 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 10:13:31 +0100 Subject: [PATCH 004/185] Added run-script tool and commands --- .config/dotnet-tools.json | 18 ++++++++++++++++++ global.json | 13 +++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 .config/dotnet-tools.json create mode 100644 global.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 00000000..8edb95f6 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "7.0.2", + "commands": [ + "dotnet-ef" + ] + }, + "run-script": { + "version": "0.5.0", + "commands": [ + "r" + ] + } + } +} \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 00000000..bcb51093 --- /dev/null +++ b/global.json @@ -0,0 +1,13 @@ +{ + "sdk": { + "version": "7.0.102", + "rollForward": "latestPatch" + }, + "scripts": { + "build": "dotnet build --configuration Debug", + "format": "dotnet format ./XClaim.sln", + "web": "dotnet watch --project src/Web/Server/XClaim.Web.Server.csproj", + "dev:blazor": "DOTNET_USE_POLLING_FILE_WATCHER=true dotnet watch --project src/Web/Client/XClaim.Web.Client.csproj", + "dev:web": "DOTNET_USE_POLLING_FILE_WATCHER=true dotnet r web" + } +} \ No newline at end of file From 3b84119ee9c4d6676e3b7e47ffebab441ac9f577 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 10:13:53 +0100 Subject: [PATCH 005/185] Update auth API address --- src/Mobile/App.xaml.cs | 1 + src/Mobile/AppConst.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mobile/App.xaml.cs b/src/Mobile/App.xaml.cs index 73269efd..55b16687 100644 --- a/src/Mobile/App.xaml.cs +++ b/src/Mobile/App.xaml.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using Microsoft.Maui.Platform; using XClaim.Mobile.Services; namespace XClaim.Mobile; diff --git a/src/Mobile/AppConst.cs b/src/Mobile/AppConst.cs index f00584fc..0f510c79 100644 --- a/src/Mobile/AppConst.cs +++ b/src/Mobile/AppConst.cs @@ -6,7 +6,7 @@ public static class AppConst { public const string AppUId = "dev.gpproton.xclaim"; public static readonly string BaseAddress = DeviceInfo.Platform == DevicePlatform.Android ? "https://10.0.2.2:7001" : "https://localhost:7001"; - public static readonly string AuthUri = $"{BaseAddress}/api/v1/auth/sign-in/mobile"; + public static readonly string AuthUri = $"{BaseAddress}/auth/sign-in/mobile"; // Shared constants public const string Naira = "₦"; From 68619f6dbeccdb0a6c580e47cae05d4defbb2640 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 10:15:35 +0100 Subject: [PATCH 006/185] Update profile response init --- src/Mobile/Views/Home/HomeView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mobile/Views/Home/HomeView.cs b/src/Mobile/Views/Home/HomeView.cs index 22ab7644..f5630114 100644 --- a/src/Mobile/Views/Home/HomeView.cs +++ b/src/Mobile/Views/Home/HomeView.cs @@ -220,7 +220,7 @@ private async void HandleSelectionChanged(object? sender, SelectionChangedEventA var cx = (CollectionView)sender; cx.SelectedItem = null; if (e.CurrentSelection.FirstOrDefault() is EventResponse item) - if (item is not null) + if (item.Id != null) await MauiPopup.PopupAction.DisplayPopup(new HomeEventPop(item)); } } @@ -234,7 +234,7 @@ public partial class HomeViewModel : ListViewModel { private async Task LoadDefaults() { IsLoading = true; await Task.Delay(500); - Status = new ProfileResponse("saurav#email.me", "Saurav", "Argawal", "+234", UserPermission.Administrator); + Status = new ProfileResponse { FirstName = "Saurav", LastName = "Argawal", Balance = 2000, Permission = UserPermission.Administrator }; RecentItems = new ObservableCollection { }; IsLoading = false; } From 113e8f81c919c23e19f97adcdca42e395a4324ea Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 13:15:41 +0100 Subject: [PATCH 007/185] Added libman to project --- .config/dotnet-tools.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 8edb95f6..8d14b8a2 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -13,6 +13,12 @@ "commands": [ "r" ] + }, + "microsoft.web.librarymanager.cli": { + "version": "2.1.175", + "commands": [ + "libman" + ] } } } \ No newline at end of file From f6e7a011cfe9398475873bd9de7dbaba8b60119f Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 15:03:20 +0100 Subject: [PATCH 008/185] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 86179b2b..60125140 100644 --- a/.gitignore +++ b/.gitignore @@ -479,3 +479,4 @@ $RECYCLE.BIN/ .fleet *.sqlite3* StaticFiles +**/wwwroot/lib \ No newline at end of file From a2c21ca0cacdcff6ea8eeb17d98533be3423c790 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 18:33:14 +0100 Subject: [PATCH 009/185] Added build improvements to components class lib project --- .../Components/XClaim.Web.Components.csproj | 11 ++--- src/Web/Components/bundleconfig.json | 1 + src/Web/Components/libman.json | 8 ++- src/Web/Components/sasscompiler.json | 15 ++++++ src/Web/Server/Program.cs | 49 ++++++++++--------- 5 files changed, 55 insertions(+), 29 deletions(-) create mode 100644 src/Web/Components/bundleconfig.json create mode 100644 src/Web/Components/sasscompiler.json diff --git a/src/Web/Components/XClaim.Web.Components.csproj b/src/Web/Components/XClaim.Web.Components.csproj index e6804833..efa5b55e 100644 --- a/src/Web/Components/XClaim.Web.Components.csproj +++ b/src/Web/Components/XClaim.Web.Components.csproj @@ -5,13 +5,16 @@ enable enable - + + + + @@ -19,8 +22,4 @@ - - - - - + \ No newline at end of file diff --git a/src/Web/Components/bundleconfig.json b/src/Web/Components/bundleconfig.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/src/Web/Components/bundleconfig.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/Web/Components/libman.json b/src/Web/Components/libman.json index ceee2710..8981317a 100644 --- a/src/Web/Components/libman.json +++ b/src/Web/Components/libman.json @@ -1,5 +1,11 @@ { "version": "1.0", "defaultProvider": "cdnjs", - "libraries": [] + "libraries": [ + { + "provider": "unpkg", + "library": "@fontsource/roboto@4.5.8", + "destination": "wwwroot/lib/roboto" + } + ] } \ No newline at end of file diff --git a/src/Web/Components/sasscompiler.json b/src/Web/Components/sasscompiler.json new file mode 100644 index 00000000..26236f47 --- /dev/null +++ b/src/Web/Components/sasscompiler.json @@ -0,0 +1,15 @@ +{ + "ScopedCssFolders": [ + "Layouts", + "Pages", + "Controls", + "Shared" + ], + "GenerateScopedCss": true, + "Arguments": "--style=compressed", + "Configurations": { + "Debug": { + "Arguments": "--style=expanded" + } + } +} \ No newline at end of file diff --git a/src/Web/Server/Program.cs b/src/Web/Server/Program.cs index f858c75e..8bb15cc5 100644 --- a/src/Web/Server/Program.cs +++ b/src/Web/Server/Program.cs @@ -12,11 +12,11 @@ using XClaim.Web.Server.Data; using XClaim.Web.Server.Helpers; -var builder = WebApplication.CreateBuilder(args); +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); -var connectionString = builder.Configuration.GetConnectionString("Default"); +string? connectionString = builder.Configuration.GetConnectionString("Default"); builder.Services.AddDbContext(options => { - options.UseSqlite(connectionString).UseSnakeCaseNamingConvention(); + _ = options.UseSqlite(connectionString).UseSnakeCaseNamingConvention(); }); builder.Services.Configure(options => { @@ -38,8 +38,8 @@ opt.SlidingExpiration = true; }) .AddMicrosoftAccount(opt => { - var clientId = builder.Configuration.GetValue("Microsoft:ClientId") ?? ""; - var clientSecret = builder.Configuration.GetValue("Microsoft:ClientSecret") ?? ""; + string clientId = builder.Configuration.GetValue("Microsoft:ClientId") ?? ""; + string clientSecret = builder.Configuration.GetValue("Microsoft:ClientSecret") ?? ""; opt.SignInScheme = "Cookies"; opt.ClientId = clientId; @@ -52,7 +52,7 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(opt => { - opt.UseAutoFiltererParameters(); + _ = opt.UseAutoFiltererParameters(); opt.SwaggerDoc("v1", new OpenApiInfo { Title = $"X-Claim", Version = "v1" }); }); builder.Services.AddAutoMapper(typeof(Program).Assembly); @@ -60,20 +60,20 @@ builder.Services.AddRazorPages(); builder.Services.RegisterModules(); -var healthCheck = builder.Services.AddHealthChecks() +IHealthChecksBuilder healthCheck = builder.Services.AddHealthChecks() .AddApplicationStatus(); builder.Services.AddHealthChecksUI() .AddInMemoryStorage(); if (connectionString != null) { - healthCheck.AddSqlite(connectionString); + _ = healthCheck.AddSqlite(connectionString); } -var app = builder.Build(); +WebApplication app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseWebAssemblyDebugging(); - app.UseSwagger(); - app.UseSwaggerUI(opt => { + _ = app.UseSwagger(); + _ = app.UseSwaggerUI(opt => { const string path = "/swagger/v1/swagger.json"; opt.SwaggerEndpoint(path, "X-Claim V1 Docs"); opt.DefaultModelExpandDepth(3); @@ -82,9 +82,9 @@ opt.ShowExtensions(); }); } -else - app.UseExceptionHandler("/Error"); - +else { + _ = app.UseExceptionHandler("/Error"); +} app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax @@ -101,20 +101,25 @@ // INFO: Disabled due to mobile self signed certificate // app.UseHttpsRedirection(); -var uploadService = app.Services.GetService(); +FileUploadService? uploadService = app.Services.GetService(); if (uploadService != null) { - var fullUploadPath = uploadService.GetUploadRootPath(); + string fullUploadPath = uploadService.GetUploadRootPath(); if (!Directory.Exists(fullUploadPath)) { Console.WriteLine("Creating static files directory"); - Directory.CreateDirectory(fullUploadPath); + _ = Directory.CreateDirectory(fullUploadPath); } - app.UseStaticFiles(); + _ = app.UseStaticFiles(); - void OnPrepareResponse(StaticFileResponseContext ctx) { - if (!ctx.Context.Request.Path.StartsWithSegments("/static")) return; + static void OnPrepareResponse(StaticFileResponseContext ctx) { + if (!ctx.Context.Request.Path.StartsWithSegments("/static")) { + return; + } ctx.Context.Response.Headers.Add("Cache-Control", "no-store"); - if (ctx.Context.User.Identity == null || ctx.Context.User.Identity.IsAuthenticated) return; + if (ctx.Context.User.Identity == null || ctx.Context.User.Identity.IsAuthenticated) { + return; + } + ctx.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; ctx.Context.Response.ContentLength = 0; ctx.Context.Response.Body = Stream.Null; @@ -122,7 +127,7 @@ void OnPrepareResponse(StaticFileResponseContext ctx) { // JsonSerializer.Serialize(new { Status = 401, Message = "UnAuthorized file access" }); } - app.UseStaticFiles(new StaticFileOptions { + _ = app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(fullUploadPath), RequestPath = new PathString("/static"), OnPrepareResponse = OnPrepareResponse From fd80a9840c71f96e4e42557124120193717e6bdc Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 18:33:18 +0100 Subject: [PATCH 010/185] Create .hintrc --- .hintrc | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .hintrc diff --git a/.hintrc b/.hintrc new file mode 100644 index 00000000..5b18485f --- /dev/null +++ b/.hintrc @@ -0,0 +1,8 @@ +{ + "extends": [ + "development" + ], + "hints": { + "meta-viewport": "off" + } +} \ No newline at end of file From 92664bc1732f956137909f93145b909b658a7b09 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 18:33:26 +0100 Subject: [PATCH 011/185] Update AuthView.cs --- src/Mobile/Views/Startup/AuthView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mobile/Views/Startup/AuthView.cs b/src/Mobile/Views/Startup/AuthView.cs index 4ceeac39..3d6d44b7 100644 --- a/src/Mobile/Views/Startup/AuthView.cs +++ b/src/Mobile/Views/Startup/AuthView.cs @@ -48,7 +48,7 @@ protected override void OnAppearing() { public partial class AuthViewModel : BaseViewModel { [RelayCommand] private async void NavigateToHome() { - var redirect = $"{AppConst.AppId}://"; + const string redirect = $"{AppConst.AppId}://"; try { WebAuthenticatorResult result = await WebAuthenticator.Default.AuthenticateAsync( new Uri($"{AppConst.AuthUri}"), From 349ab345280fa86549c953d199507004ffb88b35 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 18:33:48 +0100 Subject: [PATCH 012/185] Use local google fonts --- src/Web/Server/appsettings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Web/Server/appsettings.json b/src/Web/Server/appsettings.json index d0310989..42f06016 100644 --- a/src/Web/Server/appsettings.json +++ b/src/Web/Server/appsettings.json @@ -1,8 +1,8 @@ { "Microsoft": { - "ClientId": "client-id", + "ClientId": "0b5d9d09-3e70-4f62-bbe8-4081c0cc1a5d", "CallbackPath": "/signin-microsoft", - "ClientSecret": "client-secret" + "ClientSecret": "d3m8Q~q5O5lW4LnX1ZCrg9qXiqg0PkOgAmjKPb4t" }, "Logging": { "LogLevel": { From 6f162124571f1868327ebb2cf3f8fac2cafe4744 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sun, 22 Jan 2023 18:53:11 +0100 Subject: [PATCH 013/185] Remove secrets from config --- global.json | 6 ++++-- src/Web/Server/appsettings.json | 7 +------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/global.json b/global.json index bcb51093..d936b9af 100644 --- a/global.json +++ b/global.json @@ -5,9 +5,11 @@ }, "scripts": { "build": "dotnet build --configuration Debug", + "build:web": "dotnet build src/Web/Server/", + "build:app": "dotnet build src/Mobile/XClaim.Mobile.csproj", "format": "dotnet format ./XClaim.sln", - "web": "dotnet watch --project src/Web/Server/XClaim.Web.Server.csproj", - "dev:blazor": "DOTNET_USE_POLLING_FILE_WATCHER=true dotnet watch --project src/Web/Client/XClaim.Web.Client.csproj", + "web": "dotnet watch --project src/Web/Server/", + "dev:blazor": "DOTNET_USE_POLLING_FILE_WATCHER=true dotnet watch --project src/Web/Client/", "dev:web": "DOTNET_USE_POLLING_FILE_WATCHER=true dotnet r web" } } \ No newline at end of file diff --git a/src/Web/Server/appsettings.json b/src/Web/Server/appsettings.json index 42f06016..a10ae235 100644 --- a/src/Web/Server/appsettings.json +++ b/src/Web/Server/appsettings.json @@ -1,9 +1,4 @@ { - "Microsoft": { - "ClientId": "0b5d9d09-3e70-4f62-bbe8-4081c0cc1a5d", - "CallbackPath": "/signin-microsoft", - "ClientSecret": "d3m8Q~q5O5lW4LnX1ZCrg9qXiqg0PkOgAmjKPb4t" - }, "Logging": { "LogLevel": { "Default": "Information", @@ -14,4 +9,4 @@ "ConnectionStrings": { "Default": "Data Source=app-data.sqlite3" } -} +} \ No newline at end of file From 9f6bc54b4c2c874cf84e4f17db0505b270fce8ea Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Mon, 23 Jan 2023 12:33:28 +0100 Subject: [PATCH 014/185] Added new secrects --- src/Web/Server/XClaim.Web.Server.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Web/Server/XClaim.Web.Server.csproj b/src/Web/Server/XClaim.Web.Server.csproj index 934a1d61..a50fe573 100644 --- a/src/Web/Server/XClaim.Web.Server.csproj +++ b/src/Web/Server/XClaim.Web.Server.csproj @@ -4,6 +4,7 @@ net7.0 enable enable + 4102fda6-15af-4599-9d0f-a2916d92f41a From be95932e7f8238c95f21a3cc33d5dc942d3e98e8 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Mon, 23 Jan 2023 12:34:04 +0100 Subject: [PATCH 015/185] Change config format to ini --- src/Web/Server/Constants.cs | 1 + src/Web/Server/Helpers/ConfigHelper.cs | 27 +++++++++++++++++++++ src/Web/Server/Program.cs | 15 ++++++------ src/Web/Server/appsettings.Development.json | 8 ------ src/Web/Server/appsettings.json | 12 --------- src/Web/Server/config.Development.ini | 9 +++++++ src/Web/Server/config.ini | 9 +++++++ 7 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 src/Web/Server/Helpers/ConfigHelper.cs delete mode 100644 src/Web/Server/appsettings.Development.json delete mode 100644 src/Web/Server/appsettings.json create mode 100644 src/Web/Server/config.Development.ini create mode 100644 src/Web/Server/config.ini diff --git a/src/Web/Server/Constants.cs b/src/Web/Server/Constants.cs index 30d42737..d9220b7d 100644 --- a/src/Web/Server/Constants.cs +++ b/src/Web/Server/Constants.cs @@ -3,4 +3,5 @@ namespace XClaim.Web.Server; public static class Constants { public const string RootApi = "/api/v1"; public const string AppUri = "xclaim"; + public const string AppSessionName = "AuthCookie"; } \ No newline at end of file diff --git a/src/Web/Server/Helpers/ConfigHelper.cs b/src/Web/Server/Helpers/ConfigHelper.cs new file mode 100644 index 00000000..aedd48f3 --- /dev/null +++ b/src/Web/Server/Helpers/ConfigHelper.cs @@ -0,0 +1,27 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace XClaim.Web.Server.Helpers; + +public static class ConfigHelper { + public static void ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args) { + IHostEnvironment env = hostingContext.HostingEnvironment; + bool reloadOnChange = GetReloadConfigOnChangeValue(hostingContext); + + appConfigBuilder.AddIniFile("config.ini", optional: true, reloadOnChange: reloadOnChange) + .AddIniFile($"config{env.EnvironmentName}.ini", optional: true, reloadOnChange: reloadOnChange); + + if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 }) { + var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); + if (appAssembly != null) + appConfigBuilder.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange); + } + + appConfigBuilder.AddEnvironmentVariables(); { + appConfigBuilder.AddCommandLine(args!); + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Calling IConfiguration.GetValue is safe when the T is bool.")] + static bool GetReloadConfigOnChangeValue(HostBuilderContext hostingContext) => hostingContext.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true); + } +} \ No newline at end of file diff --git a/src/Web/Server/Program.cs b/src/Web/Server/Program.cs index 8bb15cc5..59da39b0 100644 --- a/src/Web/Server/Program.cs +++ b/src/Web/Server/Program.cs @@ -14,9 +14,13 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args); +builder.Host.ConfigureServices((ctx, srv) => { + ConfigHelper.ApplyDefaultAppConfiguration(ctx, builder.Configuration, args); +}); + string? connectionString = builder.Configuration.GetConnectionString("Default"); builder.Services.AddDbContext(options => { - _ = options.UseSqlite(connectionString).UseSnakeCaseNamingConvention(); + options.UseSqlite(connectionString).UseSnakeCaseNamingConvention(); }); builder.Services.Configure(options => { @@ -32,18 +36,15 @@ builder.Services.AddAuthentication("Cookies") .AddCookie(opt => { - opt.Cookie.Name = "AuthCookie"; + opt.Cookie.Name = Constants.AppSessionName; opt.Cookie.IsEssential = true; opt.ExpireTimeSpan = TimeSpan.FromDays(7); opt.SlidingExpiration = true; }) .AddMicrosoftAccount(opt => { - string clientId = builder.Configuration.GetValue("Microsoft:ClientId") ?? ""; - string clientSecret = builder.Configuration.GetValue("Microsoft:ClientSecret") ?? ""; - opt.SignInScheme = "Cookies"; - opt.ClientId = clientId; - opt.ClientSecret = clientSecret; + opt.ClientId = builder.Configuration.GetValue("Microsoft:ClientId") ?? "client-id"; + opt.ClientSecret = builder.Configuration.GetValue("Microsoft:ClientSecret") ?? "client-secret"; opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; opt.SaveTokens = true; }); diff --git a/src/Web/Server/appsettings.Development.json b/src/Web/Server/appsettings.Development.json deleted file mode 100644 index 0c208ae9..00000000 --- a/src/Web/Server/appsettings.Development.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/src/Web/Server/appsettings.json b/src/Web/Server/appsettings.json deleted file mode 100644 index a10ae235..00000000 --- a/src/Web/Server/appsettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "Default": "Data Source=app-data.sqlite3" - } -} \ No newline at end of file diff --git a/src/Web/Server/config.Development.ini b/src/Web/Server/config.Development.ini new file mode 100644 index 00000000..7bff08da --- /dev/null +++ b/src/Web/Server/config.Development.ini @@ -0,0 +1,9 @@ +AllowedHosts=* +Database=sqlite + +[Logging.LogLevel] +Default=Information +Microsoft.AspNetCore=Warning + +[ConnectionStrings] +Default="Data Source=app-data.sqlite3" diff --git a/src/Web/Server/config.ini b/src/Web/Server/config.ini new file mode 100644 index 00000000..7bff08da --- /dev/null +++ b/src/Web/Server/config.ini @@ -0,0 +1,9 @@ +AllowedHosts=* +Database=sqlite + +[Logging.LogLevel] +Default=Information +Microsoft.AspNetCore=Warning + +[ConnectionStrings] +Default="Data Source=app-data.sqlite3" From 071519f6268fa4e3594f8638932477eb46cc021d Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Mon, 23 Jan 2023 12:34:14 +0100 Subject: [PATCH 016/185] Update XClaim.sln.DotSettings --- XClaim.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/XClaim.sln.DotSettings b/XClaim.sln.DotSettings index ce9cdb7b..205f2e8d 100644 --- a/XClaim.sln.DotSettings +++ b/XClaim.sln.DotSettings @@ -1,4 +1,5 @@  + True True True True From b7a27106105b8c14c9b4f9e8ba2b4e182f044c68 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Mon, 23 Jan 2023 12:34:49 +0100 Subject: [PATCH 017/185] Use local roboto font --- src/Web/Client/wwwroot/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Client/wwwroot/index.html b/src/Web/Client/wwwroot/index.html index 0ef52956..bb700d3c 100644 --- a/src/Web/Client/wwwroot/index.html +++ b/src/Web/Client/wwwroot/index.html @@ -6,7 +6,7 @@ X-Claim - + From 82d7e1f594cad1c07c7b0f5fb93be4351f5806fc Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Mon, 23 Jan 2023 12:44:31 +0100 Subject: [PATCH 018/185] Delete 20230115181843_Initial.cs --- .../Migrations/20230115181843_Initial.cs | 816 ------------------ 1 file changed, 816 deletions(-) delete mode 100644 src/Web/Server/Migrations/20230115181843_Initial.cs diff --git a/src/Web/Server/Migrations/20230115181843_Initial.cs b/src/Web/Server/Migrations/20230115181843_Initial.cs deleted file mode 100644 index ce259e01..00000000 --- a/src/Web/Server/Migrations/20230115181843_Initial.cs +++ /dev/null @@ -1,816 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace XClaim.Web.Server.Migrations -{ - /// - public partial class Initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "banks", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - name = table.Column(type: "TEXT", maxLength: 128, nullable: false), - description = table.Column(type: "TEXT", nullable: false), - active = table.Column(type: "INTEGER", nullable: false), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_banks", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "currency_entity", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - name = table.Column(type: "TEXT", nullable: false), - symbol = table.Column(type: "TEXT", nullable: false), - description = table.Column(type: "TEXT", nullable: false), - active = table.Column(type: "INTEGER", nullable: false), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_currency_entity", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "bank_accounts", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - fullname = table.Column(name: "full_name", type: "TEXT", nullable: false), - bankid = table.Column(name: "bank_id", type: "TEXT", nullable: false), - ownerid = table.Column(name: "owner_id", type: "TEXT", nullable: true), - number = table.Column(type: "TEXT", maxLength: 20, nullable: false), - description = table.Column(type: "TEXT", maxLength: 1024, nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_bank_accounts", x => x.id); - table.ForeignKey( - name: "fk_bank_accounts_banks_bank_id", - column: x => x.bankid, - principalTable: "banks", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "categories", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - name = table.Column(type: "TEXT", maxLength: 128, nullable: false), - companyid = table.Column(name: "company_id", type: "TEXT", nullable: true), - description = table.Column(type: "TEXT", maxLength: 1024, nullable: true), - active = table.Column(type: "INTEGER", nullable: false), - icon = table.Column(type: "TEXT", maxLength: 64, nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_categories", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "claims", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - description = table.Column(type: "TEXT", maxLength: 256, nullable: false), - notes = table.Column(type: "TEXT", maxLength: 1024, nullable: true), - amount = table.Column(type: "TEXT", nullable: false), - paymentid = table.Column(name: "payment_id", type: "TEXT", nullable: true), - categoryid = table.Column(name: "category_id", type: "TEXT", nullable: false), - companyid = table.Column(name: "company_id", type: "TEXT", nullable: true), - status = table.Column(type: "INTEGER", nullable: false), - ownerid = table.Column(name: "owner_id", type: "TEXT", nullable: false), - reviewedbyid = table.Column(name: "reviewed_by_id", type: "TEXT", nullable: true), - reviewedat = table.Column(name: "reviewed_at", type: "TEXT", nullable: true), - confirmedbyid = table.Column(name: "confirmed_by_id", type: "TEXT", nullable: true), - confirmedat = table.Column(name: "confirmed_at", type: "TEXT", nullable: true), - approvedbyid = table.Column(name: "approved_by_id", type: "TEXT", nullable: true), - approvedat = table.Column(name: "approved_at", type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_claims", x => x.id); - table.ForeignKey( - name: "fk_claims_categories_category_id", - column: x => x.categoryid, - principalTable: "categories", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "comments", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - claimid = table.Column(name: "claim_id", type: "TEXT", nullable: true), - paymentid = table.Column(name: "payment_id", type: "TEXT", nullable: true), - ownerid = table.Column(name: "owner_id", type: "TEXT", nullable: false), - content = table.Column(type: "TEXT", maxLength: 1024, nullable: false), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_comments", x => x.id); - table.ForeignKey( - name: "fk_comments_claims_claim_id", - column: x => x.claimid, - principalTable: "claims", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "companies", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - shortname = table.Column(name: "short_name", type: "TEXT", maxLength: 64, nullable: false), - fullname = table.Column(name: "full_name", type: "TEXT", maxLength: 128, nullable: false), - adminemail = table.Column(name: "admin_email", type: "TEXT", maxLength: 256, nullable: false), - managerid = table.Column(name: "manager_id", type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_companies", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "domain_entity", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - address = table.Column(type: "TEXT", nullable: false), - companyentityid = table.Column(name: "company_entity_id", type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_domain_entity", x => x.id); - table.ForeignKey( - name: "fk_domain_entity_companies_company_entity_id", - column: x => x.companyentityid, - principalTable: "companies", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "events", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - type = table.Column(type: "INTEGER", nullable: false), - claimid = table.Column(name: "claim_id", type: "TEXT", nullable: true), - paymentid = table.Column(name: "payment_id", type: "TEXT", nullable: true), - description = table.Column(type: "TEXT", maxLength: 512, nullable: false), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_events", x => x.id); - table.ForeignKey( - name: "fk_events_claims_claim_id", - column: x => x.claimid, - principalTable: "claims", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "files", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - name = table.Column(type: "TEXT", maxLength: 256, nullable: false), - path = table.Column(type: "TEXT", maxLength: 1024, nullable: false), - extension = table.Column(type: "TEXT", maxLength: 8, nullable: true), - ownerid = table.Column(name: "owner_id", type: "TEXT", nullable: true), - claimentityid = table.Column(name: "claim_entity_id", type: "TEXT", nullable: true), - paymententityid = table.Column(name: "payment_entity_id", type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_files", x => x.id); - table.ForeignKey( - name: "fk_files_claims_claim_entity_id", - column: x => x.claimentityid, - principalTable: "claims", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "payments", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - description = table.Column(type: "TEXT", maxLength: 256, nullable: true), - notes = table.Column(type: "TEXT", maxLength: 1024, nullable: true), - amount = table.Column(type: "TEXT", nullable: false), - ownerid = table.Column(name: "owner_id", type: "TEXT", nullable: false), - completedat = table.Column(name: "completed_at", type: "TEXT", nullable: true), - completedbyid = table.Column(name: "completed_by_id", type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_payments", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "teams", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - name = table.Column(type: "TEXT", maxLength: 128, nullable: false), - companyid = table.Column(name: "company_id", type: "TEXT", nullable: true), - managerid = table.Column(name: "manager_id", type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_teams", x => x.id); - table.ForeignKey( - name: "fk_teams_companies_company_id", - column: x => x.companyid, - principalTable: "companies", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "users", - columns: table => new - { - id = table.Column(type: "TEXT", nullable: false), - email = table.Column(type: "TEXT", maxLength: 256, nullable: false), - profileimage = table.Column(name: "profile_image", type: "TEXT", nullable: true), - phone = table.Column(type: "TEXT", maxLength: 64, nullable: false), - username = table.Column(name: "user_name", type: "TEXT", maxLength: 128, nullable: false), - firstname = table.Column(name: "first_name", type: "TEXT", maxLength: 128, nullable: false), - lastname = table.Column(name: "last_name", type: "TEXT", maxLength: 128, nullable: false), - balance = table.Column(type: "TEXT", nullable: false), - permission = table.Column(type: "INTEGER", nullable: false), - companyid = table.Column(name: "company_id", type: "TEXT", nullable: true), - companymanagedid = table.Column(name: "company_managed_id", type: "TEXT", nullable: true), - managerid = table.Column(name: "manager_id", type: "TEXT", nullable: true), - teamid = table.Column(name: "team_id", type: "TEXT", nullable: true), - teammanagedid = table.Column(name: "team_managed_id", type: "TEXT", nullable: true), - bankaccountid = table.Column(name: "bank_account_id", type: "TEXT", nullable: true), - active = table.Column(type: "INTEGER", nullable: false), - token = table.Column(type: "TEXT", maxLength: 128, nullable: true), - image = table.Column(type: "TEXT", nullable: true), - createdat = table.Column(name: "created_at", type: "TEXT", nullable: false), - modifiedat = table.Column(name: "modified_at", type: "TEXT", nullable: true), - deletedat = table.Column(name: "deleted_at", type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_users", x => x.id); - table.ForeignKey( - name: "fk_users_companies_company_id", - column: x => x.companyid, - principalTable: "companies", - principalColumn: "id"); - table.ForeignKey( - name: "fk_users_teams_team_id", - column: x => x.teamid, - principalTable: "teams", - principalColumn: "id"); - table.ForeignKey( - name: "fk_users_users_manager_id", - column: x => x.managerid, - principalTable: "users", - principalColumn: "id"); - }); - - migrationBuilder.InsertData( - table: "banks", - columns: new[] { "id", "active", "created_at", "deleted_at", "description", "modified_at", "name" }, - values: new object[,] - { - { new Guid("2416552e-495b-49de-8a2c-48aa7e55941a"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Zenith Bank" }, - { new Guid("2b90a7c1-b184-4a81-90d5-064ac5ce04c7"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "GT Bank" }, - { new Guid("3e54f0c5-70e2-4007-afad-2eece797bd1d"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "United Bank for Africa" }, - { new Guid("3eaaa9ee-9370-42db-80b5-8b9506f6eb1b"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Polaris Bank Limited" }, - { new Guid("60dc66e7-10ce-4313-993b-ea528ee3e6b7"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Access Bank" }, - { new Guid("7b19efc3-7772-4e4c-84c3-b62888b69b2b"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Keystone Bank Limited" }, - { new Guid("7bdace1e-f7e5-4c4f-b759-4a3dc02cb6c6"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Fidelity Bank" }, - { new Guid("9591ce72-fa44-4337-a477-dd68e90d86a1"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Wema Bank" }, - { new Guid("bc55b8e1-2c15-4844-aca8-198392129eea"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Sterling Bank" }, - { new Guid("beac0a9e-9724-49ff-a75f-411247bf613b"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "First Bank" }, - { new Guid("cb2af089-4476-4f99-b496-a9b5a09420f6"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "First City Monument Bank" }, - { new Guid("fb1b15ca-481d-4409-aad1-2638e9d830bc"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Stanbic IBTC Bank" }, - { new Guid("fd6dfacb-7c41-478f-a346-46142a5f1680"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Union Bank of Nigeria" } - }); - - migrationBuilder.InsertData( - table: "categories", - columns: new[] { "id", "active", "company_id", "created_at", "deleted_at", "description", "icon", "modified_at", "name" }, - values: new object[,] - { - { new Guid("186c18f4-e02c-48f8-b5c4-868fef9e0cf8"), false, null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", "", null, "General Fuelling" }, - { new Guid("83ab2715-50ce-47d2-90bc-18c0a5581115"), false, null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", "", null, "Internet Service" } - }); - - migrationBuilder.InsertData( - table: "companies", - columns: new[] { "id", "admin_email", "created_at", "deleted_at", "full_name", "manager_id", "modified_at", "short_name" }, - values: new object[,] - { - { new Guid("71927876-903a-4b7a-a5a6-a3bef7321ec3"), "", new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "Multi Consumer Product LTD", null, null, "MCPL LTD" }, - { new Guid("94d47c0b-fdba-4806-9357-4a2934b05fbd"), "", new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "Dufil Prima Foods Plc", null, null, "Dufil" }, - { new Guid("c42df454-1b41-470d-9ec8-11b9e4c9f5a4"), "", new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "MCPL LTD - BHN Division", null, null, "BHN LTD" } - }); - - migrationBuilder.InsertData( - table: "currency_entity", - columns: new[] { "id", "active", "created_at", "deleted_at", "description", "modified_at", "name", "symbol" }, - values: new object[,] - { - { new Guid("6f514f6d-de6b-46a7-aabe-448a1d1682cb"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Dollar", "$" }, - { new Guid("d7e33ed0-453d-45a8-aea0-fb989624869f"), false, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", null, "Naira", "₦" } - }); - - migrationBuilder.InsertData( - table: "domain_entity", - columns: new[] { "id", "address", "company_entity_id", "created_at", "deleted_at", "modified_at" }, - values: new object[,] - { - { new Guid("3906d110-193c-4029-b1c8-7db06100e7dd"), "dufil.com", null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, null }, - { new Guid("61f19266-2b6f-4ab0-a080-c69637169cde"), "agboolas@outlook.com", null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, null }, - { new Guid("a4c3605d-cc20-4da5-8f8d-32ee6cea14ca"), "tolaram.com", null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, null } - }); - - migrationBuilder.InsertData( - table: "categories", - columns: new[] { "id", "active", "company_id", "created_at", "deleted_at", "description", "icon", "modified_at", "name" }, - values: new object[,] - { - { new Guid("01069213-1141-4fdd-8618-4de210f95c80"), false, new Guid("71927876-903a-4b7a-a5a6-a3bef7321ec3"), new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", "", null, "MCPL - Monthly training expense" }, - { new Guid("4cad163d-ec4c-468b-bb9b-7c894b8485d2"), false, new Guid("c42df454-1b41-470d-9ec8-11b9e4c9f5a4"), new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "", "", null, "BHN - Weekly meeting expense" } - }); - - migrationBuilder.InsertData( - table: "teams", - columns: new[] { "id", "company_id", "created_at", "deleted_at", "manager_id", "modified_at", "name" }, - values: new object[,] - { - { new Guid("567851e6-955f-4f2a-928b-1db6d2b493ad"), new Guid("c42df454-1b41-470d-9ec8-11b9e4c9f5a4"), new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, null, null, "Account Dept" }, - { new Guid("acf60b30-6128-481c-a643-19bc2a2db6ad"), new Guid("94d47c0b-fdba-4806-9357-4a2934b05fbd"), new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, null, null, "QA Dept" }, - { new Guid("b13dd109-9d5a-416b-a3dc-ea7ce734969f"), new Guid("71927876-903a-4b7a-a5a6-a3bef7321ec3"), new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, null, null, "Logistics Dept" } - }); - - migrationBuilder.InsertData( - table: "users", - columns: new[] { "id", "active", "balance", "bank_account_id", "company_id", "company_managed_id", "created_at", "deleted_at", "email", "first_name", "image", "last_name", "manager_id", "modified_at", "permission", "phone", "profile_image", "team_id", "team_managed_id", "token", "user_name" }, - values: new object[,] - { - { new Guid("28bdb705-e568-49c7-8217-74d44b57461e"), false, 0m, null, new Guid("71927876-903a-4b7a-a5a6-a3bef7321ec3"), null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "jane.doe@test.com", "Jane", null, "Doe", null, null, 1, "+23402", null, new Guid("b13dd109-9d5a-416b-a3dc-ea7ce734969f"), null, null, "jane_doe" }, - { new Guid("557afd14-d7c3-4015-a0b6-0a745df7e9cd"), false, 0m, null, new Guid("94d47c0b-fdba-4806-9357-4a2934b05fbd"), null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "johnny.test@test.com", "Johnny ", null, "Test", null, null, 1, "+23403", null, new Guid("acf60b30-6128-481c-a643-19bc2a2db6ad"), null, null, "johnny_test" }, - { new Guid("64a4fd2d-f81a-4b91-ae8f-33e790d9f93a"), false, 0m, null, new Guid("c42df454-1b41-470d-9ec8-11b9e4c9f5a4"), null, new DateTime(2023, 1, 15, 19, 18, 43, 214, DateTimeKind.Local).AddTicks(7158), null, "john.doe@test.com", "John", null, "Doe", null, null, 4, "+23401", null, new Guid("567851e6-955f-4f2a-928b-1db6d2b493ad"), null, null, "john_doe" } - }); - - migrationBuilder.CreateIndex( - name: "ix_bank_accounts_bank_id", - table: "bank_accounts", - column: "bank_id"); - - migrationBuilder.CreateIndex( - name: "ix_bank_accounts_deleted_at", - table: "bank_accounts", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_bank_accounts_owner_id", - table: "bank_accounts", - column: "owner_id", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_banks_deleted_at", - table: "banks", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_banks_name", - table: "banks", - column: "name", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_categories_company_id", - table: "categories", - column: "company_id"); - - migrationBuilder.CreateIndex( - name: "ix_categories_deleted_at", - table: "categories", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_claims_approved_by_id", - table: "claims", - column: "approved_by_id"); - - migrationBuilder.CreateIndex( - name: "ix_claims_category_id", - table: "claims", - column: "category_id"); - - migrationBuilder.CreateIndex( - name: "ix_claims_company_id", - table: "claims", - column: "company_id"); - - migrationBuilder.CreateIndex( - name: "ix_claims_confirmed_by_id", - table: "claims", - column: "confirmed_by_id"); - - migrationBuilder.CreateIndex( - name: "ix_claims_deleted_at", - table: "claims", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_claims_owner_id", - table: "claims", - column: "owner_id"); - - migrationBuilder.CreateIndex( - name: "ix_claims_payment_id", - table: "claims", - column: "payment_id"); - - migrationBuilder.CreateIndex( - name: "ix_claims_reviewed_by_id", - table: "claims", - column: "reviewed_by_id"); - - migrationBuilder.CreateIndex( - name: "ix_comments_claim_id", - table: "comments", - column: "claim_id"); - - migrationBuilder.CreateIndex( - name: "ix_comments_deleted_at", - table: "comments", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_comments_owner_id", - table: "comments", - column: "owner_id"); - - migrationBuilder.CreateIndex( - name: "ix_comments_payment_id", - table: "comments", - column: "payment_id"); - - migrationBuilder.CreateIndex( - name: "ix_companies_deleted_at", - table: "companies", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_companies_manager_id", - table: "companies", - column: "manager_id", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_currency_entity_name", - table: "currency_entity", - column: "name", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_domain_entity_company_entity_id", - table: "domain_entity", - column: "company_entity_id"); - - migrationBuilder.CreateIndex( - name: "ix_domain_entity_deleted_at", - table: "domain_entity", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_events_claim_id", - table: "events", - column: "claim_id"); - - migrationBuilder.CreateIndex( - name: "ix_events_deleted_at", - table: "events", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_events_payment_id", - table: "events", - column: "payment_id"); - - migrationBuilder.CreateIndex( - name: "ix_files_claim_entity_id", - table: "files", - column: "claim_entity_id"); - - migrationBuilder.CreateIndex( - name: "ix_files_deleted_at", - table: "files", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_files_owner_id", - table: "files", - column: "owner_id"); - - migrationBuilder.CreateIndex( - name: "ix_files_payment_entity_id", - table: "files", - column: "payment_entity_id"); - - migrationBuilder.CreateIndex( - name: "ix_payments_completed_by_id", - table: "payments", - column: "completed_by_id"); - - migrationBuilder.CreateIndex( - name: "ix_payments_deleted_at", - table: "payments", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_payments_owner_id", - table: "payments", - column: "owner_id"); - - migrationBuilder.CreateIndex( - name: "ix_teams_company_id", - table: "teams", - column: "company_id"); - - migrationBuilder.CreateIndex( - name: "ix_teams_deleted_at", - table: "teams", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_teams_manager_id", - table: "teams", - column: "manager_id", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_users_company_id", - table: "users", - column: "company_id"); - - migrationBuilder.CreateIndex( - name: "ix_users_deleted_at", - table: "users", - column: "deleted_at"); - - migrationBuilder.CreateIndex( - name: "ix_users_email", - table: "users", - column: "email", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_users_manager_id", - table: "users", - column: "manager_id"); - - migrationBuilder.CreateIndex( - name: "ix_users_phone", - table: "users", - column: "phone", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_users_team_id", - table: "users", - column: "team_id"); - - migrationBuilder.CreateIndex( - name: "ix_users_user_name", - table: "users", - column: "user_name", - unique: true); - - migrationBuilder.AddForeignKey( - name: "fk_bank_accounts_users_owner_id1", - table: "bank_accounts", - column: "owner_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_categories_companies_company_id", - table: "categories", - column: "company_id", - principalTable: "companies", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_claims_companies_company_id", - table: "claims", - column: "company_id", - principalTable: "companies", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_claims_payments_payment_id", - table: "claims", - column: "payment_id", - principalTable: "payments", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_claims_users_approved_by_id", - table: "claims", - column: "approved_by_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_claims_users_confirmed_by_id", - table: "claims", - column: "confirmed_by_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_claims_users_owner_id", - table: "claims", - column: "owner_id", - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "fk_claims_users_reviewed_by_id", - table: "claims", - column: "reviewed_by_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_comments_payments_payment_id", - table: "comments", - column: "payment_id", - principalTable: "payments", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_comments_users_owner_id", - table: "comments", - column: "owner_id", - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "fk_companies_users_manager_id", - table: "companies", - column: "manager_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_events_payments_payment_id", - table: "events", - column: "payment_id", - principalTable: "payments", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_files_payments_payment_entity_id", - table: "files", - column: "payment_entity_id", - principalTable: "payments", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_files_users_owner_id", - table: "files", - column: "owner_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_payments_users_completed_by_id", - table: "payments", - column: "completed_by_id", - principalTable: "users", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "fk_payments_users_owner_id", - table: "payments", - column: "owner_id", - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "fk_teams_users_manager_id", - table: "teams", - column: "manager_id", - principalTable: "users", - principalColumn: "id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "fk_companies_users_manager_id", - table: "companies"); - - migrationBuilder.DropForeignKey( - name: "fk_teams_users_manager_id", - table: "teams"); - - migrationBuilder.DropTable( - name: "bank_accounts"); - - migrationBuilder.DropTable( - name: "comments"); - - migrationBuilder.DropTable( - name: "currency_entity"); - - migrationBuilder.DropTable( - name: "domain_entity"); - - migrationBuilder.DropTable( - name: "events"); - - migrationBuilder.DropTable( - name: "files"); - - migrationBuilder.DropTable( - name: "banks"); - - migrationBuilder.DropTable( - name: "claims"); - - migrationBuilder.DropTable( - name: "categories"); - - migrationBuilder.DropTable( - name: "payments"); - - migrationBuilder.DropTable( - name: "users"); - - migrationBuilder.DropTable( - name: "teams"); - - migrationBuilder.DropTable( - name: "companies"); - } - } -} From 96bbb288b3db885ec9fbc20544d2d3189b49d6e2 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Mon, 23 Jan 2023 13:06:14 +0100 Subject: [PATCH 019/185] Update auth view --- src/Web/Components/Pages/Startup/Auth.razor | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Web/Components/Pages/Startup/Auth.razor b/src/Web/Components/Pages/Startup/Auth.razor index 34dd960f..6a7736d1 100644 --- a/src/Web/Components/Pages/Startup/Auth.razor +++ b/src/Web/Components/Pages/Startup/Auth.razor @@ -1,11 +1,15 @@ +@inject NavigationManager Nav @page "/app/auth" @code { - + private void BackHome() => Nav.NavigateTo(WebConst.AppHome); } Sign In - - - \ No newline at end of file + + + + Home + + \ No newline at end of file From 4a4193a058d643a7d9af456bdec1864477650166 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Tue, 24 Jan 2023 16:18:22 +0100 Subject: [PATCH 020/185] Create CookieHandler.cs --- src/Web/Client/Handler/CookieHandler.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/Web/Client/Handler/CookieHandler.cs diff --git a/src/Web/Client/Handler/CookieHandler.cs b/src/Web/Client/Handler/CookieHandler.cs new file mode 100644 index 00000000..8bde2bfd --- /dev/null +++ b/src/Web/Client/Handler/CookieHandler.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Http; + +namespace XClaim.Web.Client.Handler; + +public class CookieHandler : DelegatingHandler { + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { + request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); + + return await base.SendAsync(request, cancellationToken); + } +} \ No newline at end of file From 886629dc87f064a02d646be049a170b5b4bc08c1 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 11:10:30 +0100 Subject: [PATCH 021/185] Update AuthProvider.cs --- src/Web/Shared/AuthProvider.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Web/Shared/AuthProvider.cs b/src/Web/Shared/AuthProvider.cs index 4d5e179d..5ea512a6 100644 --- a/src/Web/Shared/AuthProvider.cs +++ b/src/Web/Shared/AuthProvider.cs @@ -6,6 +6,7 @@ namespace XClaim.Web.Shared; public class AuthProvider : AuthenticationStateProvider { + private const string SessionKey = "UserSession"; private readonly ISessionStorageService _sessionStorage; private readonly ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity()); @@ -15,12 +16,12 @@ public AuthProvider(ISessionStorageService sessionStorage) { public override async Task GetAuthenticationStateAsync() { try { - var userSession = await _sessionStorage.GetAsync("UserSession"); + var userSession = await _sessionStorage.GetAsync(SessionKey); if (userSession == null) return await Task.FromResult(new AuthenticationState(_anonymous)); var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List { - new(ClaimTypes.Name, userSession.UserName), - new(ClaimTypes.Role, userSession.Role) + new Claim(ClaimTypes.Name, userSession.UserName), + new Claim(ClaimTypes.Role, userSession.Role) }, "SessionAuth")); return await Task.FromResult(new AuthenticationState(claimsPrincipal)); @@ -40,27 +41,27 @@ public async Task UpdateAuthenticationState(AuthResponse? userSession) { new Claim(ClaimTypes.Role, userSession.Role) })); userSession.ExpiryTimeStamp = DateTime.Now.AddSeconds(userSession.ExpiresIn); - await _sessionStorage.SaveAsync("UserSession", userSession); + await _sessionStorage.SaveAsync(SessionKey, userSession); } else { claimsPrincipal = _anonymous; - await _sessionStorage.RemoveItemAsync("UserSession"); + await _sessionStorage.RemoveItemAsync(SessionKey); } NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal))); } + public async Task ClearAuthInfo() => await this.UpdateAuthenticationState(null); + public async Task GetToken() { var result = string.Empty; try { - var userSession = await _sessionStorage.GetAsync("UserSession"); + var userSession = await _sessionStorage.GetAsync(SessionKey); if (userSession != null && DateTime.Now < userSession.ExpiryTimeStamp) result = userSession.Token; - } - catch { + } catch { // ignored } - return result; } } \ No newline at end of file From 7374fe58575b9e33cebb52c388844933c1d39d6f Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:35:09 +0100 Subject: [PATCH 022/185] Minor improvement to auth endpoint --- src/Common/Dtos/UserResponse.cs | 2 +- src/Common/HTTP/IProfileService.cs | 3 ++- src/Common/HTTP/ProfileService.cs | 5 +++-- .../Server/Modules/ProfileModule/ProfileModule.cs | 15 ++++++++------- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Common/Dtos/UserResponse.cs b/src/Common/Dtos/UserResponse.cs index 8f21d498..bd9157fc 100644 --- a/src/Common/Dtos/UserResponse.cs +++ b/src/Common/Dtos/UserResponse.cs @@ -12,7 +12,7 @@ public string FullName { get { return $"{FirstName} {LastName}"; } } public decimal Balance { get; set; } - public UserPermission Permission { get; set; } + public UserPermission Permission { get; set; } = UserPermission.Standard; public CompanyResponse? Company { get; set; } public Guid? CompanyId { get; set; } public CompanyResponse? CompanyManaged { get; set; } diff --git a/src/Common/HTTP/IProfileService.cs b/src/Common/HTTP/IProfileService.cs index 9b49320f..c02668bb 100644 --- a/src/Common/HTTP/IProfileService.cs +++ b/src/Common/HTTP/IProfileService.cs @@ -1,8 +1,9 @@ using XClaim.Common.Dtos; +using XClaim.Common.Wrappers; namespace XClaim.Common.HTTP; public interface IProfileService { - Task GetAsync(); + Task> GetAsync(); Task SignOutAsync(); } \ No newline at end of file diff --git a/src/Common/HTTP/ProfileService.cs b/src/Common/HTTP/ProfileService.cs index fa07ffd1..2c396da8 100644 --- a/src/Common/HTTP/ProfileService.cs +++ b/src/Common/HTTP/ProfileService.cs @@ -1,5 +1,6 @@ using XClaim.Common.Dtos; using XClaim.Common.Service; +using XClaim.Common.Wrappers; namespace XClaim.Common.HTTP; @@ -11,8 +12,8 @@ public ProfileService(IHttpService http) { _http = http; } - public async Task GetAsync() { - return await _http.Get($"{RootApi}/account"); + public async Task> GetAsync() { + return await _http.Get>($"{RootApi}/account"); } public async Task SignOutAsync() { diff --git a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs index 4250dd6e..10367f75 100644 --- a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs +++ b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs @@ -2,6 +2,7 @@ using IdentityModel; using Microsoft.AspNetCore.Authentication; using XClaim.Common.Dtos; +using XClaim.Common.Wrappers; using XClaim.Web.Server.Modules.UserModule; namespace XClaim.Web.Server.Modules.ProfileModule; @@ -19,8 +20,9 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { group.MapGet("/account", async (HttpRequest request, UserService user) => { bool isAuth = request.HttpContext.User.Identity?.IsAuthenticated ?? false; - - if (!isAuth) return Results.Unauthorized(); + + if (!isAuth) return TypedResults.Unauthorized(); + var auth = await request.HttpContext.AuthenticateAsync("Microsoft"); var email = request.HttpContext.User.FindFirst(ClaimTypes.Email)?.Value ?? ""; var role = request.HttpContext.User.FindFirst(ClaimTypes.Role)?.Value ?? ""; @@ -41,8 +43,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { LastName = names[^1], Phone = phone }; - } - else { + } else { profile = new ProfileResponse { Email = account.Email, FirstName = account.FirstName, @@ -54,8 +55,8 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { }; } - var response = new AuthResponse { - Confirmed = false, + var result = new AuthResponse { + Confirmed = account != null, ExpiryTimeStamp = expiry, ExpiresIn = expireIn, Token = token, @@ -65,7 +66,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { UserName = fullName }; - return Results.Ok(response); + return Results.Ok(new Response(result) { Succeeded = expireIn > 0 }); }).WithName("AccountProfile").WithOpenApi(); return group; From 31abcd36804acf460c86856b9fac0036abc3600a Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:36:01 +0100 Subject: [PATCH 023/185] Move all auth action to AuthState --- src/Web/Shared/AuthProvider.cs | 9 ++-- src/Web/Shared/SharedServiceExtensions.cs | 6 ++- src/Web/Shared/States/AuthState.cs | 56 ++++++++++++++--------- src/Web/Shared/WebConst.cs | 1 + 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/Web/Shared/AuthProvider.cs b/src/Web/Shared/AuthProvider.cs index 5ea512a6..cf2bc9bb 100644 --- a/src/Web/Shared/AuthProvider.cs +++ b/src/Web/Shared/AuthProvider.cs @@ -6,7 +6,6 @@ namespace XClaim.Web.Shared; public class AuthProvider : AuthenticationStateProvider { - private const string SessionKey = "UserSession"; private readonly ISessionStorageService _sessionStorage; private readonly ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity()); @@ -16,7 +15,7 @@ public AuthProvider(ISessionStorageService sessionStorage) { public override async Task GetAuthenticationStateAsync() { try { - var userSession = await _sessionStorage.GetAsync(SessionKey); + var userSession = await _sessionStorage.GetAsync(WebConst.SessionKey); if (userSession == null) return await Task.FromResult(new AuthenticationState(_anonymous)); var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List { @@ -41,11 +40,11 @@ public async Task UpdateAuthenticationState(AuthResponse? userSession) { new Claim(ClaimTypes.Role, userSession.Role) })); userSession.ExpiryTimeStamp = DateTime.Now.AddSeconds(userSession.ExpiresIn); - await _sessionStorage.SaveAsync(SessionKey, userSession); + await _sessionStorage.SaveAsync(WebConst.SessionKey, userSession); } else { claimsPrincipal = _anonymous; - await _sessionStorage.RemoveItemAsync(SessionKey); + await _sessionStorage.RemoveItemAsync(WebConst.SessionKey); } NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal))); @@ -56,7 +55,7 @@ public async Task UpdateAuthenticationState(AuthResponse? userSession) { public async Task GetToken() { var result = string.Empty; try { - var userSession = await _sessionStorage.GetAsync(SessionKey); + var userSession = await _sessionStorage.GetAsync(WebConst.SessionKey); if (userSession != null && DateTime.Now < userSession.ExpiryTimeStamp) result = userSession.Token; } catch { diff --git a/src/Web/Shared/SharedServiceExtensions.cs b/src/Web/Shared/SharedServiceExtensions.cs index a03811b7..8a7ee0b0 100644 --- a/src/Web/Shared/SharedServiceExtensions.cs +++ b/src/Web/Shared/SharedServiceExtensions.cs @@ -12,11 +12,13 @@ public static IServiceCollection UseSharedExtensions(this IServiceCollection ser services.AddMudServices(); services.AddBlazoredSessionStorage(); services.AddScoped(); + services.AddScoped(); + services.AddAuthorizationCore(); + + // App States services.AddSingleton(); services.AddSingleton(); services.AddScoped(); - services.AddScoped(); - services.AddAuthorizationCore(); return services; } diff --git a/src/Web/Shared/States/AuthState.cs b/src/Web/Shared/States/AuthState.cs index 73f84db6..fa5761a6 100644 --- a/src/Web/Shared/States/AuthState.cs +++ b/src/Web/Shared/States/AuthState.cs @@ -1,39 +1,51 @@ +using System.Security.Claims; +using Blazored.SessionStorage; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; +using XClaim.Common.Dtos; using XClaim.Common.HTTP; -using XClaim.Common.Service; namespace XClaim.Web.Shared.States; public class AuthState : RootState { - public AuthState(AuthenticationStateProvider authProvider, NavigationManager nav, IProfileService userService) { + private readonly NavigationManager _nav; + private readonly IProfileService _profileService; + private readonly AuthenticationStateProvider _authProvider; + private readonly ISessionStorageService _sessionStorage; + + public AuthState(AuthenticationStateProvider authProvider, NavigationManager nav, IProfileService profileService, ISessionStorageService sessionStorage) { _authProvider = authProvider; - Nav = nav; - UserService = userService; + _nav = nav; + _profileService = profileService; + _sessionStorage = sessionStorage; } - private NavigationManager Nav { get; set; } - - private IProfileService UserService { get; set; } + public async Task GetSession() => await _sessionStorage.GetAsync(WebConst.SessionKey); - private readonly AuthenticationStateProvider _authProvider; + private AuthProvider Profile { get { + return (AuthProvider)_authProvider; + } + } - public bool Register { get; set; } + private async Task GetState() => await Profile.GetAuthenticationStateAsync(); - public async Task BootstrapAuth() { - var auth = (AuthProvider)_authProvider; - var authState = await auth.GetAuthenticationStateAsync(); - var user = authState.User; - var isAuth = user.Identity?.IsAuthenticated ?? false; + private async Task GetUser() => (await GetState()).User; - if (!isAuth) { - var profile = await UserService.GetAsync()!; - if (profile is not null) { - await auth.UpdateAuthenticationState(profile); - if (!profile.Confirmed) Register = true; - } - } + public async Task IsAuth() => (await GetUser()).Identity!.IsAuthenticated; + + public async Task TriggerAuthentication() { + var response = await _profileService.GetAsync(); + if (response is { Data: { }, Succeeded: true }) + await Profile.UpdateAuthenticationState(response.Data); + else + await Profile.UpdateAuthenticationState(null); + } + + public void TriggerApiAuth() => _nav.NavigateTo($"{_nav.BaseUri}{WebConst.ApiAuth}", true); - Nav.NavigateTo(Register ? $"/{WebConst.AppHome}" : $"/{WebConst.AppRegister}"); + public async Task TriggerSignOut() { + await _profileService.SignOutAsync(); + await Profile.UpdateAuthenticationState(null); + _nav.NavigateTo(WebConst.AppAuth, true); } } \ No newline at end of file diff --git a/src/Web/Shared/WebConst.cs b/src/Web/Shared/WebConst.cs index 30890050..a1e54b93 100644 --- a/src/Web/Shared/WebConst.cs +++ b/src/Web/Shared/WebConst.cs @@ -9,6 +9,7 @@ public static class WebConst { public const string AppHome = "app/overview"; public const string AppAuth = "app/auth"; public const string AppRegister = "app/registration"; + public const string SessionKey = "UserSession"; public static readonly DateRange AppDateRange = new DateRange(DateTime.Now.AddDays(-7), DateTime.Now); public static readonly int[] AppPaged = new[] { 25, 100, 250, 2000 }; public const string TableHeight = "calc(100vh - 256px)"; From 17d1ca4384e2b9d659b9fe39edbaa7e0fdd1e0ea Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:36:18 +0100 Subject: [PATCH 024/185] Fix empty layout --- src/Web/Components/Layouts/EmptyLayout.razor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Web/Components/Layouts/EmptyLayout.razor b/src/Web/Components/Layouts/EmptyLayout.razor index d099c374..5721c77a 100644 --- a/src/Web/Components/Layouts/EmptyLayout.razor +++ b/src/Web/Components/Layouts/EmptyLayout.razor @@ -1 +1,3 @@ -@inherits LayoutComponentBase \ No newline at end of file +@inherits LayoutComponentBase + +
@Body
\ No newline at end of file From 610bd4b78318a6b18cea1a9d9583d817e16ad81f Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:36:33 +0100 Subject: [PATCH 025/185] Remove index redirect --- src/Web/Components/Pages/Index.razor | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/Web/Components/Pages/Index.razor b/src/Web/Components/Pages/Index.razor index 3d1cc1ff..a04ae91d 100644 --- a/src/Web/Components/Pages/Index.razor +++ b/src/Web/Components/Pages/Index.razor @@ -1,14 +1,8 @@ @page "/" -@inject AuthState Auth +@layout EmptyLayout -@code { +Bootstrapping - protected override async Task OnInitializedAsync() { - await base.OnInitializedAsync(); - await Auth.BootstrapAuth(); - } -} - -Bootstrapping... - - \ No newline at end of file + + + \ No newline at end of file From c1388a728d0e4b934742dee6301f732e50f05ade Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:37:14 +0100 Subject: [PATCH 026/185] Use authState triggers in layout UI --- src/Web/Components/Layouts/AuthLayout.razor | 6 +++--- src/Web/Components/Shared/AppBar.razor | 15 ++------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/Web/Components/Layouts/AuthLayout.razor b/src/Web/Components/Layouts/AuthLayout.razor index 5eebb8d4..a025356b 100644 --- a/src/Web/Components/Layouts/AuthLayout.razor +++ b/src/Web/Components/Layouts/AuthLayout.razor @@ -1,9 +1,9 @@ @inherits LayoutComponentBase -@inject NavigationManager Nav +@inject AuthState AuthState @code { - void SignIn() => Nav.NavigateTo($"{Nav.BaseUri}{WebConst.ApiAuth}", true); - void SignOut() => Console.WriteLine("Trigger SignOut"); + void SignIn() => AuthState.TriggerApiAuth(); + async Task SignOut() => await AuthState.TriggerSignOut(); } diff --git a/src/Web/Components/Shared/AppBar.razor b/src/Web/Components/Shared/AppBar.razor index 002d98b0..131158c4 100644 --- a/src/Web/Components/Shared/AppBar.razor +++ b/src/Web/Components/Shared/AppBar.razor @@ -1,13 +1,7 @@ -@using Blazored.SessionStorage -@using XClaim.Common.Dtos -@using XClaim.Common.HTTP @implements IDisposable @inject AppState AppState @inject ThemeState ThemeState -@inject NavigationManager Nav -@inject IProfileService UserService -@inject ISessionStorageService SessionStorage -@inject AuthenticationStateProvider AuthProvider +@inject AuthState AuthState @code { protected override void OnInitialized() { @@ -21,12 +15,7 @@ ThemeState.OnChange -= StateHasChanged; } - async Task SignOut() { - var auth = (AuthProvider)AuthProvider; - await UserService.SignOutAsync(); - await auth.UpdateAuthenticationState(null); - Nav.NavigateTo(WebConst.AppAuth, true); - } + async Task SignOut() => await AuthState.TriggerSignOut(); } From 34ce024b5cc4daefdec5aa4610935181a0e34051 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:37:53 +0100 Subject: [PATCH 027/185] Handle authentication in root component OnNavigateAsync --- src/Web/Client/App.razor | 51 +++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/Web/Client/App.razor b/src/Web/Client/App.razor index 0c73aa2c..fe243099 100644 --- a/src/Web/Client/App.razor +++ b/src/Web/Client/App.razor @@ -1,26 +1,55 @@ -@code { } +@inject NavigationManager Nav +@inject AuthState AuthState + +@code { + private async Task OnNavigateAsync(NavigationContext args) { + var isRootPath = args.Path.Equals(string.Empty); + var isAuthPath = args.Path.Equals(WebConst.AppAuth); + var session = await AuthState.GetSession(); + var isAuth = await AuthState.IsAuth(); + switch (isAuth) { + case true when !session!.Confirmed && !args.Path.Equals(WebConst.AppRegister): + Nav.NavigateTo(WebConst.AppRegister, true); + break; + case false when isAuthPath: + break; + case true when isAuthPath || isRootPath: + Nav.NavigateTo(WebConst.AppHome, true); + break; + case false when isRootPath: + await AuthState.TriggerAuthentication(); + if (isAuth) Nav.NavigateTo(!session!.Confirmed ? WebConst.AppRegister : WebConst.AppHome, true); + else { + await Task.Delay(50); + Nav.NavigateTo(WebConst.AppAuth, true); + } + break; + case false: { + break; + } + } + } +} - + - @if (context.User.Identity?.IsAuthenticated != true) { - - } else { -

You are not authorized to access this resource.

- } + @if (context.User.Identity?.IsAuthenticated != true) { + + } else { +

You are not authorized to access this resource.

+ }
- @* @if (Register) { *@ - @* *@ - @* } *@ + ...
- Not found + Not Found

Sorry, there's nothing at this address.

From 32625e52f5cc8131ef6b9d62dd8528cec497f58f Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 18:38:29 +0100 Subject: [PATCH 028/185] Added initial registration binding --- .../Pages/Startup/Registration.razor | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Web/Components/Pages/Startup/Registration.razor b/src/Web/Components/Pages/Startup/Registration.razor index c8860fb0..bfbb7064 100644 --- a/src/Web/Components/Pages/Startup/Registration.razor +++ b/src/Web/Components/Pages/Startup/Registration.razor @@ -1,11 +1,13 @@ @page "/app/registration" @using XClaim.Common.Dtos @using XClaim.Common.Helpers +@using Nextended.Core.Extensions @inject IUserService Http @inject ICompanyService CompanyService @inject ICurrencyService CurrencyService @inject NavigationManager Nav @inject ISnackbar Snackbar +@inject AuthState AuthState @attribute [Authorize] @code { @@ -27,6 +29,19 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); + var session = await AuthState.GetSession(); + + if (session?.Data != null) { + ProfileResponse data = session.Data; + + // Check domain validation + if (data.Email.IsNullOrEmpty()) await AuthState.TriggerSignOut(); + + Item.FirstName = data.FirstName; + Item.LastName = data.LastName; + Item.Email = data.Email; + Item.Phone = data.Phone; + } } async Task Verify() { @@ -34,9 +49,10 @@ Item.CurrencyId = Currency?.Id; var result = await Http.RegistrationAsync(Item); if (result.Succeeded) { + await AuthState.TriggerAuthentication(); Snackbar.Add("Verification successful..", Severity.Success); - await Task.Delay(1500); - Nav.NavigateTo(WebConst.AppHome); + await Task.Delay(500); + Nav.NavigateTo(WebConst.AppHome, true); } else { Snackbar.Add("Verification failed..", Severity.Error); } From c87e16097f8d9a7e9e8918c1c0d83d38b328728b Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 22:49:30 +0100 Subject: [PATCH 029/185] Re-arrange user permission enum --- src/Common/Enums/UserPermission.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Common/Enums/UserPermission.cs b/src/Common/Enums/UserPermission.cs index b33a0554..7d7314fa 100644 --- a/src/Common/Enums/UserPermission.cs +++ b/src/Common/Enums/UserPermission.cs @@ -1,10 +1,10 @@ namespace XClaim.Common.Enums; public enum UserPermission { + System, + Administrator, + Finance, Cashier, - Standard, Lead, - Finance, - Administrator, - System + Standard } \ No newline at end of file From 7143fc9c24c34945245f0e832cebf0e18c264317 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 22:50:05 +0100 Subject: [PATCH 030/185] Added extension for lazy DI resolution --- .../Extensions/LazyResolutionExtension.cs | 19 +++++++++++++++++++ src/Common/HTTP/HttpServiceExtensions.cs | 2 ++ 2 files changed, 21 insertions(+) create mode 100644 src/Common/Extensions/LazyResolutionExtension.cs diff --git a/src/Common/Extensions/LazyResolutionExtension.cs b/src/Common/Extensions/LazyResolutionExtension.cs new file mode 100644 index 00000000..8d894d7d --- /dev/null +++ b/src/Common/Extensions/LazyResolutionExtension.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace XClaim.Common.Extensions; + +public static class LazyResolutionExtension { + public static IServiceCollection AddLazyResolution(this IServiceCollection services) + { + return services.AddTransient( + typeof(Lazy<>), + typeof(LazilyResolved<>)); + } + + private class LazilyResolved : Lazy where T : notnull { + public LazilyResolved(IServiceProvider serviceProvider) + : base(serviceProvider.GetRequiredService) + { + } + } +} \ No newline at end of file diff --git a/src/Common/HTTP/HttpServiceExtensions.cs b/src/Common/HTTP/HttpServiceExtensions.cs index 68cdde4b..a1d79d69 100644 --- a/src/Common/HTTP/HttpServiceExtensions.cs +++ b/src/Common/HTTP/HttpServiceExtensions.cs @@ -1,9 +1,11 @@ using Microsoft.Extensions.DependencyInjection; +using XClaim.Common.Extensions; namespace XClaim.Common.HTTP; public static class HttpServiceExtensions { public static IServiceCollection UseHttpServices(this IServiceCollection services) { + services.AddLazyResolution(); services.AddScoped(); services.AddScoped(); services.AddScoped(); From 6c217270126fd0d2bec1241eb39016f2af52b256 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 22:50:13 +0100 Subject: [PATCH 031/185] Update HomeView.cs --- src/Mobile/Views/Home/HomeView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mobile/Views/Home/HomeView.cs b/src/Mobile/Views/Home/HomeView.cs index f5630114..6ec0517a 100644 --- a/src/Mobile/Views/Home/HomeView.cs +++ b/src/Mobile/Views/Home/HomeView.cs @@ -228,13 +228,13 @@ private async void HandleSelectionChanged(object? sender, SelectionChangedEventA public partial class HomeViewModel : ListViewModel { [ObservableProperty] private ObservableCollection? _recentItems; - [ObservableProperty] private ProfileResponse? _status; + [ObservableProperty] private UserResponse? _status; [RelayCommand] private async Task LoadDefaults() { IsLoading = true; await Task.Delay(500); - Status = new ProfileResponse { FirstName = "Saurav", LastName = "Argawal", Balance = 2000, Permission = UserPermission.Administrator }; + Status = new UserResponse { FirstName = "Saurav", LastName = "Argawal", Balance = 2000, Permission = UserPermission.Administrator }; RecentItems = new ObservableCollection { }; IsLoading = false; } From f177652a30bf3d4ce3e8d078dbbcdfd0f3195e96 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 22:51:03 +0100 Subject: [PATCH 032/185] Update type on auth response --- src/Common/Dtos/AuthResponse.cs | 2 +- src/Web/Client/App.razor | 1 + .../Pages/Startup/Registration.razor | 3 +- .../Modules/ProfileModule/ProfileModule.cs | 46 ++++++++----------- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/Common/Dtos/AuthResponse.cs b/src/Common/Dtos/AuthResponse.cs index 805e3222..c84e8bee 100644 --- a/src/Common/Dtos/AuthResponse.cs +++ b/src/Common/Dtos/AuthResponse.cs @@ -8,5 +8,5 @@ public class AuthResponse { public string Message { get; set; } = string.Empty; public string UserName { get; set; } = string.Empty; public string Role { get; set; } = string.Empty; - public ProfileResponse? Data { get; set; } + public UserResponse? Data { get; set; } } \ No newline at end of file diff --git a/src/Web/Client/App.razor b/src/Web/Client/App.razor index fe243099..71a59b56 100644 --- a/src/Web/Client/App.razor +++ b/src/Web/Client/App.razor @@ -7,6 +7,7 @@ var isAuthPath = args.Path.Equals(WebConst.AppAuth); var session = await AuthState.GetSession(); var isAuth = await AuthState.IsAuth(); + switch (isAuth) { case true when !session!.Confirmed && !args.Path.Equals(WebConst.AppRegister): Nav.NavigateTo(WebConst.AppRegister, true); diff --git a/src/Web/Components/Pages/Startup/Registration.razor b/src/Web/Components/Pages/Startup/Registration.razor index bfbb7064..810cb2bc 100644 --- a/src/Web/Components/Pages/Startup/Registration.razor +++ b/src/Web/Components/Pages/Startup/Registration.razor @@ -32,8 +32,7 @@ var session = await AuthState.GetSession(); if (session?.Data != null) { - ProfileResponse data = session.Data; - + UserResponse data = session.Data; // Check domain validation if (data.Email.IsNullOrEmpty()) await AuthState.TriggerSignOut(); diff --git a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs index 10367f75..45198a45 100644 --- a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs +++ b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs @@ -2,6 +2,7 @@ using IdentityModel; using Microsoft.AspNetCore.Authentication; using XClaim.Common.Dtos; +using XClaim.Common.Enums; using XClaim.Common.Wrappers; using XClaim.Web.Server.Modules.UserModule; @@ -19,43 +20,34 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { var group = endpoints.MapGroup(url).WithTags(name); group.MapGet("/account", async (HttpRequest request, UserService user) => { - bool isAuth = request.HttpContext.User.Identity?.IsAuthenticated ?? false; - + var userContext = request.HttpContext.User; + bool isAuth = userContext.Identity?.IsAuthenticated ?? false; if (!isAuth) return TypedResults.Unauthorized(); var auth = await request.HttpContext.AuthenticateAsync("Microsoft"); - var email = request.HttpContext.User.FindFirst(ClaimTypes.Email)?.Value ?? ""; - var role = request.HttpContext.User.FindFirst(ClaimTypes.Role)?.Value ?? ""; - var fullName = request.HttpContext.User.FindFirst(ClaimTypes.Name)?.Value ?? ""; - var phone = request.HttpContext.User.FindFirst(ClaimTypes.MobilePhone)?.Value ?? ""; + var email = userContext.FindFirst(ClaimTypes.Email)?.Value ?? ""; + var fullName = userContext.FindFirst(ClaimTypes.Name)?.Value ?? ""; + var phone = userContext.FindFirst(ClaimTypes.HomePhone)?.Value ?? ""; var names = fullName.Split(" "); var token = auth?.Properties?.GetTokenValue("access_token"); var expiry = (auth?.Properties?.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToDateTimeFromEpoch(); var expireIn = (int)expiry.Subtract(DateTime.Now).TotalSeconds; - ProfileResponse? profile; + UserResponse? profile = new UserResponse(); var account = (await user.GetByEmailAsync(email)).Data; - - if (account is null) { - profile = new ProfileResponse { - Email = email, - FirstName = names[0], - LastName = names[^1], - Phone = phone - }; + if (account == null) { + profile.Email = email; + profile.FirstName = names[0]; + profile.LastName = names[^1]; + profile.Phone = phone; } else { - profile = new ProfileResponse { - Email = account.Email, - FirstName = account.FirstName, - LastName = account.LastName, - Phone = account.LastName, - Permission = account.Permission, - Balance = account.Balance, - Team = account.Team - }; + profile = account; } + + var role = account?.Permission != null ? + account.Permission.ToString() : userContext.FindFirst(ClaimTypes.Role)?.Value ?? UserPermission.Standard.ToString(); - var result = new AuthResponse { + return Results.Ok(new Response(new AuthResponse { Confirmed = account != null, ExpiryTimeStamp = expiry, ExpiresIn = expireIn, @@ -64,9 +56,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { Message = "Success", Data = profile, UserName = fullName - }; - - return Results.Ok(new Response(result) { Succeeded = expireIn > 0 }); + }) { Succeeded = expireIn > 0 }); }).WithName("AccountProfile").WithOpenApi(); return group; From 31573dbb606e9a0f3a6c760a7451a9e0b85b02fa Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 22:51:38 +0100 Subject: [PATCH 033/185] Added company, team and currency data to user response --- src/Web/Server/Modules/UserModule/UserService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Web/Server/Modules/UserModule/UserService.cs b/src/Web/Server/Modules/UserModule/UserService.cs index efbb8490..2f11a263 100644 --- a/src/Web/Server/Modules/UserModule/UserService.cs +++ b/src/Web/Server/Modules/UserModule/UserService.cs @@ -14,7 +14,11 @@ public UserService(ServerContext ctx, IMapper mapper, ILogger logge public async Task> GetByEmailAsync(string email) { var item = await _ctx.Users .Where(x => x.DeletedAt == null) - .FirstOrDefaultAsync(u => u.Email == email); + .Where(x => x.Email == email) + .Include(x => x.Company) + .Include(x => x.Team) + .Include(x => x.Currency) + .FirstOrDefaultAsync(); var data = _mapper.Map(item); return new Response { @@ -58,6 +62,7 @@ public async Task>> GetAllAsync(UserFilter resp .Where(x => x.Id == id) .Include(x => x.Company) .Include(x => x.Team) + .Include(x => x.Currency) .FirstOrDefaultAsync(); var data = _mapper.Map(item); response.Data = data; From b493a71702a4c9e2beff4c829da368309cd81039 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Thu, 26 Jan 2023 22:51:59 +0100 Subject: [PATCH 034/185] Added token to request header --- src/Web/Shared/HttpService.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Web/Shared/HttpService.cs b/src/Web/Shared/HttpService.cs index 39e50ccb..4321f509 100644 --- a/src/Web/Shared/HttpService.cs +++ b/src/Web/Shared/HttpService.cs @@ -1,23 +1,23 @@ -using Microsoft.AspNetCore.Components; +using System.Net.Http.Headers; using XClaim.Common.Service; +using XClaim.Web.Shared.States; namespace XClaim.Web.Shared; public class HttpService : AbstractHttpService { - private readonly NavigationManager _navigation; + private readonly Lazy _state; - public HttpService(HttpClient http, NavigationManager navigation) : base(http) { - _navigation = navigation; + public HttpService(HttpClient http, Lazy state) : base(http) { + _state = state; } + protected override async Task AddJwtHeader(HttpRequestMessage request) { - // var user = await _localStorageService.GetItem("user"); - // var isApiUrl = !request.RequestUri.IsAbsoluteUri; - // if (user != null && isApiUrl) - // request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", user.Token); - await Task.CompletedTask; + var user = await _state.Value.GetSession(); + var isApiUrl = !request!.RequestUri!.IsAbsoluteUri; + if (user != null && isApiUrl) + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", user.Token); } protected override async Task SignOut() { - _navigation.NavigateTo(""); - await Task.CompletedTask; + await _state.Value.TriggerSignOut(); } } \ No newline at end of file From 759c547b41cac903d20707518bac960f2cb69d9a Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 00:24:52 +0100 Subject: [PATCH 035/185] Update AbstractHttpService.cs --- src/Common/Service/AbstractHttpService.cs | 44 ++++++++++++++--------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Common/Service/AbstractHttpService.cs b/src/Common/Service/AbstractHttpService.cs index f8187424..cc32cdf1 100644 --- a/src/Common/Service/AbstractHttpService.cs +++ b/src/Common/Service/AbstractHttpService.cs @@ -70,30 +70,40 @@ private HttpRequestMessage CreateRequest(HttpMethod method, string uri, object? private async Task SendRequest(HttpRequestMessage request) { await AddJwtHeader(request); - using var response = await _http.SendAsync(request); - if (response.StatusCode == HttpStatusCode.Unauthorized) { - await SignOut(); - return; + try { + using var response = await _http.SendAsync(request); + if (response.StatusCode == HttpStatusCode.Unauthorized) { + await SignOut(); + return; + } + await HandleErrors(response); + } + catch (Exception) { + Console.WriteLine("A HTTP callback error occurred"); } - - await HandleErrors(response); } private async Task SendRequest(HttpRequestMessage request) { await AddJwtHeader(request); - using var response = await _http.SendAsync(request); - if (response.StatusCode == HttpStatusCode.Unauthorized) { - await SignOut(); - return default!; + try { + using var response = await _http.SendAsync(request); + if (response.StatusCode == HttpStatusCode.Unauthorized) { + await SignOut(); + return default!; + } + await HandleErrors(response); + var options = new JsonSerializerOptions { + PropertyNameCaseInsensitive = true + }; + options.Converters.Add(new StringConverter()); + + return (await response.Content.ReadFromJsonAsync(options))!; + } + catch (Exception) { + Console.WriteLine("A HTTP callback error occurred"); } - await HandleErrors(response); - var options = new JsonSerializerOptions { - PropertyNameCaseInsensitive = true - }; - options.Converters.Add(new StringConverter()); - - return (await response.Content.ReadFromJsonAsync(options))!; + return default!; } protected abstract Task AddJwtHeader(HttpRequestMessage request); From 506683d8a963d9d18e1ee02e42df98fce595d5c8 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 01:00:24 +0100 Subject: [PATCH 036/185] Improve role permissions --- src/Web/Client/App.razor | 3 --- src/Web/Components/Pages/Reviews/Index.razor | 2 +- src/Web/Components/Pages/Settings/Bank/Index.razor | 2 +- src/Web/Components/Pages/Settings/Category/Index.razor | 2 +- src/Web/Components/Pages/Settings/Company/Index.razor | 2 +- src/Web/Components/Pages/Settings/Currency/Index.razor | 2 +- src/Web/Components/Pages/Settings/Domains/Index.razor | 2 +- src/Web/Components/Pages/Settings/Server.razor | 2 +- src/Web/Components/Pages/Settings/Teams/Index.razor | 2 +- src/Web/Components/Pages/Transactions/Index.razor | 2 +- src/Web/Components/Pages/User/Index.razor | 3 ++- src/Web/Server/Modules/ProfileModule/ProfileModule.cs | 4 ++-- 12 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Web/Client/App.razor b/src/Web/Client/App.razor index 71a59b56..6e6b41e1 100644 --- a/src/Web/Client/App.razor +++ b/src/Web/Client/App.razor @@ -44,9 +44,6 @@

You are not authorized to access this resource.

} - - ... - diff --git a/src/Web/Components/Pages/Reviews/Index.razor b/src/Web/Components/Pages/Reviews/Index.razor index a6ca3bc2..407fcdeb 100644 --- a/src/Web/Components/Pages/Reviews/Index.razor +++ b/src/Web/Components/Pages/Reviews/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject IClaimService Http @page "/app/reviews" -@attribute [Authorize] +@attribute [Authorize(Roles = "System, Administrator, Finance, Lead")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Settings/Bank/Index.razor b/src/Web/Components/Pages/Settings/Bank/Index.razor index e9985e5c..a298e16c 100644 --- a/src/Web/Components/Pages/Settings/Bank/Index.razor +++ b/src/Web/Components/Pages/Settings/Bank/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject IBankService Http @page "/app/settings/banks" -@attribute [Authorize] +@attribute [Authorize(Roles = "System, Administrator")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Settings/Category/Index.razor b/src/Web/Components/Pages/Settings/Category/Index.razor index f76543fc..23d3c7c2 100644 --- a/src/Web/Components/Pages/Settings/Category/Index.razor +++ b/src/Web/Components/Pages/Settings/Category/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject ICategoryService Http @page "/app/settings/category" -@attribute [Authorize] +@attribute [Authorize(Roles = "System, Administrator")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Settings/Company/Index.razor b/src/Web/Components/Pages/Settings/Company/Index.razor index 912bab69..3be40e84 100644 --- a/src/Web/Components/Pages/Settings/Company/Index.razor +++ b/src/Web/Components/Pages/Settings/Company/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject ICompanyService Http @page "/app/settings/companies" -@attribute [Authorize] +@attribute [Authorize(Roles = "System")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Settings/Currency/Index.razor b/src/Web/Components/Pages/Settings/Currency/Index.razor index 4d1b1a53..ef389a8b 100644 --- a/src/Web/Components/Pages/Settings/Currency/Index.razor +++ b/src/Web/Components/Pages/Settings/Currency/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject ICurrencyService Http @page "/app/settings/currency" -@attribute [Authorize] +@attribute [Authorize(Roles = "System")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Settings/Domains/Index.razor b/src/Web/Components/Pages/Settings/Domains/Index.razor index b6c180d3..ed51f1fe 100644 --- a/src/Web/Components/Pages/Settings/Domains/Index.razor +++ b/src/Web/Components/Pages/Settings/Domains/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject IDomainService Http @page "/app/settings/domains" -@attribute [Authorize] +@attribute [Authorize(Roles = "System")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Settings/Server.razor b/src/Web/Components/Pages/Settings/Server.razor index b993f9b3..05f1b4ef 100644 --- a/src/Web/Components/Pages/Settings/Server.razor +++ b/src/Web/Components/Pages/Settings/Server.razor @@ -1,6 +1,6 @@ @inject NavigationManager Nav @page "/app/settings/server" -@attribute [Authorize] +@attribute [Authorize(Roles = "System")] @code { } diff --git a/src/Web/Components/Pages/Settings/Teams/Index.razor b/src/Web/Components/Pages/Settings/Teams/Index.razor index c3072ee5..db65bf47 100644 --- a/src/Web/Components/Pages/Settings/Teams/Index.razor +++ b/src/Web/Components/Pages/Settings/Teams/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject ITeamService Http @page "/app/settings/teams" -@attribute [Authorize] +@attribute [Authorize(Roles = "System, Administrator")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/Transactions/Index.razor b/src/Web/Components/Pages/Transactions/Index.razor index f228518c..c62fd610 100644 --- a/src/Web/Components/Pages/Transactions/Index.razor +++ b/src/Web/Components/Pages/Transactions/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject IPaymentService Http @page "/app/transactions" -@attribute [Authorize] +@attribute [Authorize(Roles = "System, Administrator, Finance, Cashier")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Components/Pages/User/Index.razor b/src/Web/Components/Pages/User/Index.razor index 8364776f..718fdb1c 100644 --- a/src/Web/Components/Pages/User/Index.razor +++ b/src/Web/Components/Pages/User/Index.razor @@ -1,8 +1,9 @@ @using XClaim.Common.Dtos +@using XClaim.Common.Enums @using XClaim.Common.Helpers @page "/app/users" @inject IUserService Http -@attribute [Authorize] +@attribute [Authorize(Roles = "System, Administrator")] @code { private string Search { get; set; } = string.Empty; diff --git a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs index 45198a45..49ccb167 100644 --- a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs +++ b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs @@ -43,9 +43,9 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { } else { profile = account; } - + var role = account?.Permission != null ? - account.Permission.ToString() : userContext.FindFirst(ClaimTypes.Role)?.Value ?? UserPermission.Standard.ToString(); + Enum.GetName(account.Permission)! : userContext.FindFirst(ClaimTypes.Role)?.Value ?? Enum.GetName(UserPermission.Standard)!; return Results.Ok(new Response(new AuthResponse { Confirmed = account != null, From 3d6b14150d961848c81e98b4eb5e6f04c245039e Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 08:31:32 +0100 Subject: [PATCH 037/185] Added 404 and UnAuthorized banner --- src/Web/Client/App.razor | 19 ++++++++++++++----- src/Web/Components/Pages/Startup/Auth.razor | 3 --- src/Web/Components/Shared/ErrorFound.razor | 12 ++++++++++++ src/Web/Components/Shared/NotAuthorized.razor | 12 ++++++++++++ src/Web/Components/Shared/UnAuthorized.razor | 1 - src/Web/Components/wwwroot/vectors/404.svg | 1 + .../wwwroot/vectors/not_permitted.svg | 1 + 7 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 src/Web/Components/Shared/ErrorFound.razor create mode 100644 src/Web/Components/Shared/NotAuthorized.razor delete mode 100644 src/Web/Components/Shared/UnAuthorized.razor create mode 100644 src/Web/Components/wwwroot/vectors/404.svg create mode 100644 src/Web/Components/wwwroot/vectors/not_permitted.svg diff --git a/src/Web/Client/App.razor b/src/Web/Client/App.razor index 6e6b41e1..a9cd5f20 100644 --- a/src/Web/Client/App.razor +++ b/src/Web/Client/App.razor @@ -41,16 +41,25 @@ @if (context.User.Identity?.IsAuthenticated != true) { } else { -

You are not authorized to access this resource.

+ } - Not Found - -

Sorry, there's nothing at this address.

-
+ Not Found + + + + + + + + + + + +
diff --git a/src/Web/Components/Pages/Startup/Auth.razor b/src/Web/Components/Pages/Startup/Auth.razor index 6a7736d1..541d357e 100644 --- a/src/Web/Components/Pages/Startup/Auth.razor +++ b/src/Web/Components/Pages/Startup/Auth.razor @@ -9,7 +9,4 @@ - - Home - \ No newline at end of file diff --git a/src/Web/Components/Shared/ErrorFound.razor b/src/Web/Components/Shared/ErrorFound.razor new file mode 100644 index 00000000..b079dac1 --- /dev/null +++ b/src/Web/Components/Shared/ErrorFound.razor @@ -0,0 +1,12 @@ +@inject NavigationManager Nav +@code { + private void BackHome() => Nav.NavigateTo(WebConst.AppHome); +} + + + + + Page Not Found + Home + + \ No newline at end of file diff --git a/src/Web/Components/Shared/NotAuthorized.razor b/src/Web/Components/Shared/NotAuthorized.razor new file mode 100644 index 00000000..6c32e51d --- /dev/null +++ b/src/Web/Components/Shared/NotAuthorized.razor @@ -0,0 +1,12 @@ +@inject NavigationManager Nav +@code { + private void BackHome() => Nav.NavigateTo(WebConst.AppHome); +} + + + + + Role Not Authorized + Home + + \ No newline at end of file diff --git a/src/Web/Components/Shared/UnAuthorized.razor b/src/Web/Components/Shared/UnAuthorized.razor deleted file mode 100644 index 7437745a..00000000 --- a/src/Web/Components/Shared/UnAuthorized.razor +++ /dev/null @@ -1 +0,0 @@ -

unauthorzed

diff --git a/src/Web/Components/wwwroot/vectors/404.svg b/src/Web/Components/wwwroot/vectors/404.svg new file mode 100644 index 00000000..8735cf86 --- /dev/null +++ b/src/Web/Components/wwwroot/vectors/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Web/Components/wwwroot/vectors/not_permitted.svg b/src/Web/Components/wwwroot/vectors/not_permitted.svg new file mode 100644 index 00000000..1e569852 --- /dev/null +++ b/src/Web/Components/wwwroot/vectors/not_permitted.svg @@ -0,0 +1 @@ + \ No newline at end of file From ccc01fc7ab4e716796f4914e2b9c3557040b61af Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 12:12:31 +0100 Subject: [PATCH 038/185] Fix permission --- src/Web/Components/Pages/Settings/Bank/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Components/Pages/Settings/Bank/Index.razor b/src/Web/Components/Pages/Settings/Bank/Index.razor index a298e16c..75dc8cac 100644 --- a/src/Web/Components/Pages/Settings/Bank/Index.razor +++ b/src/Web/Components/Pages/Settings/Bank/Index.razor @@ -2,7 +2,7 @@ @using XClaim.Common.Helpers @inject IBankService Http @page "/app/settings/banks" -@attribute [Authorize(Roles = "System, Administrator")] +@attribute [Authorize(Roles = "System")] @code { private string Search { get; set; } = string.Empty; From 7d37f98975d6d41575e1dfead9d56a19227332e3 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 12:13:05 +0100 Subject: [PATCH 039/185] Added currency code to module --- src/Common/Dtos/CurrencyResponse.cs | 1 + .../Pages/Settings/Currency/Index.razor | 1 + .../Settings/Currency/MutateCurrency.razor | 22 +++++++++---------- src/Web/Server/Data/DbInitializer.cs | 20 +++++++++-------- src/Web/Server/Entities/CurrencyEntity.cs | 5 ++++- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/Common/Dtos/CurrencyResponse.cs b/src/Common/Dtos/CurrencyResponse.cs index 1785e328..80892b80 100644 --- a/src/Common/Dtos/CurrencyResponse.cs +++ b/src/Common/Dtos/CurrencyResponse.cs @@ -6,6 +6,7 @@ public class CurrencyResponse : BaseResponse { public string Name { get; set; } = string.Empty; public string Symbol { get; set; } = string.Empty; + public string Code { get; set; } = string.Empty; public decimal Rate { get; set; } public string Description { get; set; } = string.Empty; public bool Active { get; set; } diff --git a/src/Web/Components/Pages/Settings/Currency/Index.razor b/src/Web/Components/Pages/Settings/Currency/Index.razor index ef389a8b..f6b17619 100644 --- a/src/Web/Components/Pages/Settings/Currency/Index.razor +++ b/src/Web/Components/Pages/Settings/Currency/Index.razor @@ -58,6 +58,7 @@ + diff --git a/src/Web/Components/Pages/Settings/Currency/MutateCurrency.razor b/src/Web/Components/Pages/Settings/Currency/MutateCurrency.razor index a6aab2ea..1b3aa0ee 100644 --- a/src/Web/Components/Pages/Settings/Currency/MutateCurrency.razor +++ b/src/Web/Components/Pages/Settings/Currency/MutateCurrency.razor @@ -55,27 +55,27 @@
- - - - + - - + + - - + + + + + - + - + @@ -83,6 +83,6 @@ - @ActionText + @ActionText \ No newline at end of file diff --git a/src/Web/Server/Data/DbInitializer.cs b/src/Web/Server/Data/DbInitializer.cs index 51415ec3..4f8858be 100644 --- a/src/Web/Server/Data/DbInitializer.cs +++ b/src/Web/Server/Data/DbInitializer.cs @@ -32,18 +32,21 @@ public void Seed() { var domains = new List { new DomainEntity { Id = Guid.NewGuid(), CreatedAt = time, Address = "tolaram.com" }, new DomainEntity { Id = Guid.NewGuid(), CreatedAt = time, Address = "dufil.com" }, - new DomainEntity { Id = Guid.NewGuid(), CreatedAt = time, Address = "agboolas@outlook.com"} + new DomainEntity { Id = Guid.NewGuid(), CreatedAt = time, Address = "outlook.com"} }; var currencies = new List { - new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Naira", Symbol = "₦" }, - new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Dollar", Symbol = "$" } + new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Naira", Code = "NGN", Symbol = "₦" }, + new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "US Dollar", Code = "USD", Symbol = "$" }, + new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Euro", Code = "EUR", Symbol = "€" }, + new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "British Pounds", Code = "GBP", Symbol = "£" }, + new CurrencyEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Rupee", Code = "INR", Symbol = "₹" } }; var companies = new List { - new CompanyEntity() { Id = Guid.NewGuid(), CreatedAt = time, ShortName = "BHN LTD", FullName = "MCPL LTD - BHN Division" }, + new CompanyEntity() { Id = Guid.NewGuid(), CreatedAt = time, ShortName = "BHN Logistics", FullName = "MCPL LTD - BHN Division" }, new CompanyEntity() { Id = Guid.NewGuid(), CreatedAt = time, ShortName = "MCPL LTD", FullName = "Multi Consumer Product LTD" }, - new CompanyEntity() { Id = Guid.NewGuid(), CreatedAt = time, ShortName = "Dufil", FullName = "Dufil Prima Foods Plc" } + new CompanyEntity() { Id = Guid.NewGuid(), CreatedAt = time, ShortName = "Dufil Prima", FullName = "Dufil Prima Foods Plc" } }; var categories = new List { @@ -56,13 +59,12 @@ public void Seed() { var teams = new List { new TeamEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Account Dept", CompanyId = companies[0].Id }, new TeamEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Logistics Dept", CompanyId = companies[1].Id }, - new TeamEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "QA Dept", CompanyId = companies[2].Id } + new TeamEntity { Id = Guid.NewGuid(), CreatedAt = time, Name = "Packaging Dept", CompanyId = companies[2].Id } }; var users = new List { - new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, Permission = UserPermission.Administrator, FirstName = "John", LastName = "Doe", Email = "john.doe@test.com", Phone = "+23401", TeamId = teams[0].Id,CompanyId = companies[0].Id }, - new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, FirstName = "Jane", LastName = "Doe", Email = "jane.doe@test.com", Phone = "+23402", TeamId = teams[1].Id, CompanyId = companies[1].Id }, - new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, FirstName = "Johnny ", LastName = "Test", Email = "johnny.test@test.com", Phone = "+23403", TeamId = teams[2].Id, CompanyId = companies[2].Id }, + new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, FirstName = "John", LastName = "Doe", Email = "john.doe@tolaram.com", Phone = "+234012345567", TeamId = teams[0].Id, CompanyId = companies[0].Id }, + new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, FirstName = "Jane", LastName = "Doe", Email = "jane.doe@tolaram.com", Phone = "+234022424553", TeamId = teams[1].Id, CompanyId = companies[1].Id } }; _modelBuilder.Entity().HasData(banks); diff --git a/src/Web/Server/Entities/CurrencyEntity.cs b/src/Web/Server/Entities/CurrencyEntity.cs index 2b69ff26..8cc21eca 100644 --- a/src/Web/Server/Entities/CurrencyEntity.cs +++ b/src/Web/Server/Entities/CurrencyEntity.cs @@ -5,10 +5,13 @@ namespace XClaim.Web.Server.Entities; [Index(nameof(Name), IsUnique = true)] +[Index(nameof(Code), IsUnique = true)] public class CurrencyEntity : BaseEntity { public string Name { get; set; } = string.Empty; - [MaxLength(4)] + [MaxLength(1)] public string Symbol { get; set; } = string.Empty; + [MaxLength(3)] + public string Code { get; set; } = string.Empty; public decimal Rate { get; set; } public string Description { get; set; } = string.Empty; public bool Active { get; set; } From 181af5d40da3182fc1ab0e361d86b9977c77b74c Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 12:13:58 +0100 Subject: [PATCH 040/185] Added automatic migration --- src/Web/Server/Program.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Web/Server/Program.cs b/src/Web/Server/Program.cs index 59da39b0..d9ffddef 100644 --- a/src/Web/Server/Program.cs +++ b/src/Web/Server/Program.cs @@ -71,6 +71,13 @@ } WebApplication app = builder.Build(); + +using (var scope = app.Services.CreateScope()) { + var services = scope.ServiceProvider; + var context = services.GetRequiredService(); + await context.Database.MigrateAsync(); +} + if (app.Environment.IsDevelopment()) { app.UseWebAssemblyDebugging(); _ = app.UseSwagger(); From 4106e17075e43d0bbaf5876ad9310e8c8bac9873 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 12:17:00 +0100 Subject: [PATCH 041/185] Added custom registration and system admin to user service --- .../Server/Modules/UserModule/UserService.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Web/Server/Modules/UserModule/UserService.cs b/src/Web/Server/Modules/UserModule/UserService.cs index 2f11a263..b857d239 100644 --- a/src/Web/Server/Modules/UserModule/UserService.cs +++ b/src/Web/Server/Modules/UserModule/UserService.cs @@ -2,6 +2,7 @@ using AutoMapper; using Microsoft.EntityFrameworkCore; using XClaim.Common.Dtos; +using XClaim.Common.Enums; using XClaim.Common.Helpers; using XClaim.Common.Wrappers; using XClaim.Web.Server.Data; @@ -75,4 +76,25 @@ public async Task>> GetAllAsync(UserFilter resp return response; } + + new public async Task> CreateAsync(UserResponse value) { + var response = new Response(); + try { + var item = _mapper.Map(value); + var isAdmin = (await _ctx.Users.CountAsync(x => x.Permission == UserPermission.System)) < 1; + if (isAdmin) item.Permission = UserPermission.System; + await _ctx.Users.AddAsync(item); + await _ctx.SaveChangesAsync(); + var data = _mapper.Map(item); + response = new Response(data!) { + Succeeded = data != null + }; + } + catch (Exception e) { + response.Errors = new[] { e.ToString() }; + _logger.LogError(e.ToString()); + } + + return response; + } } \ No newline at end of file From 128d26f6b0682deb7c55472f0951652b848410fe Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 16:33:58 +0100 Subject: [PATCH 042/185] Seal service classes --- src/Web/Server/Modules/BankModule/BankService.cs | 2 +- src/Web/Server/Modules/CategoryModule/CategoryService.cs | 4 ++-- src/Web/Server/Modules/ClaimModule/ClaimService.cs | 6 +++--- src/Web/Server/Modules/CompanyModule/CompanyService.cs | 2 +- src/Web/Server/Modules/CurrencyModule/CurrencyService.cs | 2 +- src/Web/Server/Modules/DomainModule/DomainService.cs | 2 +- src/Web/Server/Modules/EventModule/EventService.cs | 2 +- src/Web/Server/Modules/PaymentModule/PaymentService.cs | 2 +- src/Web/Server/Modules/TeamModule/TeamService.cs | 6 +++--- src/Web/Server/Modules/UserModule/UserService.cs | 4 ++-- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Web/Server/Modules/BankModule/BankService.cs b/src/Web/Server/Modules/BankModule/BankService.cs index 1b0400d1..01d7a4c7 100644 --- a/src/Web/Server/Modules/BankModule/BankService.cs +++ b/src/Web/Server/Modules/BankModule/BankService.cs @@ -5,6 +5,6 @@ namespace XClaim.Web.Server.Modules.BankModule; -public class BankService : GenericService, IBankService { +public sealed class BankService : GenericService, IBankService { public BankService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } } \ No newline at end of file diff --git a/src/Web/Server/Modules/CategoryModule/CategoryService.cs b/src/Web/Server/Modules/CategoryModule/CategoryService.cs index f5a360d7..cf6f7090 100644 --- a/src/Web/Server/Modules/CategoryModule/CategoryService.cs +++ b/src/Web/Server/Modules/CategoryModule/CategoryService.cs @@ -10,7 +10,7 @@ namespace XClaim.Web.Server.Modules.CategoryModule; -public class CategoryService : GenericService { +public sealed class CategoryService : GenericService { public CategoryService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { @@ -38,7 +38,7 @@ public CategoryService(ServerContext ctx, IMapper mapper, ILogger> GetByIdAsync(Guid id) { + new public async Task> GetByIdAsync(Guid id) { var result = new Response(); try { var item = await _ctx.Categories diff --git a/src/Web/Server/Modules/ClaimModule/ClaimService.cs b/src/Web/Server/Modules/ClaimModule/ClaimService.cs index 76704549..6d9b86f7 100644 --- a/src/Web/Server/Modules/ClaimModule/ClaimService.cs +++ b/src/Web/Server/Modules/ClaimModule/ClaimService.cs @@ -10,10 +10,10 @@ namespace XClaim.Web.Server.Modules.ClaimModule; -public class ClaimService : GenericService, IClaimService { +public sealed class ClaimService : GenericService, IClaimService { public ClaimService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } - new public virtual async Task>> GetAllAsync(PaginationFilterBase responseFilter) { + new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { var result = new PagedResponse>(); var query = _ctx.Claims.Where(x => x.DeletedAt == null) .Include(x => x.Owner) @@ -38,7 +38,7 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log return result; } - new public virtual async Task> GetByIdAsync(Guid id) { + new public async Task> GetByIdAsync(Guid id) { var response = new Response(); try { var item = await _ctx.Claims.Where(x => x.Id == id) diff --git a/src/Web/Server/Modules/CompanyModule/CompanyService.cs b/src/Web/Server/Modules/CompanyModule/CompanyService.cs index e435c23c..f82594d9 100644 --- a/src/Web/Server/Modules/CompanyModule/CompanyService.cs +++ b/src/Web/Server/Modules/CompanyModule/CompanyService.cs @@ -10,7 +10,7 @@ namespace XClaim.Web.Server.Modules.CompanyModule; -public class CompanyService : GenericService { +public sealed class CompanyService : GenericService { public CompanyService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { diff --git a/src/Web/Server/Modules/CurrencyModule/CurrencyService.cs b/src/Web/Server/Modules/CurrencyModule/CurrencyService.cs index 835dabcc..88bc81c1 100644 --- a/src/Web/Server/Modules/CurrencyModule/CurrencyService.cs +++ b/src/Web/Server/Modules/CurrencyModule/CurrencyService.cs @@ -5,6 +5,6 @@ namespace XClaim.Web.Server.Modules.CurrencyModule; -public class CurrencyService : GenericService { +public sealed class CurrencyService : GenericService { public CurrencyService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } } \ No newline at end of file diff --git a/src/Web/Server/Modules/DomainModule/DomainService.cs b/src/Web/Server/Modules/DomainModule/DomainService.cs index 4264b90b..a7fcbdac 100644 --- a/src/Web/Server/Modules/DomainModule/DomainService.cs +++ b/src/Web/Server/Modules/DomainModule/DomainService.cs @@ -5,6 +5,6 @@ namespace XClaim.Web.Server.Modules.DomainModule; -public class DomainService : GenericService { +public sealed class DomainService : GenericService { public DomainService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } } \ No newline at end of file diff --git a/src/Web/Server/Modules/EventModule/EventService.cs b/src/Web/Server/Modules/EventModule/EventService.cs index c6a3483d..ae0cb6e4 100644 --- a/src/Web/Server/Modules/EventModule/EventService.cs +++ b/src/Web/Server/Modules/EventModule/EventService.cs @@ -5,7 +5,7 @@ namespace XClaim.Web.Server.Modules.EventModule; -public class EventService : GenericService, IEventService { +public sealed class EventService : GenericService, IEventService { public EventService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } public Task ClearOld() { throw new NotImplementedException(); diff --git a/src/Web/Server/Modules/PaymentModule/PaymentService.cs b/src/Web/Server/Modules/PaymentModule/PaymentService.cs index e60f9d75..6a0a4fe1 100644 --- a/src/Web/Server/Modules/PaymentModule/PaymentService.cs +++ b/src/Web/Server/Modules/PaymentModule/PaymentService.cs @@ -5,6 +5,6 @@ namespace XClaim.Web.Server.Modules.PaymentModule; -public class PaymentService : GenericService { +public sealed class PaymentService : GenericService { public PaymentService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } } \ No newline at end of file diff --git a/src/Web/Server/Modules/TeamModule/TeamService.cs b/src/Web/Server/Modules/TeamModule/TeamService.cs index 47de0685..228ba2d1 100644 --- a/src/Web/Server/Modules/TeamModule/TeamService.cs +++ b/src/Web/Server/Modules/TeamModule/TeamService.cs @@ -10,10 +10,10 @@ namespace XClaim.Web.Server.Modules.TeamModule; -public class TeamService : GenericService { +public sealed class TeamService : GenericService { public TeamService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } - new public virtual async Task>> GetAllAsync(PaginationFilterBase responseFilter) { + new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { var result = new PagedResponse>(); var query = _ctx.Teams .Include(e => e.Company) @@ -41,7 +41,7 @@ public TeamService(ServerContext ctx, IMapper mapper, ILogger logge return result; } - new public virtual async Task> GetByIdAsync(Guid id) { + new public async Task> GetByIdAsync(Guid id) { var result = new Response(); try { var item = await _ctx.Teams diff --git a/src/Web/Server/Modules/UserModule/UserService.cs b/src/Web/Server/Modules/UserModule/UserService.cs index b857d239..2d4ca6e4 100644 --- a/src/Web/Server/Modules/UserModule/UserService.cs +++ b/src/Web/Server/Modules/UserModule/UserService.cs @@ -10,7 +10,7 @@ namespace XClaim.Web.Server.Modules.UserModule; -public class UserService : GenericService, IUserService { +public sealed class UserService : GenericService, IUserService { public UserService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } public async Task> GetByEmailAsync(string email) { var item = await _ctx.Users @@ -56,7 +56,7 @@ public async Task>> GetAllAsync(UserFilter resp return result; } - new public virtual async Task> GetByIdAsync(Guid id) { + new public async Task> GetByIdAsync(Guid id) { var response = new Response(); try { var item = await _ctx.Users From e4a68e6524c42c17b80656b33125614a2892752c Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Fri, 27 Jan 2023 16:34:19 +0100 Subject: [PATCH 043/185] Added session extensions --- src/Web/Server/Program.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Web/Server/Program.cs b/src/Web/Server/Program.cs index d9ffddef..b6a44011 100644 --- a/src/Web/Server/Program.cs +++ b/src/Web/Server/Program.cs @@ -51,6 +51,13 @@ builder.Services.AddHttpContextAccessor(); ; builder.Services.AddAuthorization(); +builder.Services.AddDistributedMemoryCache(); +builder.Services.AddSession(options => { + options.IdleTimeout = TimeSpan.FromDays(7); + options.Cookie.HttpOnly = true; + options.Cookie.IsEssential = true; +}); + builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(opt => { _ = opt.UseAutoFiltererParameters(); @@ -95,17 +102,19 @@ } app.UseCookiePolicy(new CookiePolicyOptions { - MinimumSameSitePolicy = SameSiteMode.Lax + MinimumSameSitePolicy = SameSiteMode.None }); -app.RegisterApiEndpoints(); + app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); -app.MapRazorPages(); app.MapControllers(); app.MapFallbackToFile("index.html"); app.UseAuthentication(); app.UseAuthorization(); +app.UseSession(); +app.MapRazorPages(); +app.RegisterApiEndpoints(); // INFO: Disabled due to mobile self signed certificate // app.UseHttpsRedirection(); From 6d4d41b3ec307103aa37500b63bbffce8afb6db7 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sat, 28 Jan 2023 03:12:05 +0100 Subject: [PATCH 044/185] Added identifier field to user entity and response --- src/Common/Dtos/UserResponse.cs | 1 + src/Web/Server/Data/DbInitializer.cs | 5 +++-- src/Web/Server/Entities/UserEntity.cs | 2 ++ src/Web/Server/XClaim.Web.Server.csproj | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Common/Dtos/UserResponse.cs b/src/Common/Dtos/UserResponse.cs index bd9157fc..34a66436 100644 --- a/src/Common/Dtos/UserResponse.cs +++ b/src/Common/Dtos/UserResponse.cs @@ -4,6 +4,7 @@ namespace XClaim.Common.Dtos; public class UserResponse : BaseResponse { + public string Identifier { get; set; } = string.Empty; public string Email { get; set; } = String.Empty; public string Phone { get; set; } = String.Empty; public string FirstName { get; set; } = String.Empty; diff --git a/src/Web/Server/Data/DbInitializer.cs b/src/Web/Server/Data/DbInitializer.cs index 4f8858be..7ed09b60 100644 --- a/src/Web/Server/Data/DbInitializer.cs +++ b/src/Web/Server/Data/DbInitializer.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using SourceExpress.ShorterGuid; using XClaim.Common.Enums; using XClaim.Web.Server.Entities; @@ -63,8 +64,8 @@ public void Seed() { }; var users = new List { - new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, FirstName = "John", LastName = "Doe", Email = "john.doe@tolaram.com", Phone = "+234012345567", TeamId = teams[0].Id, CompanyId = companies[0].Id }, - new UserEntity { Id = Guid.NewGuid(), CreatedAt = time, FirstName = "Jane", LastName = "Doe", Email = "jane.doe@tolaram.com", Phone = "+234022424553", TeamId = teams[1].Id, CompanyId = companies[1].Id } + new UserEntity { Id = Guid.NewGuid(), Identifier = (Guid.NewGuid()).ToLowerShorterString(), CreatedAt = time, FirstName = "John", LastName = "Doe", Email = "john.doe@tolaram.com", Phone = "+234012345567", TeamId = teams[0].Id, CompanyId = companies[0].Id }, + new UserEntity { Id = Guid.NewGuid(), Identifier = (Guid.NewGuid()).ToLowerShorterString(), CreatedAt = time, FirstName = "Jane", LastName = "Doe", Email = "jane.doe@tolaram.com", Phone = "+234022424553", TeamId = teams[1].Id, CompanyId = companies[1].Id } }; _modelBuilder.Entity().HasData(banks); diff --git a/src/Web/Server/Entities/UserEntity.cs b/src/Web/Server/Entities/UserEntity.cs index dfd32c7a..62fda342 100644 --- a/src/Web/Server/Entities/UserEntity.cs +++ b/src/Web/Server/Entities/UserEntity.cs @@ -6,7 +6,9 @@ namespace XClaim.Web.Server.Entities; [Index(nameof(Email), IsUnique = true)] +[Index(nameof(Identifier), IsUnique = true)] public sealed class UserEntity : BaseEntity { + public string Identifier { get; set; } = string.Empty; [MaxLength(256)] public string Email { get; set; } = string.Empty; public string? ProfileImage { get; set; } diff --git a/src/Web/Server/XClaim.Web.Server.csproj b/src/Web/Server/XClaim.Web.Server.csproj index a50fe573..2a40bf07 100644 --- a/src/Web/Server/XClaim.Web.Server.csproj +++ b/src/Web/Server/XClaim.Web.Server.csproj @@ -36,6 +36,7 @@ + From cae13b059b2d6fb802181d37a8cce8fef6aeb0a7 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sat, 28 Jan 2023 03:13:07 +0100 Subject: [PATCH 045/185] Added authentication and identity helper --- src/Web/Server/Helpers/IdentityHelper.cs | 76 +++++++++++++++++++ .../Modules/ProfileModule/ProfileModule.cs | 46 +++-------- .../Server/Modules/UserModule/UserService.cs | 23 +++++- src/Web/Server/Program.cs | 1 + 4 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 src/Web/Server/Helpers/IdentityHelper.cs diff --git a/src/Web/Server/Helpers/IdentityHelper.cs b/src/Web/Server/Helpers/IdentityHelper.cs new file mode 100644 index 00000000..05506f04 --- /dev/null +++ b/src/Web/Server/Helpers/IdentityHelper.cs @@ -0,0 +1,76 @@ +using System.Security.Claims; +using IdentityModel; +using Microsoft.AspNetCore.Authentication; +using XClaim.Common.Dtos; +using XClaim.Web.Server.Data; +using XClaim.Web.Server.Entities; + +namespace XClaim.Web.Server.Helpers; + +public sealed class IdentityHelper { + + private readonly IHttpContextAccessor _contextAccessor; + private readonly ServerContext _ctx; + + public IdentityHelper(IHttpContextAccessor contextAccessor, ServerContext ctx) { + _contextAccessor = contextAccessor; + _ctx = ctx; + } + + private ClaimsPrincipal? Claim { + get { return _contextAccessor?.HttpContext?.User; } + } + + public string? NameIdentifier { + get { + return this.Claim!.FindFirstValue(ClaimTypes.NameIdentifier); + } + } + + public bool IsAuthenticated { + get { + return this.Claim?.Identity?.IsAuthenticated ?? false; + } + } + + public async Task GetAuthProfile() { + var ctx = _contextAccessor!.HttpContext; + var auth = await ctx!.AuthenticateAsync("Microsoft"); + + // Get required options + var email = this.Claim!.FindFirstValue(ClaimTypes.Email) ?? ""; + var fullName = this.Claim!.FindFirstValue(ClaimTypes.Name) ?? ""; + var phone = this.Claim!.FindFirstValue(ClaimTypes.HomePhone) ?? ""; + var token = auth?.Properties?.GetTokenValue("access_token"); + var expiry = (auth?.Properties?.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToDateTimeFromEpoch(); + var expireIn = (int)expiry.Subtract(DateTime.Now).TotalSeconds; + + var names = fullName.Split(" "); + var data = new UserResponse { + Identifier = this.NameIdentifier ?? "", + Email = email, + FirstName = names[0], + LastName = names[^1], + Phone = phone + }; + + return new AuthResponse { + ExpiryTimeStamp = expiry, + ExpiresIn = expireIn, + Token = token, + Message = "Success", + UserName = fullName, + Data = data + }; + } + + public async Task GetUser() => default!; + + public async Task GetManager() => default!; + + public async Task HasManager() => default!; + + public async Task GetCompany() => default!; + + public async Task GetTeam() => default!; +} \ No newline at end of file diff --git a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs index 49ccb167..85a2ec13 100644 --- a/src/Web/Server/Modules/ProfileModule/ProfileModule.cs +++ b/src/Web/Server/Modules/ProfileModule/ProfileModule.cs @@ -4,6 +4,7 @@ using XClaim.Common.Dtos; using XClaim.Common.Enums; using XClaim.Common.Wrappers; +using XClaim.Web.Server.Helpers; using XClaim.Web.Server.Modules.UserModule; namespace XClaim.Web.Server.Modules.ProfileModule; @@ -19,44 +20,19 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { var url = $"{Constants.RootApi}/{name.ToLower()}"; var group = endpoints.MapGroup(url).WithTags(name); - group.MapGet("/account", async (HttpRequest request, UserService user) => { - var userContext = request.HttpContext.User; - bool isAuth = userContext.Identity?.IsAuthenticated ?? false; - if (!isAuth) return TypedResults.Unauthorized(); + group.MapGet("/account", async (IdentityHelper identity, UserService user) => { + var authProfile = await identity.GetAuthProfile(); + if (!identity.IsAuthenticated) return TypedResults.Unauthorized(); - var auth = await request.HttpContext.AuthenticateAsync("Microsoft"); - var email = userContext.FindFirst(ClaimTypes.Email)?.Value ?? ""; - var fullName = userContext.FindFirst(ClaimTypes.Name)?.Value ?? ""; - var phone = userContext.FindFirst(ClaimTypes.HomePhone)?.Value ?? ""; - var names = fullName.Split(" "); - var token = auth?.Properties?.GetTokenValue("access_token"); - var expiry = (auth?.Properties?.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToDateTimeFromEpoch(); - var expireIn = (int)expiry.Subtract(DateTime.Now).TotalSeconds; - - UserResponse? profile = new UserResponse(); - var account = (await user.GetByEmailAsync(email)).Data; - if (account == null) { - profile.Email = email; - profile.FirstName = names[0]; - profile.LastName = names[^1]; - profile.Phone = phone; - } else { - profile = account; + var account = (await user.GetByIdentifierAsync(authProfile!.Data!.Identifier)).Data; + if (account != null) { + authProfile!.Data = account; + authProfile.Confirmed = true; } + var role = account?.Permission != null ? Enum.GetName(account.Permission)! : Enum.GetName(UserPermission.Standard)!; + authProfile.Role = role; - var role = account?.Permission != null ? - Enum.GetName(account.Permission)! : userContext.FindFirst(ClaimTypes.Role)?.Value ?? Enum.GetName(UserPermission.Standard)!; - - return Results.Ok(new Response(new AuthResponse { - Confirmed = account != null, - ExpiryTimeStamp = expiry, - ExpiresIn = expireIn, - Token = token, - Role = role, - Message = "Success", - Data = profile, - UserName = fullName - }) { Succeeded = expireIn > 0 }); + return Results.Ok(new Response(authProfile) { Succeeded = authProfile.ExpiresIn > 0 }); }).WithName("AccountProfile").WithOpenApi(); return group; diff --git a/src/Web/Server/Modules/UserModule/UserService.cs b/src/Web/Server/Modules/UserModule/UserService.cs index 2d4ca6e4..0dcdd2b4 100644 --- a/src/Web/Server/Modules/UserModule/UserService.cs +++ b/src/Web/Server/Modules/UserModule/UserService.cs @@ -7,11 +7,15 @@ using XClaim.Common.Wrappers; using XClaim.Web.Server.Data; using XClaim.Web.Server.Entities; +using XClaim.Web.Server.Helpers; namespace XClaim.Web.Server.Modules.UserModule; public sealed class UserService : GenericService, IUserService { - public UserService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } + private readonly IdentityHelper _identity; + public UserService(ServerContext ctx, IMapper mapper, ILogger logger, IdentityHelper identity) : base(ctx, mapper, logger) { + _identity = identity; + } public async Task> GetByEmailAsync(string email) { var item = await _ctx.Users .Where(x => x.DeletedAt == null) @@ -27,6 +31,22 @@ public UserService(ServerContext ctx, IMapper mapper, ILogger logge Succeeded = data != null }; } + + public async Task> GetByIdentifierAsync(string identifier) { + var item = await _ctx.Users + .Where(x => x.DeletedAt == null) + .Where(x => x.Identifier == identifier) + .Include(x => x.Company) + .Include(x => x.Team) + .Include(x => x.Currency) + .FirstOrDefaultAsync(); + var data = _mapper.Map(item); + + return new Response { + Data = data, + Succeeded = data != null + }; + } public async Task>> GetAllAsync(UserFilter responseFilter) { var result = new PagedResponse>(); @@ -81,6 +101,7 @@ public async Task>> GetAllAsync(UserFilter resp var response = new Response(); try { var item = _mapper.Map(value); + item.Identifier = _identity!.NameIdentifier!; var isAdmin = (await _ctx.Users.CountAsync(x => x.Permission == UserPermission.System)) < 1; if (isAdmin) item.Permission = UserPermission.System; await _ctx.Users.AddAsync(item); diff --git a/src/Web/Server/Program.cs b/src/Web/Server/Program.cs index b6a44011..a9b9b8d9 100644 --- a/src/Web/Server/Program.cs +++ b/src/Web/Server/Program.cs @@ -28,6 +28,7 @@ }); builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.Configure(options => { options.CheckConsentNeeded = _ => true; From 50d8691b8c76ca4ee8052fc8ca3bfdf9bfabce79 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sat, 28 Jan 2023 11:44:31 +0100 Subject: [PATCH 046/185] Implement user identity helper --- .../Server/Extensions/SessionExtensions.cs | 16 ++++ src/Web/Server/Helpers/IdentityHelper.cs | 78 +++++++++++++++++-- .../Server/Modules/UserModule/UserService.cs | 2 +- src/Web/Server/Program.cs | 4 +- 4 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 src/Web/Server/Extensions/SessionExtensions.cs diff --git a/src/Web/Server/Extensions/SessionExtensions.cs b/src/Web/Server/Extensions/SessionExtensions.cs new file mode 100644 index 00000000..7196b8e4 --- /dev/null +++ b/src/Web/Server/Extensions/SessionExtensions.cs @@ -0,0 +1,16 @@ +using System.Text.Json; + +namespace XClaim.Web.Server.Extensions; + +public static class SessionExtensions { + public static void Set(this ISession session, string key, T value) + { + session.SetString(key, JsonSerializer.Serialize(value)); + } + + public static T? Get(this ISession session, string key) + { + var value = session.GetString(key); + return value == null ? default : JsonSerializer.Deserialize(value); + } +} \ No newline at end of file diff --git a/src/Web/Server/Helpers/IdentityHelper.cs b/src/Web/Server/Helpers/IdentityHelper.cs index 05506f04..5bde796a 100644 --- a/src/Web/Server/Helpers/IdentityHelper.cs +++ b/src/Web/Server/Helpers/IdentityHelper.cs @@ -1,20 +1,28 @@ using System.Security.Claims; +using AutoMapper; using IdentityModel; using Microsoft.AspNetCore.Authentication; +using Microsoft.EntityFrameworkCore; using XClaim.Common.Dtos; using XClaim.Web.Server.Data; using XClaim.Web.Server.Entities; +using XClaim.Web.Server.Extensions; namespace XClaim.Web.Server.Helpers; public sealed class IdentityHelper { + + private const string UserKey = "identity-user-state"; + private const string ManagerKey = "identity-manager-state"; private readonly IHttpContextAccessor _contextAccessor; private readonly ServerContext _ctx; + private readonly IMapper _mapper; - public IdentityHelper(IHttpContextAccessor contextAccessor, ServerContext ctx) { + public IdentityHelper(IHttpContextAccessor contextAccessor, ServerContext ctx, IMapper mapper) { _contextAccessor = contextAccessor; _ctx = ctx; + _mapper = mapper; } private ClaimsPrincipal? Claim { @@ -64,13 +72,71 @@ public bool IsAuthenticated { }; } - public async Task GetUser() => default!; + private async Task GetByIdentifierAsync(string identifier) { + var query = _ctx.Users.Where(x => x.DeletedAt == null) + .Where(x => x.Identifier == identifier); + + return await this.GetUserEntity(query); + } - public async Task GetManager() => default!; + private async Task GetByIdAsync(Guid id) { + var query = _ctx.Users.Where(x => x.DeletedAt == null) + .Where(x => x.Id == id); + + return await this.GetUserEntity(query); + } - public async Task HasManager() => default!; + private async Task GetUserEntity (IQueryable queryable) { + var ctx = _contextAccessor!.HttpContext; + var cache = ctx!.Session.Get(UserKey); + if (cache != null) { + return cache; + } + + var query = await queryable.Include(x => x.Company) + .Include(x => x.Team) + .Include(x => x.Currency) + .FirstOrDefaultAsync(); + var result = _mapper.Map(query); + ctx!.Session.Set(UserKey, result); + + return result; + } + + public async Task GetUser() { + var id = this.NameIdentifier; + var response = await this.GetByIdentifierAsync(id!); + + return response; + } + + public async Task GetCompany() { + var user = await this.GetUser(); + + return user?.Company; + } + + public async Task GetTeam() { + var user = await this.GetUser(); + + return user?.Team; + } - public async Task GetCompany() => default!; + public async Task GetManager() { + var ctx = _contextAccessor!.HttpContext; + var cache = ctx!.Session.Get(ManagerKey); + if (cache != null) { + return cache; + } + + var team = await this.GetTeam(); + if (team!.ManagerId == null) return null; + Guid managerId = ((Guid)team!.ManagerId!); + var manager = await this.GetByIdAsync(managerId); + ctx!.Session.Set(ManagerKey, manager); + + return manager; + } - public async Task GetTeam() => default!; + public async Task HasManager() => await this.GetManager() != null; } \ No newline at end of file diff --git a/src/Web/Server/Modules/UserModule/UserService.cs b/src/Web/Server/Modules/UserModule/UserService.cs index 0dcdd2b4..6232f473 100644 --- a/src/Web/Server/Modules/UserModule/UserService.cs +++ b/src/Web/Server/Modules/UserModule/UserService.cs @@ -32,7 +32,7 @@ public UserService(ServerContext ctx, IMapper mapper, ILogger logge }; } - public async Task> GetByIdentifierAsync(string identifier) { + public async Task> GetByIdentifierAsync(string? identifier) { var item = await _ctx.Users .Where(x => x.DeletedAt == null) .Where(x => x.Identifier == identifier) diff --git a/src/Web/Server/Program.cs b/src/Web/Server/Program.cs index a9b9b8d9..61d84376 100644 --- a/src/Web/Server/Program.cs +++ b/src/Web/Server/Program.cs @@ -54,8 +54,8 @@ builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { - options.IdleTimeout = TimeSpan.FromDays(7); - options.Cookie.HttpOnly = true; + options.IdleTimeout = TimeSpan.FromMinutes(2); + options.Cookie.HttpOnly = false; options.Cookie.IsEssential = true; }); From 775de2c0022f2dc56521f66b2875744d4ba6a243 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sat, 28 Jan 2023 12:22:48 +0100 Subject: [PATCH 047/185] apply claim permission handler --- .../Modules/ClaimModule/ClaimService.cs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Web/Server/Modules/ClaimModule/ClaimService.cs b/src/Web/Server/Modules/ClaimModule/ClaimService.cs index 6d9b86f7..c1491120 100644 --- a/src/Web/Server/Modules/ClaimModule/ClaimService.cs +++ b/src/Web/Server/Modules/ClaimModule/ClaimService.cs @@ -2,22 +2,33 @@ using AutoFilterer.Types; using AutoMapper; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; using XClaim.Common.Dtos; using XClaim.Common.Helpers; using XClaim.Common.Wrappers; using XClaim.Web.Server.Data; using XClaim.Web.Server.Entities; +using XClaim.Web.Server.Helpers; namespace XClaim.Web.Server.Modules.ClaimModule; public sealed class ClaimService : GenericService, IClaimService { - public ClaimService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } + private readonly IdentityHelper _identity; + public ClaimService(ServerContext ctx, IMapper mapper, ILogger logger, IdentityHelper identity) : base(ctx, mapper, logger) { + _identity = identity; + } - new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { - var result = new PagedResponse>(); - var query = _ctx.Claims.Where(x => x.DeletedAt == null) + private async Task> ClaimPersonalQuery(IQueryable queryable) { + var userId = ((await _identity.GetUser())!).Id; + return queryable.Where(x => x.DeletedAt == null) + .Where(x => x.OwnerId == userId) .Include(x => x.Owner) .Include(x => x.Category); + } + + new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { + var result = new PagedResponse>(); + var query = await ClaimPersonalQuery(_ctx.Claims); try { var count = await query.CountAsync(); var data = await query.ApplyFilter(responseFilter).ToListAsync(); @@ -29,8 +40,7 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log result = new PagedResponse>(response, count, filter) { Succeeded = true }; - } - catch (Exception e) { + } catch (Exception e) { result.Errors = new[] { e.ToString() }; _logger.LogError(e.ToString()); } @@ -41,15 +51,12 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log new public async Task> GetByIdAsync(Guid id) { var response = new Response(); try { - var item = await _ctx.Claims.Where(x => x.Id == id) - .Include(x => x.Owner) - .Include(x => x.Category) - .FirstOrDefaultAsync(); + var item = await (await ClaimPersonalQuery(_ctx.Claims)) + .Where(x => x.Id == id).FirstOrDefaultAsync(); var data = _mapper.Map(item); response.Data = data; response.Succeeded = data != null; - } - catch (Exception e) { + } catch (Exception e) { response.Errors = new[] { e.ToString() }; _logger.LogError(e.ToString()); } From 0a3abc7365bd14457ab1785206eb9659d84772aa Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Sat, 28 Jan 2023 12:44:56 +0100 Subject: [PATCH 048/185] fix getById error --- src/Web/Server/Modules/ClaimModule/ClaimService.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Web/Server/Modules/ClaimModule/ClaimService.cs b/src/Web/Server/Modules/ClaimModule/ClaimService.cs index c1491120..0e241777 100644 --- a/src/Web/Server/Modules/ClaimModule/ClaimService.cs +++ b/src/Web/Server/Modules/ClaimModule/ClaimService.cs @@ -18,17 +18,16 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log _identity = identity; } - private async Task> ClaimPersonalQuery(IQueryable queryable) { - var userId = ((await _identity.GetUser())!).Id; - return queryable.Where(x => x.DeletedAt == null) - .Where(x => x.OwnerId == userId) + private static Task> ClaimPersonalQuery(IQueryable queryable) { + return Task.FromResult(queryable.Where(x => x.DeletedAt == null) .Include(x => x.Owner) - .Include(x => x.Category); + .Include(x => x.Category)); } new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { + var userId = ((await _identity.GetUser())!).Id; var result = new PagedResponse>(); - var query = await ClaimPersonalQuery(_ctx.Claims); + var query = (await ClaimPersonalQuery(_ctx.Claims)).Where(x => x.OwnerId == userId); try { var count = await query.CountAsync(); var data = await query.ApplyFilter(responseFilter).ToListAsync(); From 1583aea566b775e6cd3c23560d5faec5e5754b3f Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Tue, 31 Jan 2023 13:58:23 +0100 Subject: [PATCH 049/185] Discard redundant package from common --- src/Common/XClaim.Common.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Common/XClaim.Common.csproj b/src/Common/XClaim.Common.csproj index 32999600..60f11f07 100644 --- a/src/Common/XClaim.Common.csproj +++ b/src/Common/XClaim.Common.csproj @@ -7,7 +7,6 @@ - From eb5fac236f75bd79501d33de77d21e2ef5503806 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Tue, 31 Jan 2023 14:08:48 +0100 Subject: [PATCH 050/185] Updated payment type and implemented gatAll and getById endpoints --- src/Common/Dtos/PaymentResponse.cs | 16 +++-- src/Web/Components/Pages/Payments/Index.razor | 4 +- src/Web/Server/Entities/PaymentEntity.cs | 12 ++-- .../Modules/PaymentModule/PaymentModule.cs | 2 +- .../Modules/PaymentModule/PaymentService.cs | 63 ++++++++++++++++++- 5 files changed, 79 insertions(+), 18 deletions(-) diff --git a/src/Common/Dtos/PaymentResponse.cs b/src/Common/Dtos/PaymentResponse.cs index 3b593d6c..447a73b7 100644 --- a/src/Common/Dtos/PaymentResponse.cs +++ b/src/Common/Dtos/PaymentResponse.cs @@ -4,20 +4,18 @@ namespace XClaim.Common.Dtos; public class PaymentResponse : BaseResponse { public string Description { get; set; } = string.Empty; - public decimal Amount { get; set; } + public string Notes { get; set; } = string.Empty; public UserResponse? Owner { get; set; } public Guid? OwnerId { get; set; } - public DateTime? CompletedAt { get; set; } - - public UserResponse? CompletedBy { get; set; } - - public bool Completed { + public DateTime? ConfirmedAt { get; set; } + public UserResponse? ConfirmedBy { get; set; } + public Guid? ConfirmedById { get; set; } + public bool Confirmed { get { - return CompletedAt != null; + return ConfirmedAt != null; } } - - public string Notes { get; set; } = string.Empty; + public int Count { get; set; } public ICollection Claims { get; set; } = default!; } \ No newline at end of file diff --git a/src/Web/Components/Pages/Payments/Index.razor b/src/Web/Components/Pages/Payments/Index.razor index 99fa9e45..7388b255 100644 --- a/src/Web/Components/Pages/Payments/Index.razor +++ b/src/Web/Components/Pages/Payments/Index.razor @@ -55,8 +55,8 @@ - - + + 1 diff --git a/src/Web/Server/Entities/PaymentEntity.cs b/src/Web/Server/Entities/PaymentEntity.cs index 49db6422..8dc89f3f 100644 --- a/src/Web/Server/Entities/PaymentEntity.cs +++ b/src/Web/Server/Entities/PaymentEntity.cs @@ -12,14 +12,16 @@ public sealed class PaymentEntity : BaseEntity { [Required] public UserEntity? Owner { get; set; } public Guid? OwnerId { get; set; } - public DateTime? CompletedAt { get; set; } - public UserEntity? CompletedBy { get; set; } - public bool Completed { + public DateTime? ConfirmedAt { get; set; } + public UserEntity? ConfirmedBy { get; set; } + public Guid? ConfirmedById { get; set; } + public bool Confirmed { get { - return CompletedAt != null; + return ConfirmedAt != null; } } - public Guid? CompletedById { get; set; } + public int Count { get; set; } + public ICollection Claims { get; set; } = default!; public ICollection Files { get; set; } = default!; public ICollection Comments { get; set; } = default!; } \ No newline at end of file diff --git a/src/Web/Server/Modules/PaymentModule/PaymentModule.cs b/src/Web/Server/Modules/PaymentModule/PaymentModule.cs index f3e31b38..ef04bfd6 100644 --- a/src/Web/Server/Modules/PaymentModule/PaymentModule.cs +++ b/src/Web/Server/Modules/PaymentModule/PaymentModule.cs @@ -26,7 +26,7 @@ await sv.GetAllAsync(filter)) }).WithName($"Get{name}ById").WithOpenApi(); group.MapPost("/confirmation", async (PaymentResponse value, PaymentService sv) => { - value.CompletedAt = DateTime.Now; + value.ConfirmedAt = DateTime.Now; var result = await sv.UpdateAsync(value); return !result.Succeeded ? Results.NotFound(result) : TypedResults.Ok(result); }).WithName($"Confirm{name}").WithOpenApi(); diff --git a/src/Web/Server/Modules/PaymentModule/PaymentService.cs b/src/Web/Server/Modules/PaymentModule/PaymentService.cs index 6a0a4fe1..a1142180 100644 --- a/src/Web/Server/Modules/PaymentModule/PaymentService.cs +++ b/src/Web/Server/Modules/PaymentModule/PaymentService.cs @@ -1,10 +1,71 @@ +using AutoFilterer.Extensions; +using AutoFilterer.Types; using AutoMapper; +using Microsoft.EntityFrameworkCore; using XClaim.Common.Dtos; +using XClaim.Common.Helpers; +using XClaim.Common.Wrappers; using XClaim.Web.Server.Data; using XClaim.Web.Server.Entities; +using XClaim.Web.Server.Helpers; namespace XClaim.Web.Server.Modules.PaymentModule; public sealed class PaymentService : GenericService { - public PaymentService(ServerContext ctx, IMapper mapper, ILogger logger) : base(ctx, mapper, logger) { } + + private readonly IdentityHelper _identity; + + public PaymentService(ServerContext ctx, IMapper mapper, ILogger logger, IdentityHelper identity) : base(ctx, mapper, logger) { + _identity = identity; + } + + new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { + var id = ((await _identity.GetUser())!).Id; + var result = new PagedResponse>(); + var query = _ctx.Payments + .Where(x => x.DeletedAt == null) + .Where(x => x.OwnerId == id) + .Include(x => x.ConfirmedBy); + try { + var count = await query.CountAsync(); + var data = await query.ApplyFilter(responseFilter).ToListAsync(); + var response = _mapper.Map>(data); + var filter = new PaginationFilter { + Page = responseFilter.Page, + PerPage = responseFilter.PerPage + }; + result = new PagedResponse>(response, count, filter) { + Succeeded = true + }; + } catch (Exception e) { + result.Errors = new[] { e.ToString() }; + _logger.LogError(e.ToString()); + } + + return result; + } + + new public async Task> GetByIdAsync(Guid id) { + var response = new Response(); + try { + var item = await _ctx.Payments.Where(x => x.Id == id) + .Include(x => x.ConfirmedBy) + .Include(x => x.Files) + .Include(x => x.Claims) + .FirstOrDefaultAsync(); + var data = _mapper.Map(item); + response.Data = data; + response.Succeeded = data != null; + } + catch (Exception e) { + response.Errors = new[] { e.ToString() }; + _logger.LogError(e.ToString()); + } + + return response; + } + + public async Task>> GetPaymentsAsync(PaginationFilterBase responseFilter) => default!; + + public async Task> CompleteAsync(Guid id) => default!; } \ No newline at end of file From d4630d150117c94e36b57470b88f56370c1e8991 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Tue, 31 Jan 2023 14:11:02 +0100 Subject: [PATCH 051/185] MInor improvements to claims service --- src/Web/Server/Modules/ClaimModule/ClaimService.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Web/Server/Modules/ClaimModule/ClaimService.cs b/src/Web/Server/Modules/ClaimModule/ClaimService.cs index 0e241777..3a41c0f4 100644 --- a/src/Web/Server/Modules/ClaimModule/ClaimService.cs +++ b/src/Web/Server/Modules/ClaimModule/ClaimService.cs @@ -25,9 +25,10 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log } new public async Task>> GetAllAsync(PaginationFilterBase responseFilter) { - var userId = ((await _identity.GetUser())!).Id; + var id = ((await _identity.GetUser())!).Id; var result = new PagedResponse>(); - var query = (await ClaimPersonalQuery(_ctx.Claims)).Where(x => x.OwnerId == userId); + var query = (await ClaimPersonalQuery(_ctx.Claims)) + .Where(x => x.OwnerId == id); try { var count = await query.CountAsync(); var data = await query.ApplyFilter(responseFilter).ToListAsync(); @@ -51,7 +52,10 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log var response = new Response(); try { var item = await (await ClaimPersonalQuery(_ctx.Claims)) - .Where(x => x.Id == id).FirstOrDefaultAsync(); + .Where(x => x.Id == id) + .Include(x => x.Payment) + .Include(x => x.Files) + .FirstOrDefaultAsync(); var data = _mapper.Map(item); response.Data = data; response.Succeeded = data != null; @@ -62,4 +66,8 @@ public ClaimService(ServerContext ctx, IMapper mapper, ILogger log return response; } + + public async Task>> GetReviewsAsync(PaginationFilterBase responseFilter) => default!; + + public async Task> ReviewAsync(Guid id) => default!; } \ No newline at end of file From a34a77a61da3c5ef91a1908b648b1edbb3439d52 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Wed, 1 Feb 2023 05:07:22 +0100 Subject: [PATCH 052/185] extended balzor navigation and added back nav --- .../Extensions/ComponentServiceExtensions.cs | 1 + src/Web/Components/Navigation.cs | 56 +++++++++++++++++++ .../Components/Pages/User/BankAccount.razor | 4 +- src/Web/Components/Pages/User/Profile.razor | 4 +- 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/Web/Components/Navigation.cs diff --git a/src/Web/Components/Extensions/ComponentServiceExtensions.cs b/src/Web/Components/Extensions/ComponentServiceExtensions.cs index dfc947ca..30748e4d 100644 --- a/src/Web/Components/Extensions/ComponentServiceExtensions.cs +++ b/src/Web/Components/Extensions/ComponentServiceExtensions.cs @@ -4,6 +4,7 @@ namespace XClaim.Web.Components.Extensions; public static class ComponentServiceExtensions { public static IServiceCollection UseComponentsExtensions(this IServiceCollection services) { + services.AddSingleton(); return services; } diff --git a/src/Web/Components/Navigation.cs b/src/Web/Components/Navigation.cs new file mode 100644 index 00000000..24ccd3df --- /dev/null +++ b/src/Web/Components/Navigation.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Routing; + +namespace XClaim.Web.Components; + +public class Navigation : IDisposable { + private const int MinHistorySize = 256; + private const int AdditionalHistorySize = 64; + private readonly NavigationManager _navigationManager; + private readonly List _history; + + public Navigation(NavigationManager navigationManager) { + _navigationManager = navigationManager; + _history = new List(MinHistorySize + AdditionalHistorySize) { + _navigationManager.Uri + }; + _navigationManager.LocationChanged += OnLocationChanged!; + } + + /// + /// Navigates to the specified url. + /// + /// The destination url (relative or absolute). + public void NavigateTo(string url) { + _navigationManager.NavigateTo(url); + } + + /// + /// Returns true if it is possible to navigate to the previous url. + /// + public bool CanNavigateBack => _history.Count >= 2; + + /// + /// Navigates to the previous url if possible or does nothing if it is not. + /// + public void NavigateBack() { + if (!CanNavigateBack) return; + var backPageUrl = _history[^2]; + _history.RemoveRange(_history.Count - 2, 2); + _navigationManager.NavigateTo(backPageUrl); + } + + private void OnLocationChanged(object sender, LocationChangedEventArgs e) { + EnsureSize(); + _history.Add(e.Location); + } + + private void EnsureSize() { + if (_history.Count < MinHistorySize + AdditionalHistorySize) return; + _history.RemoveRange(0, _history.Count - MinHistorySize); + } + + public void Dispose() { + _navigationManager.LocationChanged -= OnLocationChanged!; + } +} diff --git a/src/Web/Components/Pages/User/BankAccount.razor b/src/Web/Components/Pages/User/BankAccount.razor index 161cfaf9..3b4e674b 100644 --- a/src/Web/Components/Pages/User/BankAccount.razor +++ b/src/Web/Components/Pages/User/BankAccount.razor @@ -1,4 +1,4 @@ -@inject NavigationManager Nav +@inject Navigation Nav @page "/app/user/bank-account" @attribute [Authorize] @@ -26,7 +26,7 @@ - Back Save diff --git a/src/Web/Components/Pages/User/Profile.razor b/src/Web/Components/Pages/User/Profile.razor index 5e2d9ca8..c9820830 100644 --- a/src/Web/Components/Pages/User/Profile.razor +++ b/src/Web/Components/Pages/User/Profile.razor @@ -3,7 +3,7 @@ @using XClaim.Common.Helpers @inject IUserService Http @inject ICurrencyService CurrencyService -@inject NavigationManager Nav +@inject Navigation Nav @inject ISnackbar Snackbar @attribute [Authorize] @@ -69,7 +69,7 @@ - Back Save From c207a439bb304ea477edc6b1c21f642937f14ffa Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Wed, 1 Feb 2023 05:08:37 +0100 Subject: [PATCH 053/185] remove blazor extensions --- src/Common/Extensions/StringExtensions.cs | 8 ++++++++ src/Common/XClaim.Common.csproj | 1 + src/Web/Components/_Imports.razor | 2 -- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 src/Common/Extensions/StringExtensions.cs diff --git a/src/Common/Extensions/StringExtensions.cs b/src/Common/Extensions/StringExtensions.cs new file mode 100644 index 00000000..3f59bcb9 --- /dev/null +++ b/src/Common/Extensions/StringExtensions.cs @@ -0,0 +1,8 @@ +namespace XClaim.Common.Extensions; + +public static class StringExtensions { + public static string Truncate(this string? value, int length = 15) { + if (value == null) return string.Empty; + return value.Length <= length ? value : value[..length] + "..."; + } +} \ No newline at end of file diff --git a/src/Common/XClaim.Common.csproj b/src/Common/XClaim.Common.csproj index 60f11f07..184e87c2 100644 --- a/src/Common/XClaim.Common.csproj +++ b/src/Common/XClaim.Common.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Web/Components/_Imports.razor b/src/Web/Components/_Imports.razor index 1f1a5b8f..94057958 100644 --- a/src/Web/Components/_Imports.razor +++ b/src/Web/Components/_Imports.razor @@ -10,8 +10,6 @@ @using Microsoft.AspNetCore.Components.Authorization @using MudBlazor @using MudBlazor.Extensions -@using MudBlazor.Extensions.Components -@using MudBlazor.Extensions.Components.ObjectEdit @using XClaim.Web.Shared @using XClaim.Web.Shared.States @using XClaim.Web.Components.Layouts From d1023c391ab53e59eec5dd58443c457ff38f3ced Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Wed, 1 Feb 2023 05:09:01 +0100 Subject: [PATCH 054/185] Enable new registration by default --- src/Web/Server/Modules/UserModule/UserService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Web/Server/Modules/UserModule/UserService.cs b/src/Web/Server/Modules/UserModule/UserService.cs index 6232f473..07b8c618 100644 --- a/src/Web/Server/Modules/UserModule/UserService.cs +++ b/src/Web/Server/Modules/UserModule/UserService.cs @@ -102,6 +102,7 @@ public async Task>> GetAllAsync(UserFilter resp try { var item = _mapper.Map(value); item.Identifier = _identity!.NameIdentifier!; + item.Active = true; var isAdmin = (await _ctx.Users.CountAsync(x => x.Permission == UserPermission.System)) < 1; if (isAdmin) item.Permission = UserPermission.System; await _ctx.Users.AddAsync(item); From 965455ab1dc15d9ed14d3d324d26ed5477004dd3 Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Wed, 1 Feb 2023 05:09:31 +0100 Subject: [PATCH 055/185] mudblazor extensions removal --- src/Web/Shared/XClaim.Web.Shared.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Web/Shared/XClaim.Web.Shared.csproj b/src/Web/Shared/XClaim.Web.Shared.csproj index f9417ddd..01d5d4db 100644 --- a/src/Web/Shared/XClaim.Web.Shared.csproj +++ b/src/Web/Shared/XClaim.Web.Shared.csproj @@ -18,7 +18,6 @@ - - + From e2d61c7ee61ef6c3938112bcd46011fd250730eb Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Wed, 1 Feb 2023 05:09:40 +0100 Subject: [PATCH 056/185] Update DbInitializer.cs --- src/Web/Server/Data/DbInitializer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Web/Server/Data/DbInitializer.cs b/src/Web/Server/Data/DbInitializer.cs index 7ed09b60..ce3fb89b 100644 --- a/src/Web/Server/Data/DbInitializer.cs +++ b/src/Web/Server/Data/DbInitializer.cs @@ -64,8 +64,8 @@ public void Seed() { }; var users = new List { - new UserEntity { Id = Guid.NewGuid(), Identifier = (Guid.NewGuid()).ToLowerShorterString(), CreatedAt = time, FirstName = "John", LastName = "Doe", Email = "john.doe@tolaram.com", Phone = "+234012345567", TeamId = teams[0].Id, CompanyId = companies[0].Id }, - new UserEntity { Id = Guid.NewGuid(), Identifier = (Guid.NewGuid()).ToLowerShorterString(), CreatedAt = time, FirstName = "Jane", LastName = "Doe", Email = "jane.doe@tolaram.com", Phone = "+234022424553", TeamId = teams[1].Id, CompanyId = companies[1].Id } + new UserEntity { Id = Guid.NewGuid(), Identifier = Guid.NewGuid().ToLowerShorterString(), CreatedAt = time, FirstName = "John", LastName = "Doe", Email = "john.doe@tolaram.com", Phone = "+234012345567", TeamId = teams[0].Id, CompanyId = companies[0].Id }, + new UserEntity { Id = Guid.NewGuid(), Identifier = Guid.NewGuid().ToLowerShorterString(), CreatedAt = time, FirstName = "Jane", LastName = "Doe", Email = "jane.doe@tolaram.com", Phone = "+234022424553", TeamId = teams[1].Id, CompanyId = companies[1].Id } }; _modelBuilder.Entity().HasData(banks); From 9d21e7b40fd847bee862456055a63e178a50454c Mon Sep 17 00:00:00 2001 From: radioActive DROID Date: Wed, 1 Feb 2023 05:10:20 +0100 Subject: [PATCH 057/185] Updated mainlayout components --- src/Web/Components/Shared/AppBar.razor | 18 ------ src/Web/Components/Shared/NavMenu.razor | 84 +++++++++++++++++-------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/Web/Components/Shared/AppBar.razor b/src/Web/Components/Shared/AppBar.razor index 131158c4..78962188 100644 --- a/src/Web/Components/Shared/AppBar.razor +++ b/src/Web/Components/Shared/AppBar.razor @@ -1,7 +1,6 @@ @implements IDisposable @inject AppState AppState @inject ThemeState ThemeState -@inject AuthState AuthState @code { protected override void OnInitialized() { @@ -14,8 +13,6 @@ AppState.OnChange -= StateHasChanged; ThemeState.OnChange -= StateHasChanged; } - - async Task SignOut() => await AuthState.TriggerSignOut(); } @@ -27,19 +24,4 @@ } else { } - - - -
- - SA - -
-
- - Profile - Bank Act - Sign Out - -
\ No newline at end of file diff --git a/src/Web/Components/Shared/NavMenu.razor b/src/Web/Components/Shared/NavMenu.razor index d0c25461..11e24078 100644 --- a/src/Web/Components/Shared/NavMenu.razor +++ b/src/Web/Components/Shared/NavMenu.razor @@ -1,7 +1,13 @@ -@code { +@using XClaim.Common.Dtos +@using XClaim.Common.Extensions +@inject AuthState AuthState + +@code { [Parameter] public bool SideBarOpen { get; set; } = true; + private UserResponse? _profile; + record MenuLink(string Title, string Icon, string Path, List? Child = null); private List _links = new() { @@ -12,7 +18,8 @@ new MenuLink("Transactions", Icons.Material.Filled.SendTimeExtension, "/app/transactions") }; - private List _secondaryLinks = new() { + private List _secondaryLinks = new List { + new MenuLink("Users", Icons.Material.Filled.People, "/app/users"), new MenuLink("Settings", Icons.Material.Filled.Settings, "/app/settings/", new () { new MenuLink("Teams", Icons.Material.Filled.Groups, "/app/settings/teams"), @@ -22,26 +29,58 @@ new MenuLink("Domains", Icons.Material.Filled.Computer, "/app/settings/domains"), new MenuLink("Currency", Icons.Material.Filled.CurrencyExchange, "/app/settings/currency"), new MenuLink("Server", Icons.Material.Filled.SettingsApplications, "/app/settings/server") - }), - new MenuLink("Users", Icons.Material.Filled.People, "/app/users"), - new MenuLink("Help", Icons.Material.Filled.Help, "/app/help") + }) }; + + async Task SignOut() => await AuthState.TriggerSignOut(); + + protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + if(await AuthState.IsAuth()) + _profile = ((await AuthState.GetSession())!).Data; + } + + private string GetInitialsText(string?[] value) { + if (value.Length < 2) return "FL"; + var firstName = value[0]?.ToUpper(); + var lastName = value[^1]?.ToUpper(); + + if (firstName == null && lastName == null) return "FL"; + return firstName![..1] + lastName![..1]; + } } - - X - X-Claim - - - - @foreach (var link in _links) { - @link.Title - } - - -