From 55bc8b4bcc90556da35a224fbf3b643ac8ac34a3 Mon Sep 17 00:00:00 2001 From: sadq Date: Mon, 19 Aug 2024 13:12:18 +0330 Subject: [PATCH 01/12] first attempt to singletonize the scoped classes --- RelationshipAnalysis/Controllers/AuthController.cs | 9 +++------ RelationshipAnalysis/Program.cs | 2 +- .../AuthServices/Abstraction/ILoginService.cs | 7 +++++-- .../Abstraction/AuthServices/LoginService.cs | 7 +++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/RelationshipAnalysis/Controllers/AuthController.cs b/RelationshipAnalysis/Controllers/AuthController.cs index e017df2..5e6de68 100644 --- a/RelationshipAnalysis/Controllers/AuthController.cs +++ b/RelationshipAnalysis/Controllers/AuthController.cs @@ -1,11 +1,8 @@ -using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; using RelationshipAnalysis.Context; using RelationshipAnalysis.Dto; using RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServices.Abstraction; -using RelationshipAnalysis.Settings.JWT; namespace RelationshipAnalysis.Controllers; @@ -21,9 +18,9 @@ public AuthController(ILoginService loginService) } [HttpPost] - public async Task Login([FromBody] LoginDto loginModel) + public async Task Login([FromBody] LoginDto loginModel, [FromServices] ApplicationDbContext context) { - var response = await _loginService.LoginAsync(loginModel, Response); + var response = await _loginService.LoginAsync(loginModel, Response, context); return StatusCode((int)response.StatusCode, response.Data); } diff --git a/RelationshipAnalysis/Program.cs b/RelationshipAnalysis/Program.cs index 2795e69..425f4e3 100644 --- a/RelationshipAnalysis/Program.cs +++ b/RelationshipAnalysis/Program.cs @@ -26,7 +26,7 @@ builder.Services.AddSingleton() .AddSingleton() - .AddScoped() + .AddSingleton() .AddScoped() .AddSingleton() .AddSingleton() diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs index 2aa6c15..4f16a63 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs @@ -1,8 +1,11 @@ -using RelationshipAnalysis.Dto; +using Microsoft.AspNetCore.Mvc; +using RelationshipAnalysis.Context; +using RelationshipAnalysis.Dto; namespace RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServices.Abstraction; public interface ILoginService { - Task> LoginAsync(LoginDto loginModel, HttpResponse response); + Task> LoginAsync(LoginDto loginModel, HttpResponse response, + [FromServices] ApplicationDbContext context); } \ No newline at end of file diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs index 9dac462..3962b35 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using RelationshipAnalysis.Context; using RelationshipAnalysis.Dto; using RelationshipAnalysis.Enums; @@ -7,16 +8,14 @@ namespace RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServices; public class LoginService( - ApplicationDbContext context, ICookieSetter cookieSetter, IJwtTokenGenerator jwtTokenGenerator, IPasswordVerifier passwordVerifier) : ILoginService { - public async Task> LoginAsync(LoginDto loginModel, HttpResponse response) + public async Task> LoginAsync(LoginDto loginModel, HttpResponse response, [FromServices] ApplicationDbContext context) { var result = new ActionResponse(); - var user = await context.Users .SingleOrDefaultAsync(u => u.Username == loginModel.Username); From 43298b4d78bcfe1637221f6b0c6f5beb09941c8a Mon Sep 17 00:00:00 2001 From: sadq Date: Mon, 19 Aug 2024 13:22:47 +0330 Subject: [PATCH 02/12] first commit --- .../InitialRecordsCreator.cs | 27 +++++++++++++++++++ RelationAnalysis.Migrations/Program.cs | 2 ++ RelationshipAnalysis/appsettings.json | 4 +++ 3 files changed, 33 insertions(+) create mode 100644 RelationAnalysis.Migrations/InitialRecordsCreator.cs diff --git a/RelationAnalysis.Migrations/InitialRecordsCreator.cs b/RelationAnalysis.Migrations/InitialRecordsCreator.cs new file mode 100644 index 0000000..289a3b8 --- /dev/null +++ b/RelationAnalysis.Migrations/InitialRecordsCreator.cs @@ -0,0 +1,27 @@ +using RelationshipAnalysis.Context; +using RelationshipAnalysis.Models.Auth; + +namespace RelationAnalysis.Migrations; + +public class InitialRecordsCreator +{ + public void AddInitialRecords(ApplicationDbContext context) + { + var roles = new List() + { + new Role() { Name = "Admin", Permissions = "[]" }, + new Role() { Name = "DataAdmin", Permissions = "[]" }, + new Role() { Name = "DataAnalyst", Permissions = "[]" } + }; + context.AddRangeAsync(roles); + context.AddAsync(new User() + { + Email = "admin@gmail.com", + FirstName = "FirstName", + LastName = "LastName", + PasswordHash = + + }) + context.SaveChanges(); + } +} \ No newline at end of file diff --git a/RelationAnalysis.Migrations/Program.cs b/RelationAnalysis.Migrations/Program.cs index 407d10a..d5ade68 100644 --- a/RelationAnalysis.Migrations/Program.cs +++ b/RelationAnalysis.Migrations/Program.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using DotNetEnv; using RelationshipAnalysis.Context; +using RelationshipAnalysis.Models.Auth; namespace RelationAnalysis.Migrations { @@ -18,6 +19,7 @@ static void Main(string[] args) using (var context = (ApplicationDbContext) webHost.Services.GetService(typeof(ApplicationDbContext))) { context.Database.Migrate(); + new InitialRecordsCreator().AddInitialRecords(context); } Console.WriteLine("Done"); } diff --git a/RelationshipAnalysis/appsettings.json b/RelationshipAnalysis/appsettings.json index caf3408..9b482a9 100644 --- a/RelationshipAnalysis/appsettings.json +++ b/RelationshipAnalysis/appsettings.json @@ -1,4 +1,8 @@ { + "PasswordHash": + { + "DefaultPassword" : "ADmin!@#" + }, "Jwt": { "CookieName" : "jwt", "Key": "kajbdiuhdqhpjQE89HBSDJIABFCIWSGF89GW3EJFBWEIUBCZNMXCJNLZDKNJKSNJKFBIGW3EASHHDUIASZGCUI", From 803eb632901b4303dc2568aa372e100eff6d21b9 Mon Sep 17 00:00:00 2001 From: sadq Date: Mon, 19 Aug 2024 13:35:14 +0330 Subject: [PATCH 03/12] add context lazy loading --- RelationshipAnalysis/Controllers/AuthController.cs | 4 ++-- .../Abstraction/AuthServices/Abstraction/ILoginService.cs | 3 +-- .../Abstraction/AuthServices/LoginService.cs | 5 ++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/RelationshipAnalysis/Controllers/AuthController.cs b/RelationshipAnalysis/Controllers/AuthController.cs index 5e6de68..1d5a3f7 100644 --- a/RelationshipAnalysis/Controllers/AuthController.cs +++ b/RelationshipAnalysis/Controllers/AuthController.cs @@ -18,9 +18,9 @@ public AuthController(ILoginService loginService) } [HttpPost] - public async Task Login([FromBody] LoginDto loginModel, [FromServices] ApplicationDbContext context) + public async Task Login([FromBody] LoginDto loginModel) { - var response = await _loginService.LoginAsync(loginModel, Response, context); + var response = await _loginService.LoginAsync(loginModel, Response); return StatusCode((int)response.StatusCode, response.Data); } diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs index 4f16a63..8c182b9 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/ILoginService.cs @@ -6,6 +6,5 @@ namespace RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServic public interface ILoginService { - Task> LoginAsync(LoginDto loginModel, HttpResponse response, - [FromServices] ApplicationDbContext context); + Task> LoginAsync(LoginDto loginModel, HttpResponse response); } \ No newline at end of file diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs index 3962b35..7cb788e 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/LoginService.cs @@ -8,14 +8,17 @@ namespace RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServices; public class LoginService( + IServiceProvider serviceProvider, ICookieSetter cookieSetter, IJwtTokenGenerator jwtTokenGenerator, IPasswordVerifier passwordVerifier) : ILoginService { - public async Task> LoginAsync(LoginDto loginModel, HttpResponse response, [FromServices] ApplicationDbContext context) + public async Task> LoginAsync(LoginDto loginModel, HttpResponse response) { var result = new ActionResponse(); + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var user = await context.Users .SingleOrDefaultAsync(u => u.Username == loginModel.Username); From 0b7afa6be92beb91d77490981c912ac0dbc19c1e Mon Sep 17 00:00:00 2001 From: sadq Date: Mon, 19 Aug 2024 13:41:11 +0330 Subject: [PATCH 04/12] add context container --- RelationshipAnalysis/Program.cs | 2 +- .../Services/AccessServices/PermissionService.cs | 4 +++- .../Services/AdminPanelServices/AllUserService.cs | 4 +++- .../DbContextServices/Abstraction/IDbContextServices.cs | 8 ++++++++ .../Services/DbContextServices/DbContextContainer.cs | 6 ++++++ 5 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs create mode 100644 RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs diff --git a/RelationshipAnalysis/Program.cs b/RelationshipAnalysis/Program.cs index 425f4e3..3b2f5f8 100644 --- a/RelationshipAnalysis/Program.cs +++ b/RelationshipAnalysis/Program.cs @@ -27,7 +27,7 @@ builder.Services.AddSingleton() .AddSingleton() .AddSingleton() - .AddScoped() + .AddSingleton() .AddSingleton() .AddSingleton() .AddScoped() diff --git a/RelationshipAnalysis/Services/AccessServices/PermissionService.cs b/RelationshipAnalysis/Services/AccessServices/PermissionService.cs index c7dcb0e..43b487b 100644 --- a/RelationshipAnalysis/Services/AccessServices/PermissionService.cs +++ b/RelationshipAnalysis/Services/AccessServices/PermissionService.cs @@ -7,7 +7,7 @@ namespace RelationshipAnalysis.Services.AccessServices; -public class PermissionService(ApplicationDbContext context) : IPermissionService +public class PermissionService(IServiceProvider serviceProvider) : IPermissionService { public async Task> GetPermissionsAsync(ClaimsPrincipal userClaims) { @@ -32,6 +32,8 @@ public async Task> GetPermissionsAsync(ClaimsPrinc foreach (var roleName in roleNames) { + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var role = await context.Roles .FirstOrDefaultAsync(r => r.Name == roleName); diff --git a/RelationshipAnalysis/Services/AdminPanelServices/AllUserService.cs b/RelationshipAnalysis/Services/AdminPanelServices/AllUserService.cs index b1e099b..acdf0f9 100644 --- a/RelationshipAnalysis/Services/AdminPanelServices/AllUserService.cs +++ b/RelationshipAnalysis/Services/AdminPanelServices/AllUserService.cs @@ -8,10 +8,12 @@ namespace RelationshipAnalysis.Services.AdminPanelServices; -public class AllUserService(ApplicationDbContext context, IMapper mapper, IRoleReceiver rolesReceiver) : IAllUserService +public class AllUserService(IServiceProvider serviceProvider, IMapper mapper, IRoleReceiver rolesReceiver) : IAllUserService { public int ReceiveAllUserCount() { + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var users = context.Users.ToList(); return users.Count; } diff --git a/RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs b/RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs new file mode 100644 index 0000000..ea228c1 --- /dev/null +++ b/RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs @@ -0,0 +1,8 @@ +using RelationshipAnalysis.Context; + +namespace RelationshipAnalysis.Services.Abstraction; + +public interface IDbContextServices +{ + ApplicationDbContext GetContext(); +} \ No newline at end of file diff --git a/RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs b/RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs new file mode 100644 index 0000000..209d7f5 --- /dev/null +++ b/RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs @@ -0,0 +1,6 @@ +namespace RelationshipAnalysis.Services; + +public class DbContextContainer +{ + +} \ No newline at end of file From 1cede183f4034fd885b90f3199bce6d7df85df1d Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 19 Aug 2024 13:57:15 +0330 Subject: [PATCH 05/12] Add initial data. --- RelationAnalysis.Migrations/.env.example | 1 - RelationAnalysis.Migrations/ConsoleStartup.cs | 4 +- .../InitialRecordsCreator.cs | 55 +++++++++++++++---- .../RelationAnalysis.Migrations.csproj | 8 +++ RelationAnalysis.Migrations/appsettings.json | 3 + RelationshipAnalysis/appsettings.json | 2 +- 6 files changed, 56 insertions(+), 17 deletions(-) delete mode 100644 RelationAnalysis.Migrations/.env.example create mode 100644 RelationAnalysis.Migrations/appsettings.json diff --git a/RelationAnalysis.Migrations/.env.example b/RelationAnalysis.Migrations/.env.example deleted file mode 100644 index 31edd6e..0000000 --- a/RelationAnalysis.Migrations/.env.example +++ /dev/null @@ -1 +0,0 @@ -CONNECTION_STRING="" \ No newline at end of file diff --git a/RelationAnalysis.Migrations/ConsoleStartup.cs b/RelationAnalysis.Migrations/ConsoleStartup.cs index 01aa7b2..163dab2 100644 --- a/RelationAnalysis.Migrations/ConsoleStartup.cs +++ b/RelationAnalysis.Migrations/ConsoleStartup.cs @@ -1,5 +1,3 @@ -using DotNetEnv; -using DotNetEnv.Configuration; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -11,7 +9,7 @@ namespace RelationAnalysis.Migrations { public class ConsoleStartup { - public IConfiguration Configuration { get; } = new ConfigurationBuilder() + private IConfiguration Configuration { get; } = new ConfigurationBuilder() .AddEnvironmentVariables() .Build(); public ConsoleStartup() diff --git a/RelationAnalysis.Migrations/InitialRecordsCreator.cs b/RelationAnalysis.Migrations/InitialRecordsCreator.cs index 289a3b8..31191a6 100644 --- a/RelationAnalysis.Migrations/InitialRecordsCreator.cs +++ b/RelationAnalysis.Migrations/InitialRecordsCreator.cs @@ -1,27 +1,58 @@ using RelationshipAnalysis.Context; using RelationshipAnalysis.Models.Auth; +using Microsoft.Extensions.Configuration; namespace RelationAnalysis.Migrations; public class InitialRecordsCreator { + private IConfiguration Configuration { get; } = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile("appsettings.json") + .Build(); + public void AddInitialRecords(ApplicationDbContext context) { var roles = new List() { - new Role() { Name = "Admin", Permissions = "[]" }, - new Role() { Name = "DataAdmin", Permissions = "[]" }, - new Role() { Name = "DataAnalyst", Permissions = "[]" } + new Role() { Name = "Admin", Permissions = "[]", Id = 1 }, + new Role() { Name = "DataAdmin", Permissions = "[]", Id = 2 }, + new Role() { Name = "DataAnalyst", Permissions = "[]", Id = 3 } }; - context.AddRangeAsync(roles); - context.AddAsync(new User() + var userRoles = new List() + { + new UserRole() + { + UserId = 1, + RoleId = 1 + }, + new UserRole() + { + UserId = 1, + RoleId = 2 + }, + new UserRole() + { + UserId = 1, + RoleId = 3 + } + }; + var users = new List() { - Email = "admin@gmail.com", - FirstName = "FirstName", - LastName = "LastName", - PasswordHash = - - }) - context.SaveChanges(); + new User() + { + Username = "admin", + PasswordHash = Configuration["admin"], + FirstName = "FirstName", + LastName = "LastName", + Email = "admin@gmail.com", + Id = 1, + } + }; + + context.AddRangeAsync(roles); + context.AddRangeAsync(users); + context.AddRangeAsync(userRoles); + context.SaveChangesAsync(); } } \ No newline at end of file diff --git a/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj b/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj index 6e764ba..cb5d663 100644 --- a/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj +++ b/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj @@ -25,4 +25,12 @@ + + + true + PreserveNewest + PreserveNewest + + + diff --git a/RelationAnalysis.Migrations/appsettings.json b/RelationAnalysis.Migrations/appsettings.json new file mode 100644 index 0000000..de69dbe --- /dev/null +++ b/RelationAnalysis.Migrations/appsettings.json @@ -0,0 +1,3 @@ +{ + "DefaultPassword" : "admin" +} diff --git a/RelationshipAnalysis/appsettings.json b/RelationshipAnalysis/appsettings.json index 9b482a9..cbc7eab 100644 --- a/RelationshipAnalysis/appsettings.json +++ b/RelationshipAnalysis/appsettings.json @@ -1,7 +1,7 @@ { "PasswordHash": { - "DefaultPassword" : "ADmin!@#" + "DefaultPassword" : "admin" }, "Jwt": { "CookieName" : "jwt", From 05cd268d8bb9dd20a13c0a1660113b9edbe7b11d Mon Sep 17 00:00:00 2001 From: sadq Date: Mon, 19 Aug 2024 14:46:37 +0330 Subject: [PATCH 06/12] converted all the scoped classes to singleton classes --- RelationshipAnalysis/Program.cs | 20 +++++++++---------- .../AdminPanelServices/RoleReceiver.cs | 7 ++++++- .../AdminPanelServices/UserCreateService.cs | 12 ++++++++++- .../AdminPanelServices/UserDeleteService.cs | 4 +++- .../UserUpdateRolesService.cs | 10 +++++++++- .../Abstraction/IDbContextServices.cs | 8 -------- .../DbContextServices/DbContextContainer.cs | 6 ------ .../UserPanelServices/UserPasswordService.cs | 5 ++++- .../UserPanelServices/UserReceiver.cs | 10 +++++++++- .../UserUpdateInfoService.cs | 10 +++++++++- 10 files changed, 60 insertions(+), 32 deletions(-) delete mode 100644 RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs delete mode 100644 RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs diff --git a/RelationshipAnalysis/Program.cs b/RelationshipAnalysis/Program.cs index 3b2f5f8..c9dba1c 100644 --- a/RelationshipAnalysis/Program.cs +++ b/RelationshipAnalysis/Program.cs @@ -29,19 +29,17 @@ .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() .AddSingleton() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped() - .AddSingleton() - .AddScoped() + .AddSingleton() .AddSingleton() - .AddScoped() - .AddScoped() - .AddScoped(); + .AddSingleton() + .AddSingleton(); builder.Services.Configure(builder.Configuration.GetSection("Jwt")); diff --git a/RelationshipAnalysis/Services/AdminPanelServices/RoleReceiver.cs b/RelationshipAnalysis/Services/AdminPanelServices/RoleReceiver.cs index 64d33a4..f133396 100644 --- a/RelationshipAnalysis/Services/AdminPanelServices/RoleReceiver.cs +++ b/RelationshipAnalysis/Services/AdminPanelServices/RoleReceiver.cs @@ -3,16 +3,21 @@ namespace RelationshipAnalysis.Services.AdminPanelServices; -public class RoleReceiver(ApplicationDbContext context) : IRoleReceiver +public class RoleReceiver(IServiceProvider serviceProvider) : IRoleReceiver { public List ReceiveRoles(int userId) { + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); return context.UserRoles.ToList().FindAll(ur => ur.UserId == userId) .Select(ur => ur.Role.Name).ToList(); } public List ReceiveAllRoles() { + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); return context.Roles.Select(x => x.Name).ToList(); } } \ No newline at end of file diff --git a/RelationshipAnalysis/Services/AdminPanelServices/UserCreateService.cs b/RelationshipAnalysis/Services/AdminPanelServices/UserCreateService.cs index 9db5d17..0027272 100644 --- a/RelationshipAnalysis/Services/AdminPanelServices/UserCreateService.cs +++ b/RelationshipAnalysis/Services/AdminPanelServices/UserCreateService.cs @@ -9,10 +9,13 @@ namespace RelationshipAnalysis.Services.AdminPanelServices; -public class UserCreateService(ApplicationDbContext context, IPasswordHasher passwordHasher) : IUserCreateService +public class UserCreateService(IServiceProvider serviceProvider, IPasswordHasher passwordHasher) : IUserCreateService { public async Task> CreateUser(CreateUserDto createUserDto) { + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var isUserExist = context.Users.Select(x => x.Username).ToList().Contains(createUserDto.Username); if (isUserExist) { @@ -56,8 +59,12 @@ private ActionResponse SuccessResult() private async Task AddUserRoles(CreateUserDto createUserDto, User user) { var roles = new List(); + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); foreach (var roleName in createUserDto.Roles) { + var role = await context.Roles .SingleOrDefaultAsync(r => r.Name == roleName); @@ -87,6 +94,9 @@ private async Task AddUser(CreateUserDto createUserDto) FirstName = createUserDto.FirstName, LastName = createUserDto.LastName, }; + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); await context.AddAsync(user); await context.SaveChangesAsync(); return user; diff --git a/RelationshipAnalysis/Services/AdminPanelServices/UserDeleteService.cs b/RelationshipAnalysis/Services/AdminPanelServices/UserDeleteService.cs index f7470f6..e4de951 100644 --- a/RelationshipAnalysis/Services/AdminPanelServices/UserDeleteService.cs +++ b/RelationshipAnalysis/Services/AdminPanelServices/UserDeleteService.cs @@ -6,7 +6,7 @@ namespace RelationshipAnalysis.Services.AdminPanelServices; -public class UserDeleteService(ApplicationDbContext context) : IUserDeleteService +public class UserDeleteService(IServiceProvider serviceProvider) : IUserDeleteService { public async Task> DeleteUser(User user) { @@ -15,6 +15,8 @@ public async Task> DeleteUser(User user) return NotFoundResult(); } + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); context.Remove(user); await context.SaveChangesAsync(); return SuccessResult(); diff --git a/RelationshipAnalysis/Services/AdminPanelServices/UserUpdateRolesService.cs b/RelationshipAnalysis/Services/AdminPanelServices/UserUpdateRolesService.cs index 309636c..19aebc4 100644 --- a/RelationshipAnalysis/Services/AdminPanelServices/UserUpdateRolesService.cs +++ b/RelationshipAnalysis/Services/AdminPanelServices/UserUpdateRolesService.cs @@ -8,7 +8,7 @@ namespace RelationshipAnalysis.Services.AdminPanelServices; -public class UserUpdateRolesService(ApplicationDbContext context) : IUserUpdateRolesService +public class UserUpdateRolesService(IServiceProvider serviceProvider) : IUserUpdateRolesService { public async Task> UpdateUserRolesAsync(User user, List newRoles) { @@ -17,6 +17,8 @@ public async Task> UpdateUserRolesAsync(User user, Li return BadRequestResult(Resources.EmptyRolesMessage); } + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var invalidRoles = newRoles.FindAll(r => !context.Roles.Select(R => R.Name) .Contains(r)); if (invalidRoles.Any()) @@ -32,6 +34,9 @@ public async Task> UpdateUserRolesAsync(User user, Li private async Task RemoveUserRoles(User user) { + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var userRoles = context.UserRoles.ToList().FindAll(r => r.UserId == user.Id); context.RemoveRange(userRoles); await context.SaveChangesAsync(); @@ -48,6 +53,9 @@ private ActionResponse SuccessResult() private async Task AddUserRoles(List newRoles, User user) { + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var roles = newRoles.Select(r => context.Roles .SingleOrDefaultAsync(R => R.Name == r)); roles.ToList().ForEach(r => context.UserRoles.Add(new UserRole() diff --git a/RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs b/RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs deleted file mode 100644 index ea228c1..0000000 --- a/RelationshipAnalysis/Services/DbContextServices/Abstraction/IDbContextServices.cs +++ /dev/null @@ -1,8 +0,0 @@ -using RelationshipAnalysis.Context; - -namespace RelationshipAnalysis.Services.Abstraction; - -public interface IDbContextServices -{ - ApplicationDbContext GetContext(); -} \ No newline at end of file diff --git a/RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs b/RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs deleted file mode 100644 index 209d7f5..0000000 --- a/RelationshipAnalysis/Services/DbContextServices/DbContextContainer.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace RelationshipAnalysis.Services; - -public class DbContextContainer -{ - -} \ No newline at end of file diff --git a/RelationshipAnalysis/Services/UserPanelServices/UserPasswordService.cs b/RelationshipAnalysis/Services/UserPanelServices/UserPasswordService.cs index d4360d6..a689055 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/UserPasswordService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/UserPasswordService.cs @@ -7,7 +7,7 @@ namespace RelationshipAnalysis.Services.UserPanelServices; -public class UserPasswordService(ApplicationDbContext context, IPasswordVerifier passwordVerifier, IPasswordHasher passwordHasher) : IUserPasswordService +public class UserPasswordService(IServiceProvider serviceProvider, IPasswordVerifier passwordVerifier, IPasswordHasher passwordHasher) : IUserPasswordService { public async Task> UpdatePasswordAsync(User user, UserPasswordInfoDto passwordInfoDto) { @@ -20,6 +20,9 @@ public async Task> UpdatePasswordAsync(User user, Use return WrongPasswordResult(); } user.PasswordHash = passwordHasher.HashPassword(passwordInfoDto.NewPassword); + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); context.Update(user); await context.SaveChangesAsync(); diff --git a/RelationshipAnalysis/Services/UserPanelServices/UserReceiver.cs b/RelationshipAnalysis/Services/UserPanelServices/UserReceiver.cs index 6f4791d..b34b152 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/UserReceiver.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/UserReceiver.cs @@ -6,23 +6,31 @@ namespace RelationshipAnalysis.Services.UserPanelServices; -public class UserReceiver(ApplicationDbContext context) : IUserReceiver +public class UserReceiver(IServiceProvider serviceProvider) : IUserReceiver { public async Task ReceiveUserAsync(ClaimsPrincipal userClaims) { var currentId = int.Parse(userClaims.FindFirst(ClaimTypes.NameIdentifier)?.Value); + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var user = await context.Users.SingleOrDefaultAsync(u => u.Id == currentId); return user; } public async Task ReceiveUserAsync(int id) { + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var user = await context.Users.SingleOrDefaultAsync(u => u.Id == id); return user; } public List ReceiveAllUser(int page, int size) { + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); var users = context.Users.Skip(page * size).Take(size).ToList(); return users; } diff --git a/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs b/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs index cf81a14..98e1992 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs @@ -7,7 +7,7 @@ namespace RelationshipAnalysis.Services.UserPanelServices; -public class UserUpdateInfoService(ApplicationDbContext context, IMapper mapper) : IUserUpdateInfoService +public class UserUpdateInfoService(IServiceProvider serviceProvider, IMapper mapper) : IUserUpdateInfoService { public async Task> UpdateUserAsync(User user, UserUpdateInfoDto userUpdateInfoDto, HttpResponse response) { @@ -26,6 +26,10 @@ public async Task> UpdateUserAsync(User user, UserUpd return BadRequestResult(Resources.EmailExistsMessage); } mapper.Map(userUpdateInfoDto, user); + + + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); context.Update(user); await context.SaveChangesAsync(); return SuccessResult(); @@ -34,11 +38,15 @@ public async Task> UpdateUserAsync(User user, UserUpd private bool IsUsernameUnique(string currentValue, string newValue) { if (currentValue == newValue) return true; + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); return !context.Users.Select(u => u.Username).Contains(newValue); } private bool IsEmailUnique(string currentValue, string newValue) { if (currentValue == newValue) return true; + using var scope = serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); return !context.Users.Select(u => u.Email).Contains(newValue); } private ActionResponse BadRequestResult(string message) From 5eed69237462396ddce264fdcf5ff127dbe28c2c Mon Sep 17 00:00:00 2001 From: sadq Date: Mon, 19 Aug 2024 15:06:50 +0330 Subject: [PATCH 07/12] resolved tests errors. --- .../Services/LoginServiceTests.cs | 10 ++++++++-- .../Services/PermissionServiceTests.cs | 9 ++++++++- .../Services/UserPasswordServiceTests.cs | 11 +++++++++-- .../Services/UserReceiverTests.cs | 13 ++++++++++--- .../Services/UserRolesReceiverTests.cs | 10 ++++++++-- .../Services/UserUpdateInfoServiceTests.cs | 12 ++++++++++-- 6 files changed, 53 insertions(+), 12 deletions(-) diff --git a/RelationshipAnalysis.Test/Services/LoginServiceTests.cs b/RelationshipAnalysis.Test/Services/LoginServiceTests.cs index 7faec5e..3cbdd2b 100644 --- a/RelationshipAnalysis.Test/Services/LoginServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/LoginServiceTests.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using Moq; using RelationshipAnalysis.Context; using RelationshipAnalysis.Dto; @@ -20,7 +21,7 @@ public class LoginServiceTests private readonly Mock _mockJwtTokenGenerator; private readonly Mock _mockPasswordVerifier; private readonly Mock _mockHttpResponse; - + private readonly IServiceProvider _serviceProvider; public LoginServiceTests() { var options = new DbContextOptionsBuilder() @@ -38,8 +39,13 @@ public LoginServiceTests() _mockHttpResponse = new Mock(); _mockHttpResponse.SetupGet(r => r.Cookies).Returns(mockResponseCookies.Object); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(_ => _context); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + _sut = new LoginService( - _context, + _serviceProvider, _mockCookieSetter.Object, _mockJwtTokenGenerator.Object, _mockPasswordVerifier.Object diff --git a/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs b/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs index a639101..ab66231 100644 --- a/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs @@ -1,5 +1,6 @@ using System.Security.Claims; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using Moq; using Newtonsoft.Json; using RelationshipAnalysis.Context; @@ -16,6 +17,7 @@ public class PermissionServiceTests private readonly ApplicationDbContext _context; private readonly List _userRoles = ["Read", "Write"]; private readonly List _adminRoles = ["Delete", "Write"]; + private readonly IServiceProvider _serviceProvider; public PermissionServiceTests() { @@ -25,9 +27,14 @@ public PermissionServiceTests() _context = new ApplicationDbContext(options); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(_ => _context); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + SeedDatabase(); - _sut = new PermissionService(_context); + _sut = new PermissionService(_serviceProvider); } private void SeedDatabase() diff --git a/RelationshipAnalysis.Test/Services/UserPasswordServiceTests.cs b/RelationshipAnalysis.Test/Services/UserPasswordServiceTests.cs index 181f9ff..cb553a7 100644 --- a/RelationshipAnalysis.Test/Services/UserPasswordServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/UserPasswordServiceTests.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using NSubstitute; using RelationshipAnalysis.Context; using RelationshipAnalysis.Dto; @@ -19,14 +20,20 @@ public class UserPasswordServiceTests private readonly IPasswordVerifier _passwordVerifier; private readonly IPasswordHasher _passwordHasher; private readonly IUserPasswordService _sut; - + private readonly IServiceProvider _serviceProvider; public UserPasswordServiceTests() { _context = new ApplicationDbContext(new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options); _passwordVerifier = Substitute.For(); _passwordHasher = Substitute.For(); - _sut = new UserPasswordService(_context, _passwordVerifier, _passwordHasher); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(_ => _context); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + + _sut = new UserPasswordService(_serviceProvider, _passwordVerifier, _passwordHasher); SeedDatabase(); } diff --git a/RelationshipAnalysis.Test/Services/UserReceiverTests.cs b/RelationshipAnalysis.Test/Services/UserReceiverTests.cs index a48fef7..93ffe62 100644 --- a/RelationshipAnalysis.Test/Services/UserReceiverTests.cs +++ b/RelationshipAnalysis.Test/Services/UserReceiverTests.cs @@ -1,9 +1,8 @@ using System.Security.Claims; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using RelationshipAnalysis.Context; -using RelationshipAnalysis.Models; using RelationshipAnalysis.Models.Auth; -using RelationshipAnalysis.Services; using RelationshipAnalysis.Services.UserPanelServices; namespace RelationshipAnalysis.Test.Services @@ -12,12 +11,20 @@ public class UserReceiverTests { private readonly ApplicationDbContext _context; private readonly UserReceiver _sut; + private readonly IServiceProvider _serviceProvider; public UserReceiverTests() { _context = new ApplicationDbContext(new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options); - _sut = new UserReceiver(_context); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(_ => _context); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + + + _sut = new UserReceiver(_serviceProvider); SeedDatabase(); } diff --git a/RelationshipAnalysis.Test/Services/UserRolesReceiverTests.cs b/RelationshipAnalysis.Test/Services/UserRolesReceiverTests.cs index d84552c..13474bb 100644 --- a/RelationshipAnalysis.Test/Services/UserRolesReceiverTests.cs +++ b/RelationshipAnalysis.Test/Services/UserRolesReceiverTests.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using RelationshipAnalysis.Context; using RelationshipAnalysis.Models; using RelationshipAnalysis.Models.Auth; @@ -12,12 +13,17 @@ public class UserRolesReceiverTests { private readonly ApplicationDbContext _context; private readonly RoleReceiver _sut; - + private readonly IServiceProvider _serviceProvider; public UserRolesReceiverTests() { _context = new ApplicationDbContext(new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options); - _sut = new RoleReceiver(_context); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(_ => _context); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + + _sut = new RoleReceiver(_serviceProvider); SeedDatabase(); } diff --git a/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs b/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs index 93ffbf0..c5b4b4b 100644 --- a/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs @@ -2,6 +2,7 @@ using AutoMapper; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using NSubstitute; using RelationshipAnalysis.Context; using RelationshipAnalysis.Dto; @@ -21,7 +22,7 @@ public class UserUpdateInfoServiceTests private readonly ICookieSetter _cookieSetter; private readonly IJwtTokenGenerator _jwtTokenGenerator; private readonly UserUpdateInfoService _sut; - + private readonly IServiceProvider _serviceProvider; public UserUpdateInfoServiceTests() { _context = new ApplicationDbContext(new DbContextOptionsBuilder() @@ -30,7 +31,14 @@ public UserUpdateInfoServiceTests() _mapper = Substitute.For(); _cookieSetter = Substitute.For(); _jwtTokenGenerator = Substitute.For(); - _sut = new UserUpdateInfoService(_context, _mapper); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(_ => _context); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + + + _sut = new UserUpdateInfoService(_serviceProvider, _mapper); SeedDatabase(); } From ad18fb5dfdd460c24374c8efabea5c1d02fc7abe Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 19 Aug 2024 15:44:55 +0330 Subject: [PATCH 08/12] Complete & Fix Migrations project. --- RelationAnalysis.Migrations/ConsoleStartup.cs | 36 --------------- .../InitialRecordsCreator.cs | 31 +++++++------ RelationAnalysis.Migrations/Program.cs | 46 ++++++++++++++----- .../RelationAnalysis.Migrations.csproj | 11 +++-- RelationAnalysis.Migrations/appsettings.json | 2 +- RelationshipAnalysis/Dto/CreateUserDto.cs | 2 +- RelationshipAnalysis/Dto/LoginDto.cs | 2 +- .../Dto/UserPasswordInfoDto.cs | 4 +- .../Abstraction/IPasswordHasher.cs | 2 +- .../Abstraction/IPasswordVerifier.cs | 2 +- .../AuthServices/CustomPasswordHasher.cs | 2 +- .../AuthServices/PasswordVerifier.cs | 2 +- 12 files changed, 66 insertions(+), 76 deletions(-) delete mode 100644 RelationAnalysis.Migrations/ConsoleStartup.cs diff --git a/RelationAnalysis.Migrations/ConsoleStartup.cs b/RelationAnalysis.Migrations/ConsoleStartup.cs deleted file mode 100644 index 163dab2..0000000 --- a/RelationAnalysis.Migrations/ConsoleStartup.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using RelationshipAnalysis.Context; -using Microsoft.Extensions.Configuration; - -namespace RelationAnalysis.Migrations -{ - public class ConsoleStartup - { - private IConfiguration Configuration { get; } = new ConfigurationBuilder() - .AddEnvironmentVariables() - .Build(); - public ConsoleStartup() - { - - //.. for test - Console.WriteLine(Configuration["CONNECTION_STRING"]); - } - - public void ConfigureServices(IServiceCollection services) - { - - services.AddDbContext(options => - { - options.UseNpgsql(Configuration["CONNECTION_STRING"]).UseLazyLoadingProxies(); - }); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - - } - } -} \ No newline at end of file diff --git a/RelationAnalysis.Migrations/InitialRecordsCreator.cs b/RelationAnalysis.Migrations/InitialRecordsCreator.cs index 31191a6..b5fd88f 100644 --- a/RelationAnalysis.Migrations/InitialRecordsCreator.cs +++ b/RelationAnalysis.Migrations/InitialRecordsCreator.cs @@ -1,17 +1,13 @@ +using Microsoft.Extensions.Configuration; using RelationshipAnalysis.Context; using RelationshipAnalysis.Models.Auth; -using Microsoft.Extensions.Configuration; +using RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServices; namespace RelationAnalysis.Migrations; -public class InitialRecordsCreator +public class InitialRecordsCreator(ApplicationDbContext context, IConfiguration configuration) { - private IConfiguration Configuration { get; } = new ConfigurationBuilder() - .AddEnvironmentVariables() - .AddJsonFile("appsettings.json") - .Build(); - - public void AddInitialRecords(ApplicationDbContext context) + public async Task AddInitialRecords() { var roles = new List() { @@ -42,17 +38,24 @@ public void AddInitialRecords(ApplicationDbContext context) new User() { Username = "admin", - PasswordHash = Configuration["admin"], + PasswordHash = new CustomPasswordHasher() + .HashPassword(configuration.GetValue("DefaultPassword")), FirstName = "FirstName", LastName = "LastName", Email = "admin@gmail.com", Id = 1, } }; - - context.AddRangeAsync(roles); - context.AddRangeAsync(users); - context.AddRangeAsync(userRoles); - context.SaveChangesAsync(); + try + { + await context.Roles.AddRangeAsync(roles); + await context.Users.AddRangeAsync(users); + await context.UserRoles.AddRangeAsync(userRoles); + await context.SaveChangesAsync(); + } + catch + { + Console.WriteLine("Data already exists!"); + } } } \ No newline at end of file diff --git a/RelationAnalysis.Migrations/Program.cs b/RelationAnalysis.Migrations/Program.cs index d5ade68..798909c 100644 --- a/RelationAnalysis.Migrations/Program.cs +++ b/RelationAnalysis.Migrations/Program.cs @@ -1,26 +1,48 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.EntityFrameworkCore; -using DotNetEnv; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using RelationshipAnalysis.Context; -using RelationshipAnalysis.Models.Auth; namespace RelationAnalysis.Migrations { class Program { - static void Main(string[] args) + static async Task Main(string[] args) { - Console.WriteLine("Applying migrations"); - var webHost = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() + Console.WriteLine("Run console app!"); + + + var host = Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((context, config) => + { + config.AddJsonFile("appsettings.json"); + config.AddEnvironmentVariables(); + }) + .ConfigureServices((context, services) => + { + var configuration = context.Configuration; + var connectionString = configuration.GetValue("CONNECTION_STRING"); + + services.AddDbContext(options => + options.UseNpgsql(connectionString)); + + services.AddTransient(); + }) .Build(); - using (var context = (ApplicationDbContext) webHost.Services.GetService(typeof(ApplicationDbContext))) + var configuration = host.Services.GetRequiredService(); + Console.WriteLine(configuration.GetValue("CONNECTION_STRING")); + + using (var scope = host.Services.CreateScope()) { - context.Database.Migrate(); - new InitialRecordsCreator().AddInitialRecords(context); + var dbContext = scope.ServiceProvider.GetRequiredService(); + await dbContext.Database.MigrateAsync(); + + var myService = scope.ServiceProvider.GetRequiredService(); + await myService.AddInitialRecords(); } + Console.WriteLine("Done"); } } diff --git a/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj b/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj index cb5d663..4c4adae 100644 --- a/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj +++ b/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj @@ -10,6 +10,9 @@ + + + @@ -26,11 +29,9 @@ - - true - PreserveNewest - PreserveNewest - + + PreserveNewest + diff --git a/RelationAnalysis.Migrations/appsettings.json b/RelationAnalysis.Migrations/appsettings.json index de69dbe..a74fa73 100644 --- a/RelationAnalysis.Migrations/appsettings.json +++ b/RelationAnalysis.Migrations/appsettings.json @@ -1,3 +1,3 @@ { - "DefaultPassword" : "admin" + "DefaultPassword": "admin" } diff --git a/RelationshipAnalysis/Dto/CreateUserDto.cs b/RelationshipAnalysis/Dto/CreateUserDto.cs index 6dd9afa..5806db6 100644 --- a/RelationshipAnalysis/Dto/CreateUserDto.cs +++ b/RelationshipAnalysis/Dto/CreateUserDto.cs @@ -10,7 +10,7 @@ public class CreateUserDto [Required(ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(Resources))] [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$", ErrorMessageResourceName = "InvalidPasswordMessage", ErrorMessageResourceType = typeof(Resources))] - public string Password { get; set; } + public string? Password { get; set; } [Required] public string FirstName { get; set; } diff --git a/RelationshipAnalysis/Dto/LoginDto.cs b/RelationshipAnalysis/Dto/LoginDto.cs index 7a734e1..306e1e7 100644 --- a/RelationshipAnalysis/Dto/LoginDto.cs +++ b/RelationshipAnalysis/Dto/LoginDto.cs @@ -6,5 +6,5 @@ public class LoginDto { [Required] public string Username { get; set; } - [Required] public string Password { get; set; } + [Required] public string? Password { get; set; } } \ No newline at end of file diff --git a/RelationshipAnalysis/Dto/UserPasswordInfoDto.cs b/RelationshipAnalysis/Dto/UserPasswordInfoDto.cs index 2530304..2040401 100644 --- a/RelationshipAnalysis/Dto/UserPasswordInfoDto.cs +++ b/RelationshipAnalysis/Dto/UserPasswordInfoDto.cs @@ -5,10 +5,10 @@ namespace RelationshipAnalysis.Dto; public class UserPasswordInfoDto { [Required(ErrorMessageResourceName = "OldPasswordRequired", ErrorMessageResourceType = typeof(Resources))] - public string OldPassword { get; set; } + public string? OldPassword { get; set; } [Required(ErrorMessageResourceName = "NewPasswordRequired", ErrorMessageResourceType = typeof(Resources))] [RegularExpression("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*\\W)(?!.* ).{8,}$", ErrorMessageResourceName = "InvalidPasswordMessage", ErrorMessageResourceType = typeof(Resources))] - public string NewPassword { get; set; } + public string? NewPassword { get; set; } } \ No newline at end of file diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordHasher.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordHasher.cs index 093be4f..c1848e1 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordHasher.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordHasher.cs @@ -2,5 +2,5 @@ public interface IPasswordHasher { - string HashPassword(string input); + string HashPassword(string? input); } \ No newline at end of file diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordVerifier.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordVerifier.cs index 9b89228..2bc032a 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordVerifier.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/Abstraction/IPasswordVerifier.cs @@ -2,5 +2,5 @@ public interface IPasswordVerifier { - bool VerifyPasswordHash(string password, string storedHash); + bool VerifyPasswordHash(string? password, string storedHash); } \ No newline at end of file diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/CustomPasswordHasher.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/CustomPasswordHasher.cs index 0195460..98802a1 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/CustomPasswordHasher.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/CustomPasswordHasher.cs @@ -6,7 +6,7 @@ namespace RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServic public class CustomPasswordHasher : IPasswordHasher { - public string HashPassword(string input) + public string HashPassword(string? input) { var hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(input)); var hash = BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); diff --git a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/PasswordVerifier.cs b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/PasswordVerifier.cs index 1db0b08..2d9dd97 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/PasswordVerifier.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/Abstraction/AuthServices/PasswordVerifier.cs @@ -4,7 +4,7 @@ namespace RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServic public class PasswordVerifier(IPasswordHasher passwordHasher) : IPasswordVerifier { - public bool VerifyPasswordHash(string password, string storedHash) + public bool VerifyPasswordHash(string? password, string storedHash) { return passwordHasher.HashPassword(password) == storedHash; } From b2dffafb7b37e9ae24f953b50c349a5c3364db44 Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 19 Aug 2024 15:52:25 +0330 Subject: [PATCH 09/12] add permissions. --- .../InitialRecordsCreator.cs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/RelationAnalysis.Migrations/InitialRecordsCreator.cs b/RelationAnalysis.Migrations/InitialRecordsCreator.cs index b5fd88f..57f88cc 100644 --- a/RelationAnalysis.Migrations/InitialRecordsCreator.cs +++ b/RelationAnalysis.Migrations/InitialRecordsCreator.cs @@ -11,9 +11,27 @@ public async Task AddInitialRecords() { var roles = new List() { - new Role() { Name = "Admin", Permissions = "[]", Id = 1 }, - new Role() { Name = "DataAdmin", Permissions = "[]", Id = 2 }, - new Role() { Name = "DataAnalyst", Permissions = "[]", Id = 3 } + new Role() + { + Name = "Admin", + Permissions = + "'[\"/api/Access/GetPermissions\",\"/api/Admin/GetUser/{id}\",\"/api/Admin/GetAllUser\",\"/api/Admin/GetAllRoles\",\"/api/Admin/UpdateUser/{id}\",\"/api/Admin/UpdatePassword/{id}\",\"/api/Admin/DeleteUser/{id}\",\"/api/Admin/CreateUser\",\"/api/Admin/UpdateRoles/{id}\",\"/api/Auth/Login\", \"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]'", + Id = 1 + }, + new Role() + { + Name = "DataAdmin", + Permissions = + "'[\"/api/Access/GetPermissions\",\"/api/Auth/Login\",\"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]'", + Id = 2 + }, + new Role() + { + Name = "DataAnalyst", + Permissions = + "'[\"/api/Access/GetPermissions\",\"/api/Auth/Login\",\"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]'", + Id = 3 + } }; var userRoles = new List() { From 3966b2d0f36a621a162482ccc969e626c4ccfbd6 Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 19 Aug 2024 17:06:24 +0330 Subject: [PATCH 10/12] Fix read appsetting bugs! --- .../RelationAnalysis.Migrations.csproj | 8 +++++--- RelationAnalysis.Migrations/appsettings.json | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj b/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj index 4c4adae..d713290 100644 --- a/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj +++ b/RelationAnalysis.Migrations/RelationAnalysis.Migrations.csproj @@ -11,6 +11,7 @@ + @@ -29,9 +30,10 @@ - - PreserveNewest - + + Always + + diff --git a/RelationAnalysis.Migrations/appsettings.json b/RelationAnalysis.Migrations/appsettings.json index a74fa73..5d902cc 100644 --- a/RelationAnalysis.Migrations/appsettings.json +++ b/RelationAnalysis.Migrations/appsettings.json @@ -1,3 +1,3 @@ -{ - "DefaultPassword": "admin" +{ + "DefaultPassword": "admin" } From 5c5d44be50a77e8ffdaeaf5f8d02b8d8ff905be5 Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 19 Aug 2024 17:44:44 +0330 Subject: [PATCH 11/12] Fix permissions. --- RelationAnalysis.Migrations/InitialRecordsCreator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RelationAnalysis.Migrations/InitialRecordsCreator.cs b/RelationAnalysis.Migrations/InitialRecordsCreator.cs index 57f88cc..6b0cb09 100644 --- a/RelationAnalysis.Migrations/InitialRecordsCreator.cs +++ b/RelationAnalysis.Migrations/InitialRecordsCreator.cs @@ -15,21 +15,21 @@ public async Task AddInitialRecords() { Name = "Admin", Permissions = - "'[\"/api/Access/GetPermissions\",\"/api/Admin/GetUser/{id}\",\"/api/Admin/GetAllUser\",\"/api/Admin/GetAllRoles\",\"/api/Admin/UpdateUser/{id}\",\"/api/Admin/UpdatePassword/{id}\",\"/api/Admin/DeleteUser/{id}\",\"/api/Admin/CreateUser\",\"/api/Admin/UpdateRoles/{id}\",\"/api/Auth/Login\", \"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]'", + "[\"/api/Access/GetPermissions\",\"/api/Admin/GetUser/{id}\",\"/api/Admin/GetAllUser\",\"/api/Admin/GetAllRoles\",\"/api/Admin/UpdateUser/{id}\",\"/api/Admin/UpdatePassword/{id}\",\"/api/Admin/DeleteUser/{id}\",\"/api/Admin/CreateUser\",\"/api/Admin/UpdateRoles/{id}\",\"/api/Auth/Login\", \"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]", Id = 1 }, new Role() { Name = "DataAdmin", Permissions = - "'[\"/api/Access/GetPermissions\",\"/api/Auth/Login\",\"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]'", + "[\"/api/Access/GetPermissions\",\"/api/Auth/Login\",\"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]", Id = 2 }, new Role() { Name = "DataAnalyst", Permissions = - "'[\"/api/Access/GetPermissions\",\"/api/Auth/Login\",\"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]'", + "[\"/api/Access/GetPermissions\",\"/api/Auth/Login\",\"/api/User/GetUser\",\"/api/User/UpdateUser\",\"/api/User/UpdatePassword\",\"/api/User/Logout\"]", Id = 3 } }; From d271adaf5085745112e6d60cdf5f903f5f286c44 Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 19 Aug 2024 18:40:46 +0330 Subject: [PATCH 12/12] Fix unit tests. --- .../Services/PermissionServiceTests.cs | 46 ++--- .../Services/UserUpdateInfoServiceTests.cs | 166 +++++++++--------- .../UserUpdateInfoService.cs | 44 +++-- 3 files changed, 133 insertions(+), 123 deletions(-) diff --git a/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs b/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs index ab66231..7143313 100644 --- a/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/PermissionServiceTests.cs @@ -14,21 +14,18 @@ namespace RelationshipAnalysis.Test.Services; public class PermissionServiceTests { private readonly PermissionService _sut; - private readonly ApplicationDbContext _context; - private readonly List _userRoles = ["Read", "Write"]; - private readonly List _adminRoles = ["Delete", "Write"]; private readonly IServiceProvider _serviceProvider; + private readonly List _userRoles = new List { "Read", "Write" }; + private readonly List _adminRoles = new List { "Delete", "Write" }; public PermissionServiceTests() { + var serviceCollection = new ServiceCollection(); + var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: "TestDatabase") .Options; - - _context = new ApplicationDbContext(options); - - var serviceCollection = new ServiceCollection(); - serviceCollection.AddScoped(_ => _context); + serviceCollection.AddScoped(_ => new ApplicationDbContext(options)); _serviceProvider = serviceCollection.BuildServiceProvider(); @@ -39,20 +36,24 @@ public PermissionServiceTests() private void SeedDatabase() { - _context.Roles.AddRange(new List + using (var scope = _serviceProvider.CreateScope()) { - new Role + var context = scope.ServiceProvider.GetRequiredService(); + context.Roles.AddRange(new List { - Name = "User", - Permissions = JsonConvert.SerializeObject(_userRoles) - }, - new Role - { - Name = "Admin", - Permissions = JsonConvert.SerializeObject(_adminRoles) - } - }); - _context.SaveChanges(); + new Role + { + Name = "User", + Permissions = JsonConvert.SerializeObject(_userRoles) + }, + new Role + { + Name = "Admin", + Permissions = JsonConvert.SerializeObject(_adminRoles) + } + }); + context.SaveChanges(); + } } [Fact] @@ -67,10 +68,13 @@ public async Task GetPermissionsAsync_ShouldReturnPermissions_WhenRolesExist() // Act var result = await _sut.GetPermissionsAsync(userClaims); + var expectedResult = _userRoles.Union(_adminRoles); + var expectedPermissions = JsonConvert.SerializeObject(expectedResult); // Assert - var expectedPermissions = JsonConvert.SerializeObject(expectedResult); + Assert.NotNull(result); + Assert.NotNull(result.Data); Assert.Equal(expectedPermissions, result.Data.Permissions); } } \ No newline at end of file diff --git a/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs b/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs index c5b4b4b..67961f3 100644 --- a/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/UserUpdateInfoServiceTests.cs @@ -1,162 +1,156 @@ - using AutoMapper; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -using NSubstitute; +using Moq; using RelationshipAnalysis.Context; using RelationshipAnalysis.Dto; using RelationshipAnalysis.Enums; -using RelationshipAnalysis.Models; using RelationshipAnalysis.Models.Auth; -using RelationshipAnalysis.Services; using RelationshipAnalysis.Services.UserPanelServices; -using RelationshipAnalysis.Services.UserPanelServices.Abstraction.AuthServices.Abstraction; namespace RelationshipAnalysis.Test.Services { public class UserUpdateInfoServiceTests { - private readonly ApplicationDbContext _context; - private readonly IMapper _mapper; - private readonly ICookieSetter _cookieSetter; - private readonly IJwtTokenGenerator _jwtTokenGenerator; private readonly UserUpdateInfoService _sut; private readonly IServiceProvider _serviceProvider; + private readonly User _user = new User + { + Id = 1, + Username = "existinguser", + Email = "existing@example.com", + PasswordHash = "hashedpassword", + FirstName = "John", + LastName = "Doe" + }; public UserUpdateInfoServiceTests() { - _context = new ApplicationDbContext(new DbContextOptionsBuilder() - .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options); - - _mapper = Substitute.For(); - _cookieSetter = Substitute.For(); - _jwtTokenGenerator = Substitute.For(); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddScoped(_ => _context); + + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) + .Options; + + serviceCollection.AddScoped(_ => new ApplicationDbContext(options)); + serviceCollection.AddAutoMapper(typeof(UserUpdateInfoService)); _serviceProvider = serviceCollection.BuildServiceProvider(); - - _sut = new UserUpdateInfoService(_serviceProvider, _mapper); + var mapper = _serviceProvider.GetRequiredService(); + _sut = new UserUpdateInfoService(_serviceProvider, mapper); + SeedDatabase(); } private void SeedDatabase() { - _context.Users.AddRange(new User + using (var scope = _serviceProvider.CreateScope()) { - Id = 1, - Username = "ExistingUser", - Email = "user@example.com", - FirstName = "", - LastName = "", - PasswordHash = "HashedPassword" - }, - new User - { - Id = 2, - Username = "NewUserName", - Email = "newemail@example.com", - FirstName = "", - LastName = "", - PasswordHash = "HashedPassword" - }); - _context.SaveChanges(); + var context = scope.ServiceProvider.GetRequiredService(); + context.Users.AddRange(new List() + { + _user, + new User + { + Id = 2, + Username = "existinguser2", + Email = "existing2@example.com", + PasswordHash = "hashedpassword", + FirstName = "John", + LastName = "Doe" + } + }); + context.SaveChanges(); + } } [Fact] - public async Task UpdateUserAsync_ReturnsBadRequest_WhenEmailAlreadyExists() + public async Task UpdateUserAsync_ShouldReturnNotFound_WhenUserIsNull() { // Arrange - var user = await _context.Users.FindAsync(1); - var userUpdateInfoDto = new UserUpdateInfoDto + User user = null; + var dto = new UserUpdateInfoDto { - Username = "ExistingUser", - Email = "newemail@example.com" + Username = "newuser", + Email = "new@example.com" }; - var response = Substitute.For(); + var response = new Mock().Object; // Act - var result = await _sut.UpdateUserAsync(user, userUpdateInfoDto, response); + var result = await _sut.UpdateUserAsync(user, dto, response); // Assert - Assert.NotNull(result); - Assert.Equal(StatusCodeType.BadRequest, result.StatusCode); - Assert.Equal(Resources.EmailExistsMessage, result.Data.Message); + Assert.Equal(StatusCodeType.NotFound, result.StatusCode); + Assert.Equal(Resources.UserNotFoundMessage, result.Data.Message); } [Fact] - public async Task UpdateUserAsync_ReturnsBadRequest_WhenUsernameAlreadyExists() + public async Task UpdateUserAsync_ShouldReturnBadRequest_WhenUsernameExists() { // Arrange - var user = await _context.Users.FindAsync(1); - var userUpdateInfoDto = new UserUpdateInfoDto + var dto = new UserUpdateInfoDto { - Username = "NewUserName", - Email = "user@example.com" + Username = "existinguser2" }; - var response = Substitute.For(); + var response = new Mock().Object; // Act - var result = await _sut.UpdateUserAsync(user, userUpdateInfoDto, response); + var result = await _sut.UpdateUserAsync(_user, dto, response); // Assert - Assert.NotNull(result); Assert.Equal(StatusCodeType.BadRequest, result.StatusCode); Assert.Equal(Resources.UsernameExistsMessage, result.Data.Message); } [Fact] - public async Task UpdateUserAsync_ReturnsNotFound_WhenUserIsNull() + public async Task UpdateUserAsync_ShouldReturnBadRequest_WhenEmailExists() { // Arrange - User user = null; - var userUpdateInfoDto = new UserUpdateInfoDto(); - var response = Substitute.For(); + var dto = new UserUpdateInfoDto + { + Email = "existing2@example.com" + }; + var response = new Mock().Object; // Act - var result = await _sut.UpdateUserAsync(user, userUpdateInfoDto, response); + var result = await _sut.UpdateUserAsync(_user, dto, response); // Assert - Assert.NotNull(result); - Assert.Equal(StatusCodeType.NotFound, result.StatusCode); - Assert.Equal(Resources.UserNotFoundMessage, result.Data.Message); + Assert.Equal(StatusCodeType.BadRequest, result.StatusCode); + Assert.Equal(Resources.EmailExistsMessage, result.Data.Message); } [Fact] - public async Task UpdateUserAsync_ReturnsSuccess_WhenUserIsUpdated() + public async Task UpdateUserAsync_ShouldUpdateUserAndReturnSuccess_WhenValidData() { // Arrange - var user = await _context.Users.FindAsync(1); - var userUpdateInfoDto = new UserUpdateInfoDto - { - Username = "UpdatedUserName", - Email = "updated@example.com" - }; - var resultUser = new User() + var dto = new UserUpdateInfoDto { - Id = 1, - Username = "UpdatedUserName", - Email = "updated@example.com", - FirstName = "", - LastName = "", - PasswordHash = "HashedPassword" + Username = "newuser", + Email = "new@example.com", + FirstName = "Jane", + LastName = "Smith" }; - _mapper.Map(userUpdateInfoDto).Returns(resultUser); - - var response = Substitute.For(); - + var response = new Mock().Object; + // Act - var result = await _sut.UpdateUserAsync(user, userUpdateInfoDto, response); + var result = await _sut.UpdateUserAsync(_user, dto, response); // Assert - Assert.NotNull(result); Assert.Equal(StatusCodeType.Success, result.StatusCode); Assert.Equal(Resources.SuccessfulUpdateUserMessage, result.Data.Message); - Assert.Equal("ExistingUser", user.Username); - Assert.Equal("user@example.com", user.Email); + + using (var scope = _serviceProvider.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + var updatedUser = context.Users.SingleOrDefault(u => u.Id == _user.Id); + Assert.NotNull(updatedUser); + Assert.Equal("newuser", updatedUser.Username); + Assert.Equal("new@example.com", updatedUser.Email); + Assert.Equal("Jane", updatedUser.FirstName); + Assert.Equal("Smith", updatedUser.LastName); + } } - } } diff --git a/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs b/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs index 98e1992..c74c64b 100644 --- a/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs +++ b/RelationshipAnalysis/Services/UserPanelServices/UserUpdateInfoService.cs @@ -11,7 +11,7 @@ public class UserUpdateInfoService(IServiceProvider serviceProvider, IMapper map { public async Task> UpdateUserAsync(User user, UserUpdateInfoDto userUpdateInfoDto, HttpResponse response) { - if (user is null) + if (user == null) { return NotFoundResult(); } @@ -25,41 +25,53 @@ public async Task> UpdateUserAsync(User user, UserUpd { return BadRequestResult(Resources.EmailExistsMessage); } + mapper.Map(userUpdateInfoDto, user); - - - using var scope = serviceProvider.CreateScope(); - var context = scope.ServiceProvider.GetRequiredService(); - context.Update(user); - await context.SaveChangesAsync(); + + using (var scope = serviceProvider.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + context.Update(user); + await context.SaveChangesAsync(); + } + return SuccessResult(); } private bool IsUsernameUnique(string currentValue, string newValue) { if (currentValue == newValue) return true; - using var scope = serviceProvider.CreateScope(); - var context = scope.ServiceProvider.GetRequiredService(); - return !context.Users.Select(u => u.Username).Contains(newValue); + + using (var scope = serviceProvider.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + return !context.Users.Any(u => u.Username == newValue); + } } + private bool IsEmailUnique(string currentValue, string newValue) { if (currentValue == newValue) return true; - using var scope = serviceProvider.CreateScope(); - var context = scope.ServiceProvider.GetRequiredService(); - return !context.Users.Select(u => u.Email).Contains(newValue); + + using (var scope = serviceProvider.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + return !context.Users.Any(u => u.Email == newValue); + } } + private ActionResponse BadRequestResult(string message) { - return new ActionResponse() + return new ActionResponse { Data = new MessageDto(message), StatusCode = StatusCodeType.BadRequest }; } + private ActionResponse NotFoundResult() { - return new ActionResponse() + return new ActionResponse { Data = new MessageDto(Resources.UserNotFoundMessage), StatusCode = StatusCodeType.NotFound @@ -68,7 +80,7 @@ private ActionResponse NotFoundResult() private ActionResponse SuccessResult() { - return new ActionResponse() + return new ActionResponse { Data = new MessageDto(Resources.SuccessfulUpdateUserMessage), StatusCode = StatusCodeType.Success