106 lines
3.8 KiB
C#
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;
|
|
}
|
|
}
|