Files
social-media/backend/src/Socialize.Api/Modules/Feedback/Handlers/SubmitFeedback.cs

106 lines
3.8 KiB
C#

using FastEndpoints;
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 SubmitFeedbackRequest(
string Type,
string Description,
string SubmittedPath,
string? BrowserUserAgent,
int? ViewportWidth,
int? ViewportHeight,
string? AppVersion,
Guid? WorkspaceId,
string? WorkspaceName,
Guid? ClientId,
string? ClientName,
Guid? ProjectId,
string? ProjectName,
Guid? ContentItemId,
string? ContentItemTitle);
public class SubmitFeedbackRequestValidator
: Validator<SubmitFeedbackRequest>
{
public SubmitFeedbackRequestValidator()
{
RuleFor(x => x.Type).NotEmpty().MaximumLength(32);
RuleFor(x => x.Description).NotEmpty().MaximumLength(8000);
RuleFor(x => x.SubmittedPath).NotEmpty().MaximumLength(2048);
RuleFor(x => x.BrowserUserAgent).MaximumLength(1024);
RuleFor(x => x.AppVersion).MaximumLength(128);
RuleFor(x => x.WorkspaceName).MaximumLength(256);
RuleFor(x => x.ClientName).MaximumLength(256);
RuleFor(x => x.ProjectName).MaximumLength(256);
RuleFor(x => x.ContentItemTitle).MaximumLength(256);
RuleFor(x => x.ViewportWidth).GreaterThan(0).When(x => x.ViewportWidth.HasValue);
RuleFor(x => x.ViewportHeight).GreaterThan(0).When(x => x.ViewportHeight.HasValue);
}
}
public class SubmitFeedbackHandler(
AppDbContext dbContext,
FeedbackNotificationService notificationService)
: Endpoint<SubmitFeedbackRequest, FeedbackReportDto>
{
public override void Configure()
{
Post("/api/feedback");
Options(o => o.WithTags("Feedback"));
}
public override async Task HandleAsync(SubmitFeedbackRequest request, CancellationToken ct)
{
if (!FeedbackRules.TryParseType(request.Type, out FeedbackType type))
{
AddError(request => request.Type, "The selected feedback type is not valid.");
await SendErrorsAsync(StatusCodes.Status400BadRequest, ct);
return;
}
DateTimeOffset now = DateTimeOffset.UtcNow;
FeedbackReport report = new()
{
Id = Guid.NewGuid(),
Type = type,
Status = FeedbackStatus.New,
Description = request.Description.Trim(),
ReporterUserId = User.GetUserId(),
ReporterDisplayName = User.GetAlias() ?? User.GetName(),
ReporterEmail = User.GetEmail(),
SubmittedPath = request.SubmittedPath.Trim(),
BrowserUserAgent = NormalizeOptional(request.BrowserUserAgent),
ViewportWidth = request.ViewportWidth,
ViewportHeight = request.ViewportHeight,
AppVersion = NormalizeOptional(request.AppVersion),
WorkspaceId = request.WorkspaceId,
WorkspaceName = NormalizeOptional(request.WorkspaceName),
ClientId = request.ClientId,
ClientName = NormalizeOptional(request.ClientName),
ProjectId = request.ProjectId,
ProjectName = NormalizeOptional(request.ProjectName),
ContentItemId = request.ContentItemId,
ContentItemTitle = NormalizeOptional(request.ContentItemTitle),
CreatedAt = now,
LastActivityAt = now,
};
dbContext.FeedbackReports.Add(report);
await notificationService.AddNewReportNotificationsAsync(report, ct);
await dbContext.SaveChangesAsync(ct);
await SendAsync(report.ToDto(), StatusCodes.Status201Created, ct);
}
private static string? NormalizeOptional(string? value)
{
string? normalized = value?.Trim();
return string.IsNullOrWhiteSpace(normalized) ? null : normalized;
}
}