diff --git a/TableBooking.Api/Extensions/RolesExtension.cs b/TableBooking.Api/Extensions/RolesExtension.cs new file mode 100644 index 0000000..eb20e38 --- /dev/null +++ b/TableBooking.Api/Extensions/RolesExtension.cs @@ -0,0 +1,28 @@ +namespace TableBooking.Api.Extensions; + +using Microsoft.AspNetCore.Identity; +using Model.Models; + +public static class RolesExtension +{ + public static async Task SeedRolesAsync(IServiceProvider serviceProvider) + { + using var scope = serviceProvider.CreateScope(); + var roleManager = scope.ServiceProvider.GetRequiredService>(); + + if (!await roleManager.RoleExistsAsync("User")) + { + await roleManager.CreateAsync(new AppRole { Name = "User" }); + } + + if (!await roleManager.RoleExistsAsync("Admin")) + { + await roleManager.CreateAsync(new AppRole { Name = "Admin" }); + } + + if (!await roleManager.RoleExistsAsync("Restaurant")) + { + await roleManager.CreateAsync(new AppRole { Name = "Restaurant" }); + } + } +} \ No newline at end of file diff --git a/TableBooking.Api/Interfaces/IUserService.cs b/TableBooking.Api/Interfaces/IUserService.cs index c88dea8..2a3aa2e 100644 --- a/TableBooking.Api/Interfaces/IUserService.cs +++ b/TableBooking.Api/Interfaces/IUserService.cs @@ -1,5 +1,6 @@ namespace TableBooking.Api.Interfaces; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Model.Dtos.UserDtos; @@ -9,5 +10,4 @@ public interface IUserService public Task Login(UserLoginDto userLoginDto); public Task Logout(string? authHeader); public Task GetUserInfo(Guid id, CancellationToken cancellationToken); - public Task SeedRoles(); } \ No newline at end of file diff --git a/TableBooking.Api/Program.cs b/TableBooking.Api/Program.cs index f1823c0..719bf64 100644 --- a/TableBooking.Api/Program.cs +++ b/TableBooking.Api/Program.cs @@ -10,6 +10,7 @@ using Serilog; using TableBooking.Api.Configuration.DbSetup; using TableBooking.Api.Configuration.HealthCheck; +using TableBooking.Api.Extensions; using TableBooking.Api.Interfaces; using TableBooking.Api.Middleware; using TableBooking.Api.Services; @@ -163,6 +164,12 @@ var app = builder.Build(); +using (var scope = app.Services.CreateScope()) +{ + var serviceProvider = scope.ServiceProvider; + await RolesExtension.SeedRolesAsync(serviceProvider); +} + app.UseMiddleware(); if (app.Environment.IsDevelopment()) diff --git a/TableBooking.Api/Services/UserService.cs b/TableBooking.Api/Services/UserService.cs index ed897e5..929eb5b 100644 --- a/TableBooking.Api/Services/UserService.cs +++ b/TableBooking.Api/Services/UserService.cs @@ -3,6 +3,7 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; +using Extensions; using Interfaces; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; @@ -18,7 +19,6 @@ public class UserService : IUserService private readonly UserManager _userManager; private readonly RoleManager _roleManager; private readonly IConfiguration _configuration; - private const string UserRoleId = "5ad1268f-f61f-4b1c-b690-cbf8c3d35019"; private readonly TableBookingContext _dbContext; public UserService(UserManager userManager, @@ -42,36 +42,38 @@ public async Task Register(UserRegisterDto dto) if (emailExists != null) return new BadRequestObjectResult($"User with the same email found: {dto.Email}."); - var appUserRole = await _roleManager.FindByIdAsync(UserRoleId); + var appUserRole = await _roleManager.FindByNameAsync("User"); if (appUserRole == null) - return new BadRequestObjectResult($"Can't find role by UserRoleId: {UserRoleId}"); + return new BadRequestObjectResult($"Can't find role by name 'User'."); var user = new AppUser { Email = dto.Email, SecurityStamp = Guid.NewGuid().ToString(), UserName = dto.Username, - AppRoleId = appUserRole.Id + AppRoleId = appUserRole.Id, + AppRole = appUserRole }; - + var result = await _userManager.CreateAsync(user, dto.Password); if (!result.Succeeded) - return new BadRequestObjectResult("Invalid password lenght Or Bad Email"); + return new BadRequestObjectResult("Invalid password length or Bad Email"); return new OkObjectResult(new ResultDto { Status = "Success", Message = "User created successfully!" }); } public async Task Login(UserLoginDto dto) { - var user = await _userManager.FindByNameAsync(dto.Username) ; - if (user == null || !await _userManager.CheckPasswordAsync(user, dto.Password)) - { - return new UnauthorizedResult(); - } + var user = await _userManager.FindByNameAsync(dto.Username); + if (user == null) + return new BadRequestObjectResult($"User with username '{dto.Username}' does not exist."); + + if (!await _userManager.CheckPasswordAsync(user, dto.Password)) + return new BadRequestObjectResult($"Wrong password."); - var role = await _roleManager.FindByIdAsync(user.AppRoleId.ToString()); - if (role == null) return new BadRequestObjectResult($"Can't login. Role for this user {user.Id} is null"); + var role = await _roleManager.FindByNameAsync("User"); + if (role == null) return new BadRequestObjectResult($"Can't login. Role named 'User' is not found."); if (string.IsNullOrEmpty(user.UserName)) { @@ -92,7 +94,7 @@ public async Task Login(UserLoginDto dto) }; var token = GetToken(authClaims); - + return new OkObjectResult(new { token = new JwtSecurityTokenHandler().WriteToken(token), @@ -144,9 +146,4 @@ private JwtSecurityToken GetToken(List authClaims) return token; } - - public Task SeedRoles() - { - throw new NotImplementedException(); - } } \ No newline at end of file diff --git a/TableBooking.Model/Models/AppRole.cs b/TableBooking.Model/Models/AppRole.cs index 6fa7af0..908b715 100644 --- a/TableBooking.Model/Models/AppRole.cs +++ b/TableBooking.Model/Models/AppRole.cs @@ -2,6 +2,4 @@ using Microsoft.AspNetCore.Identity; -public class AppRole : IdentityRole -{ -} \ No newline at end of file +public class AppRole : IdentityRole; \ No newline at end of file diff --git a/TableBooking.Model/Models/AppUser.cs b/TableBooking.Model/Models/AppUser.cs index ced16cb..39764bd 100644 --- a/TableBooking.Model/Models/AppUser.cs +++ b/TableBooking.Model/Models/AppUser.cs @@ -1,5 +1,6 @@ namespace TableBooking.Model.Models; +using System.ComponentModel.DataAnnotations.Schema; using Dtos.UserDtos; using Microsoft.AspNetCore.Identity; @@ -10,7 +11,6 @@ public class AppUser : IdentityUser public IEnumerable Bookings { get; set; } = new List(); public Guid AppRoleId { get; set; } public AppRole AppRole { get; set; } = new(); - public AppUserDto ToDto() { return new AppUserDto diff --git a/TableBooking.Model/Seed/migration-deploy.sql b/TableBooking.Model/Seed/migration-deploy.sql index 64c4fb9..6bacaeb 100644 --- a/TableBooking.Model/Seed/migration-deploy.sql +++ b/TableBooking.Model/Seed/migration-deploy.sql @@ -3,9 +3,9 @@ CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" ( "MigrationId" character varying(150) NOT NULL, - "ProductVersion" character varying(32) NOT NULL, - CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId") - ); + "ProductVersion" character varying(32) NOT NULL, + CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId") +); START TRANSACTION; CREATE TABLE "Restaurants" ( @@ -143,4 +143,9 @@ ALTER TABLE "RevokedTokens" ALTER COLUMN "Token" TYPE character varying(512); INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('20250117211021_RevokedTokensTableMaxLength', '9.0.0'); +ALTER TABLE "Bookings" ADD "RestaurantId" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20250119150709_BookingChanges', '9.0.0'); + COMMIT; \ No newline at end of file