diff --git a/PandaVerticalSlices.sln.DotSettings b/PandaVerticalSlices.sln.DotSettings deleted file mode 100644 index e8be5c3..0000000 --- a/PandaVerticalSlices.sln.DotSettings +++ /dev/null @@ -1,4 +0,0 @@ - - True - True - True \ No newline at end of file diff --git a/PandaWebApi.sln.DotSettings b/PandaWebApi.sln.DotSettings deleted file mode 100644 index e8be5c3..0000000 --- a/PandaWebApi.sln.DotSettings +++ /dev/null @@ -1,4 +0,0 @@ - - True - True - True \ No newline at end of file diff --git a/qodana.yaml b/qodana.yaml deleted file mode 100644 index f2bd515..0000000 --- a/qodana.yaml +++ /dev/null @@ -1,29 +0,0 @@ -#-------------------------------------------------------------------------------# -# Qodana analysis is configured by qodana.yaml file # -# https://www.jetbrains.com/help/qodana/qodana-yaml.html # -#-------------------------------------------------------------------------------# -version: "1.0" - -#Specify IDE code to run analysis without container (Applied in CI/CD pipeline) -ide: QDNET - -#Specify inspection profile for code analysis -profile: - name: qodana.starter - -#Enable inspections -#include: -# - name: - -#Disable inspections -#exclude: -# - name: -# paths: -# - - -#Execute shell command before Qodana execution (Applied in CI/CD pipeline) -#bootstrap: sh ./prepare-qodana.sh - -#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) -#plugins: -# - id: #(plugin id can be found at https://plugins.jetbrains.com) diff --git a/src/Pandatech.VerticalSlices/Infrastructure/DependencyInjection.cs b/src/Pandatech.VerticalSlices/Infrastructure/DependencyInjection.cs index 5374332..ed4a64c 100644 --- a/src/Pandatech.VerticalSlices/Infrastructure/DependencyInjection.cs +++ b/src/Pandatech.VerticalSlices/Infrastructure/DependencyInjection.cs @@ -1,6 +1,7 @@ using Pandatech.VerticalSlices.Infrastructure.Extensions; using Pandatech.VerticalSlices.Infrastructure.Repositories; using Pandatech.VerticalSlices.Infrastructure.Seed; +using Pandatech.VerticalSlices.Infrastructure.Seed.User; using Pandatech.VerticalSlices.SharedKernel.Extensions; namespace Pandatech.VerticalSlices.Infrastructure; diff --git a/src/Pandatech.VerticalSlices/Infrastructure/Seed/SeederExtension.cs b/src/Pandatech.VerticalSlices/Infrastructure/Seed/SeederExtension.cs deleted file mode 100644 index ea5db30..0000000 --- a/src/Pandatech.VerticalSlices/Infrastructure/Seed/SeederExtension.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Collections; -using Pandatech.Crypto; -using Pandatech.VerticalSlices.Domain.Entities; -using Pandatech.VerticalSlices.Domain.Enums; -using Pandatech.VerticalSlices.Infrastructure.Contexts; - -namespace Pandatech.VerticalSlices.Infrastructure.Seed; - -public static class SeederExtension -{ - public static WebApplication SeedSystemUser(this WebApplication app) - { - using var scope = app.Services.CreateScope(); - var services = scope.ServiceProvider; - var context = services.GetRequiredService(); - var configuration = services.GetRequiredService(); - var argon2Id = services.GetRequiredService(); - - var username = configuration["Security:SuperUser:Username"]; - ValidateConfiguration(username, "SuperUser:Username"); - - var normalizedUsername = username!.ToLowerInvariant(); - var existingUsers = context.Users - .Where(u => u.Username == normalizedUsername || u.Role == UserRole.SuperAdmin) - .ToList(); - - ValidateSuperUserUniqueness(existingUsers); - - if (existingUsers.Count == 1) - { - return app; - } - - var userPassword = configuration["Security:SuperUser:Password"]; - ValidateConfiguration(userPassword, "SuperUser:Password"); - - var passwordHash = argon2Id.HashPassword(userPassword!); - var currentTime = DateTime.UtcNow; - - var newUser = CreateNewUser(normalizedUsername, passwordHash, currentTime); - context.Users.Add(newUser); - context.SaveChanges(); - - return app; - } - - private static void ValidateConfiguration(string? configValue, string configName) - { - if (string.IsNullOrWhiteSpace(configValue)) - { - throw new ArgumentException($"{configName} is not set in appsettings.json"); - } - } - - private static void ValidateSuperUserUniqueness(ICollection users) - { - if (users.Count > 1) - { - throw new InvalidOperationException("There are multiple super users in the database."); - } - } - - private static UserEntity CreateNewUser(string username, byte[] passwordHash, DateTime currentTime) - { - return new UserEntity - { - FullName = "System", - PasswordHash = passwordHash, - Username = username, - Role = UserRole.SuperAdmin, - ForcePasswordChange = false, - Status = UserStatus.Active, - CreatedAt = currentTime, - UpdatedAt = currentTime, - Comment = "Seeded user, please do not delete" - }; - } -} \ No newline at end of file diff --git a/src/Pandatech.VerticalSlices/Infrastructure/Seed/User/SystemUser.cs b/src/Pandatech.VerticalSlices/Infrastructure/Seed/User/SystemUser.cs new file mode 100644 index 0000000..0258d3d --- /dev/null +++ b/src/Pandatech.VerticalSlices/Infrastructure/Seed/User/SystemUser.cs @@ -0,0 +1,74 @@ +using System.Collections; +using Pandatech.Crypto; +using Pandatech.VerticalSlices.Domain.Entities; +using Pandatech.VerticalSlices.Domain.Enums; +using Pandatech.VerticalSlices.Infrastructure.Contexts; + +namespace Pandatech.VerticalSlices.Infrastructure.Seed.User; + +public static class SystemUser +{ + public static WebApplication SeedSystemUser(this WebApplication app) + { + using var scope = app.Services.CreateScope(); + var services = scope.ServiceProvider; + var context = services.GetRequiredService(); + var configuration = services.GetRequiredService(); + var argon2Id = services.GetRequiredService(); + + var username = configuration["Security:SuperUser:Username"]; + ValidateConfiguration(username, "SuperUser:Username"); + + var normalizedUsername = username!.ToLowerInvariant(); + var existingUsers = context.Users + .Where(u => u.Username == normalizedUsername || u.Role == UserRole.SuperAdmin) + .ToList(); + + ValidateSuperUserUniqueness(existingUsers); + + if (existingUsers.Count == 1) + { + return app; + } + + var userPassword = configuration["Security:SuperUser:Password"]; + ValidateConfiguration(userPassword, "SuperUser:Password"); + + var passwordHash = argon2Id.HashPassword(userPassword!); + + var newUser = CreateNewUser(normalizedUsername, passwordHash); + context.Users.Add(newUser); + context.SaveChanges(); + + return app; + } + + private static void ValidateConfiguration(string? configValue, string configName) + { + if (string.IsNullOrWhiteSpace(configValue)) + { + throw new ArgumentException($"{configName} is not set in appsettings.json"); + } + } + + private static void ValidateSuperUserUniqueness(ICollection users) + { + if (users.Count > 1) + { + throw new InvalidOperationException("There are multiple super users in the database."); + } + } + + private static UserEntity CreateNewUser(string username, byte[] passwordHash) + { + return new UserEntity + { + FullName = "System", + PasswordHash = passwordHash, + Username = username, + Role = UserRole.SuperAdmin, + ForcePasswordChange = false, + Comment = "Seeded user, please do not delete" + }; + } +}