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 CancelMyFeedbackRequest(string? Reason); public class CancelMyFeedbackRequestValidator : Validator { public CancelMyFeedbackRequestValidator() { RuleFor(x => x.Reason).MaximumLength(2000); } } public class CancelMyFeedbackHandler(AppDbContext dbContext) : Endpoint { public override void Configure() { Post("/api/my-feedback/{id}/cancel"); Options(o => o.WithTags("Feedback")); } public override async Task HandleAsync(CancelMyFeedbackRequest request, CancellationToken ct) { Guid id = Route("id"); Guid reporterUserId = User.GetUserId(); FeedbackReport? report = await dbContext.FeedbackReports .Include(candidate => candidate.Tags) .Include(candidate => candidate.Screenshot) .SingleOrDefaultAsync( candidate => candidate.Id == id && candidate.ReporterUserId == reporterUserId, ct); if (report is null) { await SendNotFoundAsync(ct); return; } if (!FeedbackAccessRules.CanReporterCancel(report, reporterUserId)) { AddError("The feedback report cannot be cancelled."); await SendErrorsAsync(StatusCodes.Status400BadRequest, ct); return; } DateTimeOffset now = DateTimeOffset.UtcNow; FeedbackStatus previousStatus = report.Status; report.Status = FeedbackStatus.Cancelled; report.CancelledAt = now; report.CancelledByUserId = reporterUserId; report.CancellationReason = string.IsNullOrWhiteSpace(request.Reason) ? null : request.Reason.Trim(); report.LastActivityAt = now; report.ActivityEntries.Add(new FeedbackActivityEntry { Id = Guid.NewGuid(), FeedbackReportId = report.Id, ActorUserId = reporterUserId, ActorDisplayName = User.GetAlias() ?? User.GetName(), ActorEmail = User.GetEmail(), ActivityType = FeedbackActivityTypes.Cancelled, FromValue = previousStatus.ToFeedbackDisplayString(), ToValue = FeedbackStatus.Cancelled.ToFeedbackDisplayString(), Note = report.CancellationReason, CreatedAt = now, }); await dbContext.SaveChangesAsync(ct); await SendOkAsync(report.ToDto(), ct); } }