Skip to content

Commit 2498b0a

Browse files
authored
fix: Return 410 Gone when updating deleted dialog (#464)
1 parent 5e55c34 commit 2498b0a

File tree

9 files changed

+34
-4
lines changed

9 files changed

+34
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using FluentValidation.Results;
2+
3+
namespace Digdir.Domain.Dialogporten.Application.Common.ReturnTypes;
4+
5+
public record BadRequest(List<string> Reasons)
6+
{
7+
private const string BadRequestMessage = "BadRequest";
8+
9+
public BadRequest(params string[] reasons) : this(reasons.ToList()) { }
10+
11+
public List<ValidationFailure> ToValidationResults() =>
12+
Reasons.Select(x => new ValidationFailure(BadRequestMessage, x)).ToList();
13+
}

src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public sealed class UpdateDialogCommand : IRequest<UpdateDialogResult>
2424
}
2525

2626
[GenerateOneOf]
27-
public partial class UpdateDialogResult : OneOfBase<Success, EntityNotFound, ValidationError, DomainError, ConcurrencyError>;
27+
public partial class UpdateDialogResult : OneOfBase<Success, EntityNotFound, BadRequest, ValidationError, DomainError, ConcurrencyError>;
2828

2929
internal sealed class UpdateDialogCommandHandler : IRequestHandler<UpdateDialogCommand, UpdateDialogResult>
3030
{
@@ -67,6 +67,7 @@ public async Task<UpdateDialogResult> Handle(UpdateDialogCommand request, Cancel
6767
.ThenInclude(x => x.Title!.Localizations)
6868
.Include(x => x.ApiActions)
6969
.ThenInclude(x => x.Endpoints)
70+
.IgnoreQueryFilters()
7071
.Where(x => resourceIds.Contains(x.ServiceResource))
7172
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken);
7273

@@ -75,6 +76,13 @@ public async Task<UpdateDialogResult> Handle(UpdateDialogCommand request, Cancel
7576
return new EntityNotFound<DialogEntity>(request.Id);
7677
}
7778

79+
if (dialog.Deleted)
80+
{
81+
// TODO: When restoration is implemented, add a hint to the error message.
82+
// https://github.com/digdir/dialogporten/pull/406
83+
return new BadRequest($"Entity '{nameof(DialogEntity)}' with key '{request.Id}' is removed, and cannot be updated.");
84+
}
85+
7886
// Update primitive properties
7987
_mapper.Map(request.Dto, dialog);
8088
ValidateTimeFields(dialog);

src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ public static Task BadRequestAsync(this IEndpoint ep, ValidationError failure, C
1010
=> ep.BadRequestAsync(failure.Errors, cancellationToken);
1111
public static Task BadRequestAsync(this IEndpoint ep, IEnumerable<ValidationFailure> failures, CancellationToken cancellationToken = default)
1212
=> ep.HttpContext.Response.SendErrorsAsync(failures.ToList() ?? [], StatusCodes.Status400BadRequest, cancellation: cancellationToken);
13+
public static Task BadRequestAsync(this IEndpoint ep, BadRequest badRequest, CancellationToken cancellationToken = default)
14+
=> ep.HttpContext.Response.SendErrorsAsync(
15+
badRequest.ToValidationResults(),
16+
cancellation: cancellationToken);
1317

1418
public static Task PreconditionFailed(this IEndpoint ep, CancellationToken cancellationToken = default)
1519
=> ep.HttpContext.Response.SendErrorsAsync([], StatusCodes.Status412PreconditionFailed, cancellation: cancellationToken);

src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/CreateDialogActivityEndpoint.cs

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public override async Task HandleAsync(CreateDialogActivityRequest req, Cancella
6666
await result.Match(
6767
success => SendCreatedAtAsync<GetDialogActivityEndpoint>(new GetDialogActivityQuery { DialogId = dialog.Id, ActivityId = req.Id.Value }, req.Id, cancellation: ct),
6868
notFound => this.NotFoundAsync(notFound, ct),
69+
badRequest => this.BadRequestAsync(badRequest, ct),
6970
validationError => this.BadRequestAsync(validationError, ct),
7071
domainError => this.UnprocessableEntityAsync(domainError, ct),
7172
concurrencyError => this.PreconditionFailed(cancellationToken: ct));

src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/CreateDialogElementEndpoint.cs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public override async Task HandleAsync(CreateDialogElementRequest req, Cancellat
6262
await result.Match(
6363
success => SendCreatedAtAsync<GetDialogElementEndpoint>(new GetDialogElementQuery { DialogId = dialog.Id, ElementId = req.Id.Value }, req.Id, cancellation: ct),
6464
notFound => this.NotFoundAsync(notFound, ct),
65+
badRequest => this.BadRequestAsync(badRequest, ct),
6566
validationError => this.BadRequestAsync(validationError, ct),
6667
domainError => this.UnprocessableEntityAsync(domainError, ct),
6768
concurrencyError => this.PreconditionFailed(cancellationToken: ct));

src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/DeleteDialogElementEndpoint.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public override async Task HandleAsync(DeleteDialogElementRequest req, Cancellat
7070
await result.Match(
7171
success => SendNoContentAsync(ct),
7272
notFound => this.NotFoundAsync(notFound, ct),
73+
badRequest => this.BadRequestAsync(badRequest, ct),
7374
validationError => this.BadRequestAsync(validationError, ct),
7475
domainError => this.UnprocessableEntityAsync(domainError, ct),
7576
concurrencyError => this.PreconditionFailed(cancellationToken: ct));
@@ -102,4 +103,3 @@ Deletes a given dialog element (hard delete). For more information see the docum
102103
Responses[StatusCodes.Status412PreconditionFailed] = Constants.SwaggerSummary.RevisionMismatch;
103104
}
104105
}
105-

src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/UpdateDialogElementEndpoint.cs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ await this.NotFoundAsync(
7272
await result.Match(
7373
success => SendNoContentAsync(ct),
7474
notFound => this.NotFoundAsync(notFound, ct),
75+
badRequest => this.BadRequestAsync(badRequest, ct),
7576
validationError => this.BadRequestAsync(validationError, ct),
7677
domainError => this.UnprocessableEntityAsync(domainError, ct),
7778
concurrencyError => this.PreconditionFailed(cancellationToken: ct));

src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/PatchDialogsController.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ public async Task<IActionResult> Patch(
8181
var result = await _sender.Send(command, ct);
8282
return result.Match(
8383
success => (IActionResult)NoContent(),
84-
entityNotFound => NotFound(HttpContext.ResponseBuilder(StatusCodes.Status404NotFound, entityNotFound.ToValidationResults())),
84+
notFound => NotFound(HttpContext.ResponseBuilder(StatusCodes.Status404NotFound, notFound.ToValidationResults())),
85+
badRequest => BadRequest(HttpContext.ResponseBuilder(StatusCodes.Status400BadRequest, badRequest.ToValidationResults())),
8586
validationFailed => BadRequest(HttpContext.ResponseBuilder(StatusCodes.Status400BadRequest, validationFailed.Errors.ToList())),
8687
domainError => UnprocessableEntity(HttpContext.ResponseBuilder(StatusCodes.Status422UnprocessableEntity, domainError.ToValidationResults())),
8788
concurrencyError => new ObjectResult(HttpContext.ResponseBuilder(StatusCodes.Status412PreconditionFailed)) { StatusCode = StatusCodes.Status412PreconditionFailed }

src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/UpdateDialogEndpoint.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ public override async Task HandleAsync(UpdateDialogRequest req, CancellationToke
3939
var updateDialogResult = await _sender.Send(command, ct);
4040
await updateDialogResult.Match(
4141
success => SendNoContentAsync(ct),
42-
entityNotFound => this.NotFoundAsync(entityNotFound, ct),
42+
notFound => this.NotFoundAsync(notFound, ct),
43+
badRequest => this.BadRequestAsync(badRequest, ct),
4344
validationFailed => this.BadRequestAsync(validationFailed, ct),
4445
domainError => this.UnprocessableEntityAsync(domainError, ct),
4546
concurrencyError => this.PreconditionFailed(ct));

0 commit comments

Comments
 (0)