Files
2026-09-20 16:21:15 +07:00

145 lines
5.4 KiB
C#

using AutoMapper;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using mws.backend.dotnet.application.Common;
using mws.backend.dotnet.application.Permissions;
using mws.backend.dotnet.application.Users;
using mws.backend.dotnet.infrastructure.Persistence;
namespace mws.backend.dotnet.api.Controllers;
[ApiController]
[Route("api/users")]
[Authorize]
public class UsersController(ISender sender, AppDbContext db, IPermissionService permissions, IMapper mapper) : ControllerBase
{
[HttpGet]
public async Task<ActionResult<PagedResult<UserDto>>> GetAll(
[FromQuery] string? q, [FromQuery] bool? isActive, [FromQuery] int page = 1, [FromQuery] int pageSize = 20, CancellationToken ct = default)
{
var filter = new UserListFilter(q, isActive);
return Ok(await sender.Send(new GetUsersQuery(User.GetUserId(), filter, page, pageSize), ct));
}
[HttpPost]
public async Task<ActionResult<UserDto>> Create([FromBody] CreateUserRequest request, CancellationToken ct)
{
return Ok(await sender.Send(new CreateUserCommand(User.GetUserId(), request), ct));
}
[HttpPut("{id:guid}")]
public async Task<ActionResult<UserDto>> Update(Guid id, [FromBody] UpdateUserRequest request, CancellationToken ct)
{
return Ok(await sender.Send(new UpdateUserCommand(User.GetUserId(), id, request), ct));
}
[HttpDelete("{id:guid}")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{
await sender.Send(new DeleteUserCommand(User.GetUserId(), id), ct);
return NoContent();
}
[HttpPost("{id:guid}/reset-password")]
public async Task<IActionResult> ResetPassword(Guid id, [FromBody] ResetPasswordRequest request, CancellationToken ct)
{
await sender.Send(new ResetPasswordCommand(User.GetUserId(), id, request), ct);
return NoContent();
}
[HttpGet("list")]
public async Task<ActionResult<List<UserDto>>> GetList([FromQuery] string? q, CancellationToken ct)
{
var query = db.Users.AsQueryable();
if (!string.IsNullOrWhiteSpace(q))
{
var lower = q.Trim().ToLower();
query = query.Where(u => u.Username.ToLower().Contains(lower) || u.DisplayName.ToLower().Contains(lower));
}
var users = await query.OrderBy(u => u.DisplayName).ToListAsync(ct);
return Ok(mapper.Map<List<UserDto>>(users));
}
[HttpGet("{id:guid}/roles")]
public async Task<ActionResult<UserRoleDetailDto>> GetUserRoles(Guid id, CancellationToken ct)
{
await permissions.EnsureAsync(User.GetUserId(), "permissions", PermissionAction.View, ct);
var user = await db.Users
.Include(u => u.UserRoles)
.ThenInclude(ur => ur.Role)
.FirstOrDefaultAsync(u => u.Id == id, ct);
if (user is null) return NotFound("User not found");
var allRoles = await db.Roles.Include(r => r.Permissions).OrderBy(r => r.Name).ToListAsync(ct);
var assignedRoleIds = user.UserRoles.Select(ur => ur.RoleId).ToHashSet();
var assigned = allRoles.Where(r => assignedRoleIds.Contains(r.Id)).ToList();
var unassigned = allRoles.Where(r => !assignedRoleIds.Contains(r.Id)).ToList();
return Ok(new UserRoleDetailDto
{
UserId = user.Id,
Username = user.Username,
DisplayName = user.DisplayName,
AssignedRoles = mapper.Map<List<RoleDto>>(assigned),
UnassignedRoles = mapper.Map<List<RoleDto>>(unassigned)
});
}
[HttpPost("{id:guid}/roles")]
public async Task<IActionResult> AssignRole(Guid id, [FromBody] AssignRoleRequest req, CancellationToken ct)
{
await sender.Send(new AssignUserRoleCommand(User.GetUserId(), id, req.RoleId), ct);
return NoContent();
}
[HttpDelete("{id:guid}/roles/{roleId:guid}")]
public async Task<IActionResult> UnassignRole(Guid id, Guid roleId, CancellationToken ct)
{
await sender.Send(new UnassignUserRoleCommand(User.GetUserId(), id, roleId), ct);
return NoContent();
}
[HttpGet("{id:guid}/permissions")]
public async Task<ActionResult<List<MenuItemDto>>> GetUserPermissions(Guid id, CancellationToken ct)
{
await permissions.EnsureAsync(User.GetUserId(), "permissions", PermissionAction.View, ct);
var roleIds = await db.UserRoles.Where(ur => ur.UserId == id).Select(ur => ur.RoleId).ToListAsync(ct);
var permissionsList = await db.RolePermissions.Where(p => roleIds.Contains(p.RoleId)).ToListAsync(ct);
var merged = permissionsList.GroupBy(p => p.Screen).ToDictionary(
g => g.Key,
g => new
{
CanView = g.Any(p => p.CanView),
CanCreate = g.Any(p => p.CanCreate),
CanEdit = g.Any(p => p.CanEdit),
CanDelete = g.Any(p => p.CanDelete),
}
);
var res = ScreenCatalog.Screens.Select(s =>
{
merged.TryGetValue(s.Key, out var p);
return new MenuItemDto
{
Key = s.Key,
Label = s.Label,
Path = s.Path,
CanView = p?.CanView ?? false,
CanCreate = p?.CanCreate ?? false,
CanEdit = p?.CanEdit ?? false,
CanDelete = p?.CanDelete ?? false,
};
}).ToList();
return Ok(res);
}
}