78 lines
3.8 KiB
C#
78 lines
3.8 KiB
C#
using System.Security.Claims;
|
|
using ItWorx.KnowledgeHub.Api.Authorization;
|
|
using ItWorx.KnowledgeHub.Api.Security;
|
|
using ItWorx.KnowledgeHub.Application.Migration;
|
|
using ItWorx.KnowledgeHub.Application.Migration.UseCases;
|
|
using ItWorx.KnowledgeHub.Contracts.Errors;
|
|
using ItWorx.KnowledgeHub.Contracts.Migration;
|
|
using Microsoft.AspNetCore.Http.HttpResults;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace ItWorx.KnowledgeHub.Api.Endpoints;
|
|
|
|
/// <summary>
|
|
/// Explicit administrative purge for an externally published source batch. It accepts
|
|
/// only a reviewed list of target page identifiers and refuses ambiguous scope before
|
|
/// it can mutate production data.
|
|
/// </summary>
|
|
public static class SourceBatchPurgeEndpoints
|
|
{
|
|
public static IEndpointRouteBuilder MapSourceBatchPurgeEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
var group = app.MapGroup("/api/v1/admin/source-batches/purge")
|
|
.WithTags("Source batch purge")
|
|
.RequireAuthorization(AuthorizationPolicies.RequireAdministrator);
|
|
|
|
group.MapPost("/dry-run", DryRunAsync).AddEndpointFilter<AntiforgeryEndpointFilter>();
|
|
group.MapPost("/execute", ExecuteAsync).AddEndpointFilter<AntiforgeryEndpointFilter>();
|
|
return app;
|
|
}
|
|
|
|
private static async Task<Ok<SourceBatchPurgeDryRunResponse>> DryRunAsync(
|
|
[FromBody] SourceBatchPurgeRequest request,
|
|
PurgeSourceBatchUseCase useCase,
|
|
CancellationToken cancellationToken) =>
|
|
TypedResults.Ok(ToResponse(await useCase.DryRunAsync(request.BatchId, request.Source, request.Pages, cancellationToken)));
|
|
|
|
private static async Task<Results<Ok<SourceBatchPurgeResponse>, ProblemHttpResult>> ExecuteAsync(
|
|
[FromBody] ExecuteSourceBatchPurgeRequest request,
|
|
PurgeSourceBatchUseCase useCase,
|
|
ClaimsPrincipal principal,
|
|
HttpContext httpContext,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var correlationId = httpContext.Items[CorrelationIdMiddleware.ItemKey] as string;
|
|
var result = await useCase.ExecuteAsync(
|
|
new PurgeSourceBatchCommand(
|
|
request.BatchId, request.Source, request.Pages, request.ConfirmationHash,
|
|
Guid.Parse(principal.FindFirstValue(ClaimTypes.NameIdentifier)!), correlationId),
|
|
cancellationToken);
|
|
|
|
if (!result.Succeeded)
|
|
{
|
|
return TypedResults.Problem(
|
|
statusCode: StatusCodes.Status409Conflict,
|
|
type: ProblemTypes.Validation,
|
|
title: result.StaleDryRun ? "Dry-run is niet langer actueel." : "Bronbatch voldoet niet aan de veiligheidscontroles.",
|
|
detail: result.StaleDryRun
|
|
? "Voer opnieuw een dry-run uit; de geselecteerde gegevens zijn intussen gewijzigd."
|
|
: string.Join(" ", result.Inspection.Blockers));
|
|
}
|
|
|
|
return TypedResults.Ok(new SourceBatchPurgeResponse(
|
|
"purged", ToResponse(result.Inspection), result.RemovedPages, result.RemovedRevisions,
|
|
result.RemovedDrafts, result.RemovedLinks, result.RemovedAttachmentUsages,
|
|
result.RemovedAttachmentReferences, result.RemovedImportJobs, result.RemovedImportItems,
|
|
result.RemovedProvenanceRecords, result.RemovedBlobs));
|
|
}
|
|
|
|
private static SourceBatchPurgeDryRunResponse ToResponse(SourceBatchPurgeInspection value) =>
|
|
new(
|
|
value.IsSafe, value.ConfirmationHash, value.PageCount, value.DescendantPageCount,
|
|
value.RevisionCount, value.DraftCount, value.LinkCount, value.AttachmentUsageCount,
|
|
value.AttachmentReferenceCount, value.OrphanedBlobCount, value.SharedBlobCount,
|
|
value.ImportJobCount, value.ImportItemCount, value.ProvenanceCount,
|
|
value.SourceTagAssignmentCount, value.SearchIndexRecordCount,
|
|
value.GeneratedSourceDerivedPageCount, value.RetainedPageCount, value.Blockers);
|
|
}
|