Skip to content

Commit

Permalink
fix: purge should accept any content-type and no body (#540)
Browse files Browse the repository at this point in the history
Issue #538

---------

Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
  • Loading branch information
knuhau and oskogstad authored Mar 13, 2024
1 parent eabd708 commit 736fb59
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Purge;
public sealed class PurgeDialogCommand : IRequest<PurgeDialogResult>
{
public Guid Id { get; set; }
public Guid DialogId { get; set; }
public Guid? IfMatchDialogRevision { get; set; }
}

[GenerateOneOf]
public partial class PurgeDialogResult : OneOfBase<Success, EntityNotFound, ConcurrencyError>;
public partial class PurgeDialogResult : OneOfBase<Success, EntityNotFound, ConcurrencyError, ValidationError>;

internal sealed class PurgeDialogCommandHandler : IRequestHandler<PurgeDialogCommand, PurgeDialogResult>
{
Expand All @@ -43,11 +43,11 @@ public async Task<PurgeDialogResult> Handle(PurgeDialogCommand request, Cancella
.Include(x => x.Elements)
.Include(x => x.Activities)
.Where(x => resourceIds.Contains(x.ServiceResource))
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken);
.FirstOrDefaultAsync(x => x.Id == request.DialogId, cancellationToken);

if (dialog is null)
{
return new EntityNotFound<DialogEntity>(request.Id);
return new EntityNotFound<DialogEntity>(request.DialogId);
}

_db.Dialogs.HardRemove(dialog);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using FluentValidation;

namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Purge;

internal sealed class PurgeDialogCommandValidator : AbstractValidator<PurgeDialogCommand>
{
public PurgeDialogCommandValidator()
{
RuleFor(x => x.DialogId)
.NotEqual(default(Guid));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ public PurgeDialogEndpoint(ISender sender)
public override void Configure()
{
Post("dialogs/{dialogId}/actions/purge");
RequestBinder(new PurgeDialogRequestBinder());
Policies(AuthorizationPolicy.ServiceProvider);
Group<ServiceOwnerGroup>();

Description(b => b
.OperationId("PurgeDialog")
.Accepts<PurgeDialogRequest>()
.ProducesOneOf(
StatusCodes.Status204NoContent,
StatusCodes.Status404NotFound,
Expand All @@ -33,21 +35,22 @@ public override void Configure()

public override async Task HandleAsync(PurgeDialogRequest req, CancellationToken ct)
{
var command = new PurgeDialogCommand { Id = req.DialogId, IfMatchDialogRevision = req.IfMatchDialogRevision };
var command = new PurgeDialogCommand { DialogId = req.DialogId, IfMatchDialogRevision = req.IfMatchDialogRevision };
var result = await _sender.Send(command, ct);
await result.Match(
success => SendNoContentAsync(ct),
notFound => this.NotFoundAsync(notFound, ct),
concurrencyError => this.PreconditionFailed(ct));
concurrencyError => this.PreconditionFailed(ct),
validationError => this.BadRequestAsync(validationError, ct));
}
}

public sealed class PurgeDialogRequest
{
public Guid DialogId { get; set; }
public Guid DialogId { get; init; }

[FromHeader(headerName: Constants.IfMatch, isRequired: false, removeFromSchema: true)]
public Guid? IfMatchDialogRevision { get; set; }
public Guid? IfMatchDialogRevision { get; init; }
}

public sealed class PurgeDialogEndpointSummary : Summary<PurgeDialogEndpoint>
Expand All @@ -67,3 +70,22 @@ Deletes a given dialog (hard delete). For more information see the documentation
Responses[StatusCodes.Status412PreconditionFailed] = Constants.SwaggerSummary.RevisionMismatch;
}
}

// Custom request binder to avoid attempted automatic deserialization of the Request body if the content type is application/json
public class PurgeDialogRequestBinder : IRequestBinder<PurgeDialogRequest>
{
public ValueTask<PurgeDialogRequest> BindAsync(BinderContext ctx, CancellationToken ct)
{
if (!Guid.TryParse(ctx.HttpContext.Request.RouteValues["dialogId"]?.ToString()!, out var dialogId))
return ValueTask.FromResult(new PurgeDialogRequest());

ctx.HttpContext.Request.Headers.TryGetValue(Constants.IfMatch, out var revisionHeader);
var revisionFound = Guid.TryParse(revisionHeader, out var revision);

return ValueTask.FromResult(new PurgeDialogRequest
{
DialogId = dialogId,
IfMatchDialogRevision = revisionFound ? revision : null
});
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Diagnostics;
using System.Reflection;
using Digdir.Library.Entity.Abstractions.Features.Aggregate;
using Digdir.Library.Entity.Abstractions.Features.SoftDeletable;
using Digdir.Library.Entity.Abstractions.Features.Updatable;
using Digdir.Library.Entity.Abstractions.Features.Versionable;
using Digdir.Library.Entity.EntityFrameworkCore.Features.SoftDeletable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ public async Task Creates_DialogDeletedEvent_When_Dialog_Purged()
// Act
var purgeCommand = new PurgeDialogCommand
{
Id = dialogId
DialogId = dialogId
};

await Application.Send(purgeCommand);
Expand Down Expand Up @@ -273,7 +273,7 @@ public async Task Creates_DialogElementDeleted_CloudEvent_When_Purging_Dialog()
// Act
var purgeCommand = new PurgeDialogCommand
{
Id = dialogId
DialogId = dialogId
};

await Application.Send(purgeCommand);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public async Task Purge_RemovesDialog_FromDatabase()
createResponse.TryPickT0(out _, out _).Should().BeTrue();

// Act
var purgeCommand = new PurgeDialogCommand { Id = expectedDialogId };
var purgeCommand = new PurgeDialogCommand { DialogId = expectedDialogId };
var purgeResponse = await Application.Send(purgeCommand);

// Assert
Expand All @@ -47,7 +47,7 @@ public async Task Purge_ReturnsConcurrencyError_OnIfMatchDialogRevisionMismatch(
createResponse.TryPickT0(out _, out _).Should().BeTrue();

// Act
var purgeCommand = new PurgeDialogCommand { Id = expectedDialogId, IfMatchDialogRevision = Guid.NewGuid() };
var purgeCommand = new PurgeDialogCommand { DialogId = expectedDialogId, IfMatchDialogRevision = Guid.NewGuid() };
var purgeResponse = await Application.Send(purgeCommand);

// Assert
Expand All @@ -61,7 +61,7 @@ public async Task Purge_ReturnsNotFound_OnNonExistingDialog()
var expectedDialogId = Guid.NewGuid();
var createCommand = DialogGenerator.GenerateFakeDialog(id: expectedDialogId);
await Application.Send(createCommand);
var purgeCommand = new PurgeDialogCommand { Id = expectedDialogId };
var purgeCommand = new PurgeDialogCommand { DialogId = expectedDialogId };
await Application.Send(purgeCommand);

// Act
Expand Down

0 comments on commit 736fb59

Please sign in to comment.