@@ -0,0 +1,101 @@
|
||||
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>(),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user