102 lines
4.0 KiB
C#
102 lines
4.0 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using ROLAC.API.Data.Logging;
|
|
using ROLAC.API.DTOs.Logging;
|
|
using ROLAC.API.DTOs.Shared;
|
|
using ROLAC.API.Entities.Logging;
|
|
|
|
namespace ROLAC.API.Services.Logging;
|
|
|
|
public interface IAuditLogQueryService
|
|
{
|
|
Task<PagedResult<AuditLogListItemDto>> GetPagedAsync(AuditLogQuery query);
|
|
Task<AuditLogDetailDto?> GetByIdAsync(long id);
|
|
AuditCatalogDto GetCatalog();
|
|
}
|
|
|
|
/// <summary>Read-only, paged access to the AuditLogs table via the dedicated LogDbContext.</summary>
|
|
public sealed class AuditLogQueryService : IAuditLogQueryService
|
|
{
|
|
private readonly LogDbContext _db;
|
|
|
|
public AuditLogQueryService(LogDbContext db) => _db = db;
|
|
|
|
public async Task<PagedResult<AuditLogListItemDto>> GetPagedAsync(AuditLogQuery query)
|
|
{
|
|
var page = Math.Max(1, query.Page);
|
|
var pageSize = Math.Clamp(query.PageSize, 1, 200);
|
|
|
|
var rows = _db.AuditLogs.AsNoTracking().AsQueryable();
|
|
|
|
if (query.From is not null) rows = rows.Where(l => l.Timestamp >= query.From);
|
|
if (query.To is not null) rows = rows.Where(l => l.Timestamp <= query.To);
|
|
if (query.MinLevel is not null) rows = rows.Where(l => l.Level >= query.MinLevel);
|
|
if (!string.IsNullOrWhiteSpace(query.Category)) rows = rows.Where(l => l.Category == query.Category);
|
|
if (!string.IsNullOrWhiteSpace(query.Action)) rows = rows.Where(l => l.Action == query.Action);
|
|
if (!string.IsNullOrWhiteSpace(query.EntityName)) rows = rows.Where(l => l.EntityName == query.EntityName);
|
|
if (!string.IsNullOrWhiteSpace(query.EntityId)) rows = rows.Where(l => l.EntityId == query.EntityId);
|
|
if (!string.IsNullOrWhiteSpace(query.UserId)) rows = rows.Where(l => l.UserId == query.UserId);
|
|
if (!string.IsNullOrWhiteSpace(query.Search))
|
|
{
|
|
var term = query.Search.Trim().ToLower();
|
|
rows = rows.Where(l =>
|
|
(l.Summary != null && l.Summary.ToLower().Contains(term)) ||
|
|
(l.EntityName != null && l.EntityName.ToLower().Contains(term)) ||
|
|
(l.UserEmail != null && l.UserEmail.ToLower().Contains(term)));
|
|
}
|
|
|
|
var total = await rows.CountAsync();
|
|
var items = await rows
|
|
.OrderByDescending(l => l.Timestamp)
|
|
.Skip((page - 1) * pageSize).Take(pageSize)
|
|
.Select(l => new AuditLogListItemDto
|
|
{
|
|
Id = l.Id,
|
|
Timestamp = l.Timestamp,
|
|
Level = l.Level.ToString(),
|
|
Action = l.Action,
|
|
Category = l.Category,
|
|
EntityName = l.EntityName,
|
|
EntityId = l.EntityId,
|
|
Summary = l.Summary,
|
|
UserId = l.UserId,
|
|
UserEmail = l.UserEmail,
|
|
})
|
|
.ToListAsync();
|
|
|
|
return new PagedResult<AuditLogListItemDto>
|
|
{
|
|
Items = items, TotalCount = total, Page = page, PageSize = pageSize,
|
|
};
|
|
}
|
|
|
|
public async Task<AuditLogDetailDto?> GetByIdAsync(long id)
|
|
{
|
|
return await _db.AuditLogs.AsNoTracking()
|
|
.Where(l => l.Id == id)
|
|
.Select(l => new AuditLogDetailDto
|
|
{
|
|
Id = l.Id,
|
|
Timestamp = l.Timestamp,
|
|
Level = l.Level.ToString(),
|
|
Action = l.Action,
|
|
Category = l.Category,
|
|
EntityName = l.EntityName,
|
|
EntityId = l.EntityId,
|
|
Summary = l.Summary,
|
|
UserId = l.UserId,
|
|
UserEmail = l.UserEmail,
|
|
Changes = l.Changes,
|
|
IpAddress = l.IpAddress,
|
|
CorrelationId = l.CorrelationId,
|
|
})
|
|
.FirstOrDefaultAsync();
|
|
}
|
|
|
|
public AuditCatalogDto GetCatalog() => new()
|
|
{
|
|
Categories = AuditCategories.All,
|
|
Actions = AuditActions.All,
|
|
Levels = Enum.GetNames<LogLevelEnum>(),
|
|
};
|
|
}
|