using FastEndpoints;
using KArtSell.BuildingBlocks.Time;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace KArtSell.Modules.ModelOperations.Compliance;
///
/// Submit GDPR right-to-be-forgotten request.
/// POST /compliance/gdpr-request
///
public class SubmitGdprRequestDto
{
public Guid CustomerId { get; set; }
public string Reason { get; set; } = "Right to be forgotten (GDPR Article 17)";
}
public class GdprRequestResponseDto
{
public Guid GdprTrackingId { get; set; }
public string Status { get; set; } = "IN_PROGRESS";
public DateTime EstimatedCompletion { get; set; }
public string Message { get; set; } = string.Empty;
}
public class SubmitGdprRequestEndpoint : Endpoint
{
private readonly ProcessGdprRequestHandler _handler;
private readonly IClock _clock;
private readonly ILogger _logger;
public SubmitGdprRequestEndpoint(ProcessGdprRequestHandler handler, IClock clock, ILogger logger)
{
_handler = handler;
_clock = clock;
_logger = logger;
}
public override void Configure()
{
Post("/compliance/gdpr-request");
AllowAnonymous(); // RBAC enforced at handler level (Data Admin/Compliance Officer role)
Summary(x =>
{
x.Summary = "Submit GDPR Request";
x.Description = "Submit right-to-be-forgotten request for customer data redaction";
});
}
public override async Task HandleAsync(SubmitGdprRequestDto req, CancellationToken ct)
{
try
{
var trackingId = Guid.NewGuid();
var now = _clock.UtcNow.UtcDateTime;
var correlationId = HttpContext.Request.Headers.TryGetValue("X-Correlation-ID", out var header)
? Guid.Parse(header.ToString())
: Guid.NewGuid();
var command = new ProcessGdprRequestCommand
{
TrackingId = trackingId,
CustomerId = req.CustomerId,
RequestDate = now,
Reason = req.Reason,
CorrelationId = correlationId
};
await _handler.Handle(command, ct);
var response = new GdprRequestResponseDto
{
GdprTrackingId = trackingId,
Status = "IN_PROGRESS",
EstimatedCompletion = now.AddHours(24),
Message = $"GDPR request {trackingId} submitted. Redaction will complete within 24 hours."
};
await Send.ResponseAsync(response, StatusCodes.Status202Accepted, ct);
_logger.LogInformation(
"GDPR request {TrackingId} submitted for customer {CustomerId}",
trackingId, req.CustomerId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to submit GDPR request for customer {CustomerId}", req.CustomerId);
await Send.ResponseAsync(
new GdprRequestResponseDto { Message = "Failed to submit request" },
StatusCodes.Status500InternalServerError,
ct);
}
}
}