chore: add missing multi-level editor for approval workflow, rename projects to campaings.

This commit is contained in:
2026-05-01 14:23:37 -04:00
parent 5077f557f4
commit 884ca4b96d
148 changed files with 11567 additions and 1383 deletions

View File

@@ -2,8 +2,10 @@ using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using Socialize.Api.Data;
using Socialize.Api.Infrastructure.Security;
using Socialize.Api.Modules.Approvals.Services;
using Socialize.Api.Modules.ContentItems.Data;
using Socialize.Api.Modules.Notifications.Contracts;
using Socialize.Api.Modules.Workspaces.Data;
namespace Socialize.Api.Modules.ContentItems.Handlers;
@@ -21,24 +23,18 @@ public class UpdateContentItemStatusRequestValidator
public class UpdateContentItemStatusHandler(
AppDbContext dbContext,
AccessScopeService accessScopeService,
ApprovalWorkflowRuntimeService approvalWorkflowRuntimeService,
INotificationEventWriter notificationEventWriter)
: Endpoint<UpdateContentItemStatusRequest, ContentItemDetailDto>
{
private static readonly HashSet<string> AllowedStatuses =
[
"Draft",
"In internal review",
"Changes requested internally",
"Internal changes in progress",
"Ready for client review",
"In client review",
"Changes requested by client",
"Client changes in progress",
"In production",
"In approval",
"Approved",
"Rejected",
"Ready to publish",
"Scheduled",
"Published",
"Archived",
];
public override void Configure()
@@ -72,7 +68,64 @@ public class UpdateContentItemStatusHandler(
return;
}
item.Status = normalizedStatus;
Workspace? workspace = await dbContext.Workspaces.SingleOrDefaultAsync(candidate => candidate.Id == item.WorkspaceId, ct);
if (workspace is null)
{
await SendNotFoundAsync(ct);
return;
}
if (normalizedStatus == "In approval" && workspace.ApprovalMode == ApprovalModes.MultiLevel)
{
ApprovalWorkflowStartResult startResult = await approvalWorkflowRuntimeService.StartMultiLevelWorkflowAsync(
item,
workspace,
User.GetUserId(),
ct);
if (!startResult.Succeeded)
{
AddError(request => request.Status, startResult.ErrorMessage ?? "The approval workflow could not be started.");
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
return;
}
}
else if (ApprovalWorkflowRules.IsApprovalCompletionStatus(normalizedStatus) &&
ApprovalWorkflowRules.BlocksManualApprovedOrScheduledStatus(workspace.ApprovalMode))
{
if (workspace.ApprovalMode == ApprovalModes.MultiLevel)
{
bool hasCompletedWorkflow = await approvalWorkflowRuntimeService.HasCompletedMultiLevelWorkflowAsync(item.Id, ct);
if (!hasCompletedWorkflow)
{
AddError(request => request.Status, "This workspace requires the multi-level approval workflow to complete before content can be approved or scheduled.");
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
return;
}
}
else
{
bool hasApprovedDecision = await dbContext.ApprovalRequests.AnyAsync(
approval => approval.ContentItemId == item.Id &&
approval.WorkspaceId == item.WorkspaceId &&
approval.State == "Approved" &&
approval.CompletedAt.HasValue,
ct);
if (!hasApprovedDecision)
{
AddError(request => request.Status, "This workspace requires approval before content can be approved or scheduled.");
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
return;
}
}
}
if (item.Status != "In approval" || normalizedStatus != "In approval")
{
item.Status = normalizedStatus;
}
await dbContext.SaveChangesAsync(ct);
await notificationEventWriter.WriteAsync(
@@ -92,7 +145,7 @@ public class UpdateContentItemStatusHandler(
item.Id,
item.WorkspaceId,
item.ClientId,
item.ProjectId,
item.CampaignId,
item.Title,
item.PublicationMessage,
item.PublicationTargets,