118 lines
4.0 KiB
C#
118 lines
4.0 KiB
C#
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<ApprovalDecisionDto> Decisions);
|
|
|
|
public class GetApprovalsHandler(
|
|
AppDbContext dbContext,
|
|
AccessScopeService accessScopeService)
|
|
: Endpoint<GetApprovalsRequest, IReadOnlyCollection<ApprovalRequestDto>>
|
|
{
|
|
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<ApprovalRequest> approvals = await dbContext.ApprovalRequests
|
|
.Where(approval => approval.ContentItemId == request.ContentItemId)
|
|
.OrderByDescending(approval => approval.SentAt)
|
|
.ToListAsync(ct);
|
|
|
|
List<Guid> approvalIds = approvals
|
|
.Select(approval => approval.Id)
|
|
.ToList();
|
|
|
|
List<ApprovalDecision> decisions = await dbContext.ApprovalDecisions
|
|
.Where(decision => approvalIds.Contains(decision.ApprovalRequestId))
|
|
.OrderByDescending(decision => decision.CreatedAt)
|
|
.ToListAsync(ct);
|
|
|
|
List<Guid> decidedByUserIds = decisions
|
|
.Where(decision => decision.DecidedByUserId.HasValue)
|
|
.Select(decision => decision.DecidedByUserId!.Value)
|
|
.Distinct()
|
|
.ToList();
|
|
|
|
Dictionary<Guid, string?> decisionPortraits = await dbContext.Users
|
|
.Where(user => decidedByUserIds.Contains(user.Id))
|
|
.ToDictionaryAsync(user => user.Id, user => user.PortraitUrl, ct);
|
|
|
|
List<ApprovalRequestDto> 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);
|
|
}
|
|
}
|