using FastEndpoints; using Microsoft.EntityFrameworkCore; using Socialize.Api.Data; using Socialize.Api.Infrastructure.Security; using Socialize.Api.Modules.Feedback.Contracts; using Socialize.Api.Modules.Feedback.Data; using Socialize.Api.Modules.Feedback.Services; namespace Socialize.Api.Modules.Feedback.Handlers; public record AddFeedbackCommentRequest(string Body); public class AddFeedbackCommentRequestValidator : Validator { public AddFeedbackCommentRequestValidator() { RuleFor(x => x.Body).NotEmpty().MaximumLength(8000); } } public class AddMyFeedbackCommentHandler( AppDbContext dbContext, FeedbackNotificationService notificationService) : Endpoint { public override void Configure() { Post("/api/my-feedback/{id}/comments"); Options(o => o.WithTags("Feedback")); } public override async Task HandleAsync(AddFeedbackCommentRequest request, CancellationToken ct) { Guid id = Route("id"); Guid reporterUserId = User.GetUserId(); FeedbackReport? report = await dbContext.FeedbackReports.SingleOrDefaultAsync(candidate => candidate.Id == id, ct); if (report is null || !FeedbackAccessRules.CanReporterComment(report, reporterUserId)) { await SendNotFoundAsync(ct); return; } DateTimeOffset now = DateTimeOffset.UtcNow; FeedbackComment comment = CreateComment(report.Id, reporterUserId, "Reporter", request.Body.Trim(), now); report.LastActivityAt = now; dbContext.FeedbackComments.Add(comment); await notificationService.AddReporterCommentNotificationsAsync(report, reporterUserId, ct); await dbContext.SaveChangesAsync(ct); await SendAsync(comment.ToTimelineDto(), StatusCodes.Status201Created, ct); } private FeedbackComment CreateComment(Guid reportId, Guid userId, string authorRole, string body, DateTimeOffset now) { return new FeedbackComment { Id = Guid.NewGuid(), FeedbackReportId = reportId, AuthorUserId = userId, AuthorDisplayName = User.GetAlias() ?? User.GetName(), AuthorEmail = User.GetEmail(), AuthorRole = authorRole, Body = body, CreatedAt = now, }; } }