diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/BadRequest.cs b/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/BadRequest.cs new file mode 100644 index 000000000..a877fc530 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/BadRequest.cs @@ -0,0 +1,13 @@ +using FluentValidation.Results; + +namespace Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; + +public record BadRequest(List Reasons) +{ + private const string BadRequestMessage = "BadRequest"; + + public BadRequest(params string[] reasons) : this(reasons.ToList()) { } + + public List ToValidationResults() => + Reasons.Select(x => new ValidationFailure(BadRequestMessage, x)).ToList(); +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs index 8816208f5..50d55a602 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs @@ -24,7 +24,7 @@ public sealed class UpdateDialogCommand : IRequest } [GenerateOneOf] -public partial class UpdateDialogResult : OneOfBase; +public partial class UpdateDialogResult : OneOfBase; internal sealed class UpdateDialogCommandHandler : IRequestHandler { @@ -67,6 +67,7 @@ public async Task Handle(UpdateDialogCommand request, Cancel .ThenInclude(x => x.Title!.Localizations) .Include(x => x.ApiActions) .ThenInclude(x => x.Endpoints) + .IgnoreQueryFilters() .Where(x => resourceIds.Contains(x.ServiceResource)) .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken); @@ -75,6 +76,13 @@ public async Task Handle(UpdateDialogCommand request, Cancel return new EntityNotFound(request.Id); } + if (dialog.Deleted) + { + // TODO: When restoration is implemented, add a hint to the error message. + // https://github.com/digdir/dialogporten/pull/406 + return new BadRequest($"Entity '{nameof(DialogEntity)}' with key '{request.Id}' is removed, and cannot be updated."); + } + // Update primitive properties _mapper.Map(request.Dto, dialog); ValidateTimeFields(dialog); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs index 85378cf09..281d35ac0 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs @@ -10,6 +10,10 @@ public static Task BadRequestAsync(this IEndpoint ep, ValidationError failure, C => ep.BadRequestAsync(failure.Errors, cancellationToken); public static Task BadRequestAsync(this IEndpoint ep, IEnumerable failures, CancellationToken cancellationToken = default) => ep.HttpContext.Response.SendErrorsAsync(failures.ToList() ?? [], StatusCodes.Status400BadRequest, cancellation: cancellationToken); + public static Task BadRequestAsync(this IEndpoint ep, BadRequest badRequest, CancellationToken cancellationToken = default) + => ep.HttpContext.Response.SendErrorsAsync( + badRequest.ToValidationResults(), + cancellation: cancellationToken); public static Task PreconditionFailed(this IEndpoint ep, CancellationToken cancellationToken = default) => ep.HttpContext.Response.SendErrorsAsync([], StatusCodes.Status412PreconditionFailed, cancellation: cancellationToken); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/CreateDialogActivityEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/CreateDialogActivityEndpoint.cs index 9b2b65e94..1e0696456 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/CreateDialogActivityEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/CreateDialogActivityEndpoint.cs @@ -66,6 +66,7 @@ public override async Task HandleAsync(CreateDialogActivityRequest req, Cancella await result.Match( success => SendCreatedAtAsync(new GetDialogActivityQuery { DialogId = dialog.Id, ActivityId = req.Id.Value }, req.Id, cancellation: ct), notFound => this.NotFoundAsync(notFound, ct), + badRequest => this.BadRequestAsync(badRequest, ct), validationError => this.BadRequestAsync(validationError, ct), domainError => this.UnprocessableEntityAsync(domainError, ct), concurrencyError => this.PreconditionFailed(cancellationToken: ct)); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/CreateDialogElementEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/CreateDialogElementEndpoint.cs index d32e3e1b0..da87c915e 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/CreateDialogElementEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/CreateDialogElementEndpoint.cs @@ -62,6 +62,7 @@ public override async Task HandleAsync(CreateDialogElementRequest req, Cancellat await result.Match( success => SendCreatedAtAsync(new GetDialogElementQuery { DialogId = dialog.Id, ElementId = req.Id.Value }, req.Id, cancellation: ct), notFound => this.NotFoundAsync(notFound, ct), + badRequest => this.BadRequestAsync(badRequest, ct), validationError => this.BadRequestAsync(validationError, ct), domainError => this.UnprocessableEntityAsync(domainError, ct), concurrencyError => this.PreconditionFailed(cancellationToken: ct)); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/DeleteDialogElementEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/DeleteDialogElementEndpoint.cs index 1746122e1..7941aa44c 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/DeleteDialogElementEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/DeleteDialogElementEndpoint.cs @@ -70,6 +70,7 @@ public override async Task HandleAsync(DeleteDialogElementRequest req, Cancellat await result.Match( success => SendNoContentAsync(ct), notFound => this.NotFoundAsync(notFound, ct), + badRequest => this.BadRequestAsync(badRequest, ct), validationError => this.BadRequestAsync(validationError, ct), domainError => this.UnprocessableEntityAsync(domainError, ct), concurrencyError => this.PreconditionFailed(cancellationToken: ct)); @@ -102,4 +103,3 @@ Deletes a given dialog element (hard delete). For more information see the docum Responses[StatusCodes.Status412PreconditionFailed] = Constants.SwaggerSummary.RevisionMismatch; } } - diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/UpdateDialogElementEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/UpdateDialogElementEndpoint.cs index 5c9f0b940..23d4a38fe 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/UpdateDialogElementEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/UpdateDialogElementEndpoint.cs @@ -72,6 +72,7 @@ await this.NotFoundAsync( await result.Match( success => SendNoContentAsync(ct), notFound => this.NotFoundAsync(notFound, ct), + badRequest => this.BadRequestAsync(badRequest, ct), validationError => this.BadRequestAsync(validationError, ct), domainError => this.UnprocessableEntityAsync(domainError, ct), concurrencyError => this.PreconditionFailed(cancellationToken: ct)); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/PatchDialogsController.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/PatchDialogsController.cs index 0a82eb163..e22521de6 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/PatchDialogsController.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/PatchDialogsController.cs @@ -81,7 +81,8 @@ public async Task Patch( var result = await _sender.Send(command, ct); return result.Match( success => (IActionResult)NoContent(), - entityNotFound => NotFound(HttpContext.ResponseBuilder(StatusCodes.Status404NotFound, entityNotFound.ToValidationResults())), + notFound => NotFound(HttpContext.ResponseBuilder(StatusCodes.Status404NotFound, notFound.ToValidationResults())), + badRequest => BadRequest(HttpContext.ResponseBuilder(StatusCodes.Status400BadRequest, badRequest.ToValidationResults())), validationFailed => BadRequest(HttpContext.ResponseBuilder(StatusCodes.Status400BadRequest, validationFailed.Errors.ToList())), domainError => UnprocessableEntity(HttpContext.ResponseBuilder(StatusCodes.Status422UnprocessableEntity, domainError.ToValidationResults())), concurrencyError => new ObjectResult(HttpContext.ResponseBuilder(StatusCodes.Status412PreconditionFailed)) { StatusCode = StatusCodes.Status412PreconditionFailed } diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/UpdateDialogEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/UpdateDialogEndpoint.cs index 95c48c106..1f22b4383 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/UpdateDialogEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/UpdateDialogEndpoint.cs @@ -39,7 +39,8 @@ public override async Task HandleAsync(UpdateDialogRequest req, CancellationToke var updateDialogResult = await _sender.Send(command, ct); await updateDialogResult.Match( success => SendNoContentAsync(ct), - entityNotFound => this.NotFoundAsync(entityNotFound, ct), + notFound => this.NotFoundAsync(notFound, ct), + badRequest => this.BadRequestAsync(badRequest, ct), validationFailed => this.BadRequestAsync(validationFailed, ct), domainError => this.UnprocessableEntityAsync(domainError, ct), concurrencyError => this.PreconditionFailed(ct));