Add UserRole handling
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Imprink.Domain.Repositories;
|
||||
using Imprink.Domain.Repositories.Products;
|
||||
using Imprink.Domain.Repositories.Users;
|
||||
|
||||
namespace Imprink.Application;
|
||||
|
||||
|
||||
7
src/Imprink.Application/Users/Dtos/RoleDto.cs
Normal file
7
src/Imprink.Application/Users/Dtos/RoleDto.cs
Normal 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; }
|
||||
}
|
||||
7
src/Imprink.Application/Users/Dtos/UserRoleDto.cs
Normal file
7
src/Imprink.Application/Users/Dtos/UserRoleDto.cs
Normal 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; }
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
29
src/Imprink.Application/Users/SetUserRoleHandler.cs
Normal file
29
src/Imprink.Application/Users/SetUserRoleHandler.cs
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>()
|
||||
[]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,13 +10,13 @@ export default function Home() {
|
||||
const fetchAccessToken = async () => {
|
||||
if (user) {
|
||||
try {
|
||||
const v = await fetch('/token');
|
||||
await fetch('/token');
|
||||
} catch (error) {
|
||||
console.error("Error fetching token");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const resp = await fetch('/untoken');
|
||||
await fetch('/untoken');
|
||||
} catch (e) {
|
||||
console.error('Error in /api/untoken:', e);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {cookies, headers} from 'next/headers';
|
||||
import { NextResponse } from 'next/server';
|
||||
import {auth0} from "@/lib/auth0";
|
||||
import api from "@/lib/api";
|
||||
@@ -9,20 +8,11 @@ export async function GET() {
|
||||
|
||||
if (!token) { return NextResponse.json({ error: 'No access token found' }, { status: 401 }); }
|
||||
|
||||
(await cookies()).set('access_token', token, {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'strict',
|
||||
path: '/',
|
||||
domain: process.env.COOKIE_DOMAIN,
|
||||
maxAge: 3600,
|
||||
});
|
||||
|
||||
await api.post('/users/sync', {}, {
|
||||
headers: { Cookie: `access_token=${token}` }
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Access token set in cookie' });
|
||||
return NextResponse.json({ access_token: token });
|
||||
} catch (error) {
|
||||
console.error('Error in /api/token:', error);
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import {cookies} from 'next/headers';
|
||||
import {NextResponse} from 'next/server';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
(await cookies()).set({
|
||||
name: 'access_token',
|
||||
value: '',
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'strict',
|
||||
path: '/',
|
||||
domain: process.env.COOKIE_DOMAIN,
|
||||
maxAge: -1,
|
||||
});
|
||||
|
||||
return NextResponse.json({message: 'Deleted access token'});
|
||||
} catch (error) {
|
||||
console.error('Error in /api/untoken:', error);
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user