feat: add Logs

This commit is contained in:
2026-09-20 16:21:15 +07:00
parent 637ca51f47
commit d3c3ecd5e6
62 changed files with 1577 additions and 66 deletions
@@ -0,0 +1,34 @@
using MediatR;
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
using mws.backend.dotnet.domain.Users;
namespace mws.backend.dotnet.application.Users;
public record AssignUserRoleCommand(Guid ActorUserId, Guid TargetUserId, Guid RoleId) : IRequest, IAuditableRequest
{
public string Action => "User.AssignRole";
public string EntityType => "User";
public Guid? EntityId => TargetUserId;
}
public class AssignUserRoleHandler(IUnitOfWork uow, IPermissionService permissions, IAuditContext auditContext)
: IRequestHandler<AssignUserRoleCommand>
{
public async Task Handle(AssignUserRoleCommand command, CancellationToken ct)
{
await permissions.EnsureAsync(command.ActorUserId, "permissions", PermissionAction.Edit, ct);
var user = await uow.Users.GetByIdWithRoleAsync(command.TargetUserId, ct)
?? throw new NotFoundException("User not found");
if (user.UserRoles.All(ur => ur.RoleId != command.RoleId))
{
user.UserRoles.Add(new UserRole { UserId = command.TargetUserId, RoleId = command.RoleId });
await uow.SaveChangesAsync(ct);
}
auditContext.EntityName = user.Username;
}
}
+7 -1
View File
@@ -1,5 +1,6 @@
using AutoMapper;
using MediatR;
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Auth;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
@@ -8,7 +9,12 @@ using mws.backend.dotnet.domain.Users;
namespace mws.backend.dotnet.application.Users;
public record CreateUserCommand(Guid ActorUserId, CreateUserRequest Request) : IRequest<UserDto>;
public record CreateUserCommand(Guid ActorUserId, CreateUserRequest Request) : IRequest<UserDto>, IAuditableRequest
{
public string Action => "User.Create";
public string EntityType => "User";
public string? EntityName => Request.Username;
}
public class CreateUserHandler(IUnitOfWork uow, IPasswordHasher passwordHasher, IPermissionService permissions, IMapper mapper)
: IRequestHandler<CreateUserCommand, UserDto>
+10 -2
View File
@@ -1,12 +1,18 @@
using MediatR;
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
namespace mws.backend.dotnet.application.Users;
public record DeleteUserCommand(Guid ActorUserId, Guid Id) : IRequest;
public record DeleteUserCommand(Guid ActorUserId, Guid Id) : IRequest, IAuditableRequest
{
public string Action => "User.Delete";
public string EntityType => "User";
public Guid? EntityId => Id;
}
public class DeleteUserHandler(IUnitOfWork uow, IPermissionService permissions) : IRequestHandler<DeleteUserCommand>
public class DeleteUserHandler(IUnitOfWork uow, IPermissionService permissions, IAuditContext auditContext) : IRequestHandler<DeleteUserCommand>
{
private const string Screen = "users";
@@ -30,5 +36,7 @@ public class DeleteUserHandler(IUnitOfWork uow, IPermissionService permissions)
uow.Users.Remove(user);
await uow.SaveChangesAsync(ct);
auditContext.EntityName = user.Username;
}
}
+10 -2
View File
@@ -1,13 +1,19 @@
using MediatR;
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Auth;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
namespace mws.backend.dotnet.application.Users;
public record ResetPasswordCommand(Guid ActorUserId, Guid Id, ResetPasswordRequest Request) : IRequest;
public record ResetPasswordCommand(Guid ActorUserId, Guid Id, ResetPasswordRequest Request) : IRequest, IAuditableRequest
{
public string Action => "User.ResetPassword";
public string EntityType => "User";
public Guid? EntityId => Id;
}
public class ResetPasswordHandler(IUnitOfWork uow, IPasswordHasher passwordHasher, IPermissionService permissions)
public class ResetPasswordHandler(IUnitOfWork uow, IPasswordHasher passwordHasher, IPermissionService permissions, IAuditContext auditContext)
: IRequestHandler<ResetPasswordCommand>
{
private const string Screen = "users";
@@ -27,5 +33,7 @@ public class ResetPasswordHandler(IUnitOfWork uow, IPasswordHasher passwordHashe
user.PasswordHash = passwordHasher.Hash(command.Request.NewPassword);
user.UpdatedAt = DateTime.UtcNow;
await uow.SaveChangesAsync(ct);
auditContext.EntityName = user.Username;
}
}
@@ -0,0 +1,34 @@
using MediatR;
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
namespace mws.backend.dotnet.application.Users;
public record UnassignUserRoleCommand(Guid ActorUserId, Guid TargetUserId, Guid RoleId) : IRequest, IAuditableRequest
{
public string Action => "User.UnassignRole";
public string EntityType => "User";
public Guid? EntityId => TargetUserId;
}
public class UnassignUserRoleHandler(IUnitOfWork uow, IPermissionService permissions, IAuditContext auditContext)
: IRequestHandler<UnassignUserRoleCommand>
{
public async Task Handle(UnassignUserRoleCommand command, CancellationToken ct)
{
await permissions.EnsureAsync(command.ActorUserId, "permissions", PermissionAction.Edit, ct);
var user = await uow.Users.GetByIdWithRoleAsync(command.TargetUserId, ct)
?? throw new NotFoundException("User not found");
var userRole = user.UserRoles.FirstOrDefault(ur => ur.RoleId == command.RoleId);
if (userRole is not null)
{
user.UserRoles.Remove(userRole);
await uow.SaveChangesAsync(ct);
}
auditContext.EntityName = user.Username;
}
}
+8 -1
View File
@@ -1,11 +1,18 @@
using AutoMapper;
using MediatR;
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
namespace mws.backend.dotnet.application.Users;
public record UpdateUserCommand(Guid ActorUserId, Guid Id, UpdateUserRequest Request) : IRequest<UserDto>;
public record UpdateUserCommand(Guid ActorUserId, Guid Id, UpdateUserRequest Request) : IRequest<UserDto>, IAuditableRequest
{
public string Action => "User.Update";
public string EntityType => "User";
public Guid? EntityId => Id;
public string? EntityName => Request.DisplayName;
}
public class UpdateUserHandler(IUnitOfWork uow, IPermissionService permissions, IMapper mapper)
: IRequestHandler<UpdateUserCommand, UserDto>
+3 -1
View File
@@ -1,3 +1,4 @@
using mws.backend.dotnet.application.Audit;
using mws.backend.dotnet.application.Permissions;
namespace mws.backend.dotnet.application.Users;
@@ -22,9 +23,10 @@ public class ResetPasswordRequest
public string NewPassword { get; set; } = string.Empty;
}
public class UserDto
public class UserDto : IHasEntityId
{
public Guid Id { get; set; }
public Guid EntityId => Id;
public string Username { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public Guid RoleId { get; set; }