Add UserRole handling

This commit is contained in:
lumijiez
2025-06-10 22:10:16 +03:00
parent beaacffb9a
commit a25459d2cb
15 changed files with 92 additions and 143 deletions

View File

@@ -1,5 +1,6 @@
using Imprink.Domain.Repositories;
using Imprink.Domain.Repositories.Products;
using Imprink.Domain.Repositories.Users;
namespace Imprink.Application;

View File

@@ -0,0 +1,7 @@
namespace Imprink.Application.Users.Dtos;
public class RoleDto
{
public required Guid RoleId { get; set; }
public required string RoleName { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace Imprink.Application.Users.Dtos;
public class UserRoleDto
{
public required string UserId { get; set; }
public required Guid RoleId { get; set; }
}

View File

@@ -1,15 +1,22 @@
using Imprink.Domain.Entities.Users;
using Imprink.Application.Users.Dtos;
using MediatR;
namespace Imprink.Application.Users;
public record GetUserRolesCommand(string Sub) : IRequest<IEnumerable<Role>>;
public record GetUserRolesCommand(string Sub) : IRequest<IEnumerable<RoleDto>>;
public class GetUserRolesHandler(IUnitOfWork uw): IRequestHandler<GetUserRolesCommand, IEnumerable<Role>>
public class GetUserRolesHandler(IUnitOfWork uw): IRequestHandler<GetUserRolesCommand, IEnumerable<RoleDto>>
{
public async Task<IEnumerable<Role>> Handle(GetUserRolesCommand request, CancellationToken cancellationToken)
public async Task<IEnumerable<RoleDto>> Handle(GetUserRolesCommand request, CancellationToken cancellationToken)
{
if (await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return [];
return await uw.UserRoleRepository.GetUserRolesAsync(request.Sub, cancellationToken);;
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return [];
var roles = await uw.UserRoleRepository.GetUserRolesAsync(request.Sub, cancellationToken);
return roles.Select(role => new RoleDto
{
RoleId = role.Id,
RoleName = role.RoleName
}).ToList();
}
}

View File

@@ -1,39 +0,0 @@
using Imprink.Domain.Entities.Users;
using Imprink.Domain.Repositories;
using MediatR;
namespace Imprink.Application.Users.Roles;
public record AddUserToRoleCommand(string UserId, Guid RoleId) : IRequest<bool>;
public class AddUserToRoleCommandHandler(
IUserRoleRepository userRoleRepository,
IRoleRepository roleRepository,
IUserRepository userRepository)
: IRequestHandler<AddUserToRoleCommand, bool>
{
public async Task<bool> Handle(AddUserToRoleCommand request, CancellationToken cancellationToken)
{
var userExists = await userRepository.UserExistsAsync(request.UserId, cancellationToken);
if (!userExists)
return false;
var roleExists = await roleRepository.RoleExistsAsync(request.RoleId, cancellationToken);
if (!roleExists)
return false;
var isAlreadyInRole = await userRoleRepository.IsUserInRoleAsync(request.UserId, request.RoleId, cancellationToken);
if (isAlreadyInRole)
return true;
var userRole = new UserRole
{
UserId = request.UserId,
RoleId = request.RoleId
};
await userRoleRepository.AddUserRoleAsync(userRole, cancellationToken);
return true;
}
}

View File

@@ -1,32 +0,0 @@
using Imprink.Domain.Repositories;
using MediatR;
namespace Imprink.Application.Users.Roles;
public record RemoveUserFromRoleCommand(string UserId, Guid RoleId) : IRequest<bool>;
public class RemoveUserFromRoleCommandHandler(
IUserRoleRepository userRoleRepository,
IRoleRepository roleRepository,
IUserRepository userRepository)
: IRequestHandler<RemoveUserFromRoleCommand, bool>
{
public async Task<bool> Handle(RemoveUserFromRoleCommand request, CancellationToken cancellationToken)
{
var userExists = await userRepository.UserExistsAsync(request.UserId, cancellationToken);
if (!userExists)
return false;
var roleExists = await roleRepository.RoleExistsAsync(request.RoleId, cancellationToken);
if (!roleExists)
return false;
var userRole = await userRoleRepository.GetUserRoleAsync(request.UserId, request.RoleId, cancellationToken);
if (userRole == null)
return true;
await userRoleRepository.RemoveUserRoleAsync(userRole, cancellationToken);
return true;
}
}

View File

@@ -0,0 +1,29 @@
using Imprink.Application.Users.Dtos;
using Imprink.Domain.Entities.Users;
using MediatR;
namespace Imprink.Application.Users;
public record SetUserRoleCommand(string Sub, Guid RoleId) : IRequest<UserRoleDto?>;
public class SetUserRoleHandler(IUnitOfWork uw) : IRequestHandler<SetUserRoleCommand, UserRoleDto?>
{
public async Task<UserRoleDto?> Handle(SetUserRoleCommand request, CancellationToken cancellationToken)
{
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return null;
var userRole = new UserRole
{
UserId = request.Sub,
RoleId = request.RoleId
};
var addedRole = await uw.UserRoleRepository.AddUserRoleAsync(userRole, cancellationToken);
return new UserRoleDto
{
UserId = addedRole.UserId,
RoleId = addedRole.RoleId
};
}
}

View File

@@ -1,15 +1,13 @@
using Imprink.Domain.Entities.Users;
namespace Imprink.Domain.Repositories;
namespace Imprink.Domain.Repositories.Users;
public interface IUserRoleRepository
{
Task<IEnumerable<Role>> GetUserRolesAsync(string userId, CancellationToken cancellationToken = default);
Task<IEnumerable<User>> GetUsersInRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
Task<bool> IsUserInRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default);
Task<UserRole?> GetUserRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default);
Task AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
Task RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
Task<IEnumerable<UserRole>> GetUserRolesByUserIdAsync(string userId, CancellationToken cancellationToken = default);
Task<UserRole> AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
Task<UserRole> RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
}

View File

@@ -1,5 +1,6 @@
using Imprink.Domain.Entities.Users;
using Imprink.Domain.Repositories;
using Imprink.Domain.Repositories.Users;
using Imprink.Infrastructure.Database;
using Microsoft.EntityFrameworkCore;
@@ -25,12 +26,6 @@ public class UserRoleRepository(ApplicationDbContext context) : IUserRoleReposit
.ToListAsync(cancellationToken);
}
public async Task<bool> IsUserInRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default)
{
return await context.UserRole
.AnyAsync(ur => ur.UserId == userId && ur.RoleId == roleId, cancellationToken);
}
public async Task<UserRole?> GetUserRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default)
{
return await context.UserRole
@@ -38,23 +33,17 @@ public class UserRoleRepository(ApplicationDbContext context) : IUserRoleReposit
.FirstOrDefaultAsync(ur => ur.UserId == userId && ur.RoleId == roleId, cancellationToken);
}
public async Task AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
public async Task<UserRole> AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
{
context.UserRole.Add(userRole);
var ur = context.UserRole.Add(userRole);
await context.SaveChangesAsync(cancellationToken);
return ur.Entity;
}
public async Task RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
public async Task<UserRole> RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
{
context.UserRole.Remove(userRole);
var ur = context.UserRole.Remove(userRole);
await context.SaveChangesAsync(cancellationToken);
}
public async Task<IEnumerable<UserRole>> GetUserRolesByUserIdAsync(string userId, CancellationToken cancellationToken = default)
{
return await context.UserRole
.AsNoTracking()
.Where(ur => ur.UserId == userId)
.ToListAsync(cancellationToken);
return ur.Entity;
}
}

View File

@@ -1,6 +1,7 @@
using Imprink.Application;
using Imprink.Domain.Repositories;
using Imprink.Domain.Repositories.Products;
using Imprink.Domain.Repositories.Users;
using Imprink.Infrastructure.Database;
namespace Imprink.Infrastructure;

View File

@@ -1,6 +1,7 @@
using System.Security.Claims;
using Imprink.Application.Users;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Imprink.WebApi.Controllers.Users;
@@ -9,7 +10,7 @@ namespace Imprink.WebApi.Controllers.Users;
[Route("/api/users/roles")]
public class UserRoleController(IMediator mediator) : ControllerBase
{
//[Authorize]
[Authorize]
[HttpGet("me")]
public async Task<IActionResult> GetMyRoles()
{
@@ -20,4 +21,16 @@ public class UserRoleController(IMediator mediator) : ControllerBase
return Ok(myRoles);
}
[Authorize(Roles = "Admin")]
[HttpPost("set")]
public async Task<IActionResult> SetUserRole(SetUserRoleCommand command)
{
var userRole = await mediator.Send(command);
if (userRole == null)
return BadRequest();
return Ok(userRole);
}
}

View File

@@ -5,6 +5,7 @@ using Imprink.Application.Products.Create;
using Imprink.Application.Validation.Models;
using Imprink.Domain.Repositories;
using Imprink.Domain.Repositories.Products;
using Imprink.Domain.Repositories.Users;
using Imprink.Infrastructure;
using Imprink.Infrastructure.Database;
using Imprink.Infrastructure.Repositories.Products;
@@ -74,6 +75,7 @@ public static class Startup
foreach (var role in roles) identity!.AddClaim(new Claim(ClaimTypes.Role, role));
identity!.AddClaim(new Claim(ClaimTypes.Role, "User"));
return Task.CompletedTask;
}
};
@@ -99,8 +101,9 @@ public static class Startup
Description = "JWT Authorization header using the Bearer scheme.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
@@ -112,12 +115,9 @@ public static class Startup
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "Bearer",
Name = "Bearer",
In = ParameterLocation.Header
}
},
new List<string>()
[]
}
});
});