using FastEndpoints; using Microsoft.EntityFrameworkCore; using Socialize.Api.Data; using Socialize.Api.Infrastructure.Security; using Socialize.Api.Modules.Comments.Data; using Socialize.Api.Modules.ContentItems.Data; using Socialize.Api.Modules.Notifications.Contracts; namespace Socialize.Api.Modules.Comments.Handlers; public class ResolveCommentHandler( AppDbContext dbContext, AccessScopeService accessScopeService, INotificationEventWriter notificationEventWriter) : EndpointWithoutRequest { public override void Configure() { Post("/api/comments/{id}/resolve"); Options(o => o.WithTags("Comments")); } public override async Task HandleAsync(CancellationToken ct) { Guid id = Route("id"); Comment? comment = await dbContext.Comments.SingleOrDefaultAsync(candidate => candidate.Id == id, ct); if (comment is null) { await SendNotFoundAsync(ct); return; } ContentItem? contentItem = await dbContext.ContentItems .SingleOrDefaultAsync(candidate => candidate.Id == comment.ContentItemId, ct); if (contentItem is null) { await SendNotFoundAsync(ct); return; } bool canResolve = await accessScopeService.CanManageWorkspaceAsync(User, comment.WorkspaceId, ct) || await accessScopeService.CanContributeToCampaignAsync(User, contentItem.WorkspaceId, contentItem.ClientId, contentItem.CampaignId, ct); if (!canResolve) { await SendForbiddenAsync(ct); return; } comment.IsResolved = true; comment.ResolvedAt = comment.ResolvedAt ?? DateTimeOffset.UtcNow; await dbContext.SaveChangesAsync(ct); string? authorPortraitUrl = await dbContext.Users .Where(candidate => candidate.Id == comment.AuthorUserId) .Select(candidate => candidate.PortraitUrl) .SingleOrDefaultAsync(ct); await notificationEventWriter.WriteAsync( new NotificationEventWriteModel( comment.WorkspaceId, comment.ContentItemId, "comment.resolved", "Comment", comment.Id, $"{User.GetAlias() ?? User.GetName()} resolved a comment.", null, null, null), ct); CommentDto dto = new( comment.Id, comment.WorkspaceId, comment.ContentItemId, comment.ParentCommentId, comment.AuthorUserId, comment.AuthorDisplayName, comment.AuthorEmail, authorPortraitUrl, comment.Body, comment.IsResolved, comment.CreatedAt, comment.ResolvedAt); await SendOkAsync(dto, ct); } }