feature: RBAC + Clinical Audit Logging

This commit is contained in:
voltsrage
2026-06-21 15:46:55 +08:00
parent a43db52813
commit 5af6ab490e
83 changed files with 4281 additions and 70 deletions
@@ -0,0 +1,62 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
/// <summary>
/// Clinical audit log query (Admin only).
/// </summary>
[ApiController]
[Route("api/v1/audit-logs")]
[Produces("application/json")]
[AuthorizePermission(ClinicalPermissions.AuditRead)]
public class AuditLogsController : ControllerBase
{
private readonly AppDbContext _db;
public AuditLogsController(AppDbContext db) => _db = db;
/// <summary>Query clinical audit logs with optional filters.</summary>
[HttpGet]
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
public async Task<IActionResult> List(
[FromQuery] string? entityType,
[FromQuery] Guid? entityId,
[FromQuery] Guid? userId,
[FromQuery] string? action,
[FromQuery] DateTimeOffset? from,
[FromQuery] DateTimeOffset? to,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50)
{
pageSize = Math.Clamp(pageSize, 1, 100);
var query = _db.ClinicalAuditLogs.AsNoTracking().AsQueryable();
if (!string.IsNullOrEmpty(entityType))
query = query.Where(a => a.EntityType == entityType);
if (entityId.HasValue)
query = query.Where(a => a.EntityId == entityId);
if (userId.HasValue)
query = query.Where(a => a.UserId == userId);
if (!string.IsNullOrEmpty(action))
query = query.Where(a => a.Action.ToDbString() == action);
if (from.HasValue)
query = query.Where(a => a.CreatedAt >= from);
if (to.HasValue)
query = query.Where(a => a.CreatedAt <= to);
var total = await query.CountAsync();
var items = await query
.OrderByDescending(a => a.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return Ok(ApiResponse<object>.Ok(new
{
items,
page,
pageSize,
totalCount = total,
totalPages = (int)Math.Ceiling(total / (double)pageSize)
}));
}
}