Files
social-media/backend/Modules/ContentItems/Handlers/UpdateContentItemStatus.cs
Jonathan Bourdon df3e602015
Some checks failed
Backend CI/CD / build_and_deploy (push) Has been cancelled
Frontend CI/CD / build_and_deploy (push) Has been cancelled
feat: pivot to social media workflow app
2026-04-24 12:58:35 -04:00

106 lines
3.1 KiB
C#

using Socialize.Infrastructure.Security;
using Socialize.Modules.ContentItems.Data;
using Socialize.Modules.Notifications.Contracts;
namespace Socialize.Modules.ContentItems.Handlers;
public record UpdateContentItemStatusRequest(string Status);
public class UpdateContentItemStatusRequestValidator
: Validator<UpdateContentItemStatusRequest>
{
public UpdateContentItemStatusRequestValidator()
{
RuleFor(x => x.Status).NotEmpty().MaximumLength(64);
}
}
public class UpdateContentItemStatusHandler(
AppDbContext dbContext,
AccessScopeService accessScopeService,
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",
"Approved",
"Rejected",
"Ready to publish",
"Published",
"Archived",
];
public override void Configure()
{
Post("/api/content-items/{id}/status");
Options(o => o.WithTags("Content Items"));
}
public override async Task HandleAsync(UpdateContentItemStatusRequest request, CancellationToken ct)
{
Guid id = Route<Guid>("id");
ContentItem? item = await dbContext.ContentItems.SingleOrDefaultAsync(candidate => candidate.Id == id, ct);
if (item is null)
{
await SendNotFoundAsync(ct);
return;
}
if (!accessScopeService.CanManageWorkspace(User, item.WorkspaceId))
{
await SendForbiddenAsync(ct);
return;
}
string normalizedStatus = request.Status.Trim();
if (!AllowedStatuses.Contains(normalizedStatus))
{
AddError(request => request.Status, "The requested status is not valid.");
await SendErrorsAsync(StatusCodes.Status400BadRequest, ct);
return;
}
item.Status = normalizedStatus;
await dbContext.SaveChangesAsync(ct);
await notificationEventWriter.WriteAsync(
new NotificationEventWriteModel(
item.WorkspaceId,
item.Id,
"content-item.status.updated",
"ContentItem",
item.Id,
$"Status changed to {item.Status} for {item.Title}.",
User.GetUserId(),
User.GetEmail(),
$$"""{"status":"{{item.Status}}"}"""),
ct);
ContentItemDetailDto dto = new(
item.Id,
item.WorkspaceId,
item.ClientId,
item.ProjectId,
item.Title,
item.PublicationMessage,
item.PublicationTargets,
item.Hashtags,
item.Status,
item.DueDate,
item.CurrentRevisionLabel,
item.CurrentRevisionNumber,
item.CreatedAt);
await SendOkAsync(dto, ct);
}
}