using Socialize.Infrastructure.Security; namespace Socialize.Modules.Approvals.Handlers; public record GetApprovalsRequest(Guid ContentItemId); public record ApprovalDecisionDto( Guid Id, Guid ApprovalRequestId, string Decision, string? Comment, Guid? DecidedByUserId, string DecidedByName, string DecidedByEmail, string? DecidedByPortraitUrl, DateTimeOffset CreatedAt); public record ApprovalRequestDto( Guid Id, Guid WorkspaceId, Guid ContentItemId, string Stage, string ReviewerName, string ReviewerEmail, Guid RequestedByUserId, DateTimeOffset? DueAt, string State, string AccessToken, DateTimeOffset SentAt, DateTimeOffset? CompletedAt, IReadOnlyCollection Decisions); public class GetApprovalsHandler( AppDbContext dbContext, AccessScopeService accessScopeService) : Endpoint> { public override void Configure() { Get("/api/approvals"); Options(o => o.WithTags("Approvals")); } public override async Task HandleAsync(GetApprovalsRequest request, CancellationToken ct) { ContentItem? item = await dbContext.ContentItems .SingleOrDefaultAsync(candidate => candidate.Id == request.ContentItemId, ct); if (item is null) { await SendNotFoundAsync(ct); return; } if (!accessScopeService.CanReviewContent(User, item.WorkspaceId, item.ClientId, item.ProjectId)) { await SendForbiddenAsync(ct); return; } List approvals = await dbContext.ApprovalRequests .Where(approval => approval.ContentItemId == request.ContentItemId) .OrderByDescending(approval => approval.SentAt) .ToListAsync(ct); List approvalIds = approvals .Select(approval => approval.Id) .ToList(); List decisions = await dbContext.ApprovalDecisions .Where(decision => approvalIds.Contains(decision.ApprovalRequestId)) .OrderByDescending(decision => decision.CreatedAt) .ToListAsync(ct); List decidedByUserIds = decisions .Where(decision => decision.DecidedByUserId.HasValue) .Select(decision => decision.DecidedByUserId!.Value) .Distinct() .ToList(); Dictionary decisionPortraits = await dbContext.Users .Where(user => decidedByUserIds.Contains(user.Id)) .ToDictionaryAsync(user => user.Id, user => user.PortraitUrl, ct); List dtos = approvals .Select(approval => new ApprovalRequestDto( approval.Id, approval.WorkspaceId, approval.ContentItemId, approval.Stage, approval.ReviewerName, approval.ReviewerEmail, approval.RequestedByUserId, approval.DueAt, approval.State, approval.AccessToken, approval.SentAt, approval.CompletedAt, decisions .Where(decision => decision.ApprovalRequestId == approval.Id) .Select(decision => new ApprovalDecisionDto( decision.Id, decision.ApprovalRequestId, decision.Decision, decision.Comment, decision.DecidedByUserId, decision.DecidedByName, decision.DecidedByEmail, decision.DecidedByUserId.HasValue ? decisionPortraits.GetValueOrDefault(decision.DecidedByUserId.Value) : null, decision.CreatedAt)) .ToList())) .ToList(); await SendOkAsync(dtos, ct); } }