From 19d7fad716565f6f06fa969c69a40e2a80cf7e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Mon, 6 Jan 2025 21:58:10 +0100 Subject: [PATCH] squash --- docs/schema/V1/swagger.verified.json | 42 ++++++++++++++--- .../Commands/Create/CreateDialogCommand.cs | 6 ++- .../Commands/Delete/DeleteDialogCommand.cs | 6 ++- .../Commands/Update/UpdateDialogCommand.cs | 7 +-- .../Common/Constants.cs | 1 + .../Headers/HttpResponseHeaderExamples.cs | 13 ++++++ .../Create/CreateDialogActivityEndpoint.cs | 11 ++++- .../CreateDialogActivityEndpointSummary.cs | 2 + .../CreateDialogTransmissionEndpoint.cs | 8 +++- ...CreateDialogTransmissionEndpointSummary.cs | 2 + .../Dialogs/Create/CreateDialogEndpoint.cs | 8 +++- .../Create/CreateDialogEndpointSummary.cs | 2 + .../Dialogs/Delete/DeleteDialogEndpoint.cs | 6 ++- .../Delete/DeleteDialogEndpointSummary.cs | 2 + .../Dialogs/Patch/PatchDialogsController.cs | 7 ++- .../Patch/ProducesResponseHeaderAttribute.cs | 16 +++++++ ...roducesResponseHeaderOperationProcessor.cs | 29 ++++++++++++ .../Dialogs/Update/UpdateDialogEndpoint.cs | 6 ++- .../Update/UpdateDialogEndpointSummary.cs | 2 + .../Program.cs | 4 ++ .../Dialogs/Queries/ActivityLogTests.cs | 10 ++-- .../Dialogs/Queries/DeletedDialogTests.cs | 2 +- .../EndUser/Dialogs/Queries/SeenLogTests.cs | 16 ++++--- .../Dialogs/Commands/CreateDialogTests.cs | 24 ++++++++-- .../Dialogs/Commands/DeleteDialogTests.cs | 26 ++++++++++- .../Dialogs/Commands/UpdateDialogTests.cs | 46 +++++++++++++++++-- .../Dialogs/Queries/ActivityLogTests.cs | 10 ++-- .../Dialogs/Queries/GetDialogTests.cs | 4 +- .../Dialogs/Queries/SeenLogTests.cs | 21 ++++++--- .../NotificationConditionTests.cs | 10 ++-- .../Commands/CreateTransmissionTests.cs | 4 +- .../Commands/UpdateTransmissionTests.cs | 12 ++--- 32 files changed, 300 insertions(+), 65 deletions(-) create mode 100644 src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/Common/Headers/HttpResponseHeaderExamples.cs create mode 100644 src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderAttribute.cs create mode 100644 src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderOperationProcessor.cs diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index 816c83190..375c25de3 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -5863,7 +5863,12 @@ } } }, - "description": "The UUID of the created dialog aggregate. A relative URL to the newly created activity is set in the \u0022Location\u0022 header." + "description": "The UUID of the created dialog aggregate. A relative URL to the newly created activity is set in the \u0022Location\u0022 header.", + "headers": { + "Etag": { + "description": "The new UUID ETag of the dialog" + } + } }, "204": { "description": "No Content" @@ -5932,7 +5937,12 @@ ], "responses": { "204": { - "description": "The dialog aggregate was deleted successfully." + "description": "The dialog aggregate was deleted successfully.", + "headers": { + "Etag": { + "description": "The new UUID ETag of the dialog" + } + } }, "400": { "content": { @@ -6088,7 +6098,12 @@ }, "responses": { "204": { - "description": "Patch was successfully applied." + "description": "Patch was successfully applied.", + "headers": { + "Etag": { + "description": "The new UUID ETag of the dialog" + } + } }, "400": { "content": { @@ -6183,7 +6198,12 @@ }, "responses": { "204": { - "description": "The dialog aggregate was updated successfully." + "description": "The dialog aggregate was updated successfully.", + "headers": { + "Etag": { + "description": "The new UUID ETag of the dialog" + } + } }, "400": { "content": { @@ -6481,7 +6501,12 @@ } } }, - "description": "The UUID of the created dialog activity. A relative URL to the newly created activity is set in the \u0022Location\u0022 header." + "description": "The UUID of the created dialog activity. A relative URL to the newly created activity is set in the \u0022Location\u0022 header.", + "headers": { + "Etag": { + "description": "The new UUID ETag of the dialog" + } + } }, "204": { "description": "No Content" @@ -6844,7 +6869,12 @@ } } }, - "description": "The UUID of the created dialog transmission. A relative URL to the newly created activity is set in the \u0022Location\u0022 header." + "description": "The UUID of the created dialog transmission. A relative URL to the newly created activity is set in the \u0022Location\u0022 header.", + "headers": { + "Etag": { + "description": "The new UUID ETag of the dialog" + } + } }, "204": { "description": "No Content" diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs index 2fee13aa3..09374e635 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs @@ -21,8 +21,10 @@ namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialog public sealed class CreateDialogCommand : CreateDialogDto, IRequest; +public sealed record CreateDialogSuccess(Guid DialogId, Guid Revision); + [GenerateOneOf] -public sealed partial class CreateDialogResult : OneOfBase, DomainError, ValidationError, Forbidden>; +public sealed partial class CreateDialogResult : OneOfBase; internal sealed class CreateDialogCommandHandler : IRequestHandler { @@ -93,7 +95,7 @@ public async Task Handle(CreateDialogCommand request, Cancel await _db.Dialogs.AddAsync(dialog, cancellationToken); var saveResult = await _unitOfWork.SaveChangesAsync(cancellationToken); return saveResult.Match( - success => new Success(dialog.Id), + success => new CreateDialogSuccess(dialog.Id, dialog.Revision), domainError => domainError, concurrencyError => throw new UnreachableException("Should never get a concurrency error when creating a new dialog")); } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Delete/DeleteDialogCommand.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Delete/DeleteDialogCommand.cs index c64e816d1..9b9250ed6 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Delete/DeleteDialogCommand.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Delete/DeleteDialogCommand.cs @@ -19,7 +19,9 @@ public sealed class DeleteDialogCommand : IRequest } [GenerateOneOf] -public sealed partial class DeleteDialogResult : OneOfBase; +public sealed partial class DeleteDialogResult : OneOfBase; + +public sealed record DeleteDialogSuccess(Guid Revision); internal sealed class DeleteDialogCommandHandler : IRequestHandler { @@ -70,7 +72,7 @@ public async Task Handle(DeleteDialogCommand request, Cancel .SaveChangesAsync(cancellationToken); return saveResult.Match( - success => success, + success => new DeleteDialogSuccess(dialog.Revision), domainError => throw new UnreachableException("Should never get a domain error when deleting a dialog"), concurrencyError => concurrencyError); } 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 fb160b026..4b11eb5aa 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 @@ -19,7 +19,6 @@ using MediatR; using Microsoft.EntityFrameworkCore; using OneOf; -using OneOf.Types; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Update; @@ -31,7 +30,9 @@ public sealed class UpdateDialogCommand : IRequest } [GenerateOneOf] -public sealed partial class UpdateDialogResult : OneOfBase; +public sealed partial class UpdateDialogResult : OneOfBase; + +public sealed record UpdateDialogSuccess(Guid Revision); internal sealed class UpdateDialogCommandHandler : IRequestHandler { @@ -167,7 +168,7 @@ public async Task Handle(UpdateDialogCommand request, Cancel .SaveChangesAsync(cancellationToken); return saveResult.Match( - success => success, + success => new UpdateDialogSuccess(dialog.Revision), domainError => domainError, concurrencyError => concurrencyError); } diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Constants.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Constants.cs index e56595733..27a652350 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Constants.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Constants.cs @@ -3,6 +3,7 @@ internal static class Constants { internal const string IfMatch = "If-Match"; + internal const string ETag = "Etag"; internal const string Authorization = "Authorization"; internal const string CurrentTokenIssuer = "CurrentIssuer"; internal const int MaxRequestBodySize = 100_000; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/Common/Headers/HttpResponseHeaderExamples.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/Common/Headers/HttpResponseHeaderExamples.cs new file mode 100644 index 000000000..288ed510d --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/Common/Headers/HttpResponseHeaderExamples.cs @@ -0,0 +1,13 @@ +using Digdir.Domain.Dialogporten.WebApi.Common; +using FastEndpoints; + +namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Headers; + +public static class HttpResponseHeaderExamples +{ + public static ResponseHeader NewDialogETagHeader(int statusCode) + => new(statusCode, Constants.ETag) + { + Description = "The new UUID ETag of the dialog", + }; +} diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpoint.cs index 85484c662..6f1e9040a 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpoint.cs @@ -65,7 +65,16 @@ await errors.Match( var result = await _sender.Send(updateDialogCommand, ct); await result.Match( - success => SendCreatedAtAsync(new GetActivityQuery { DialogId = dialog.Id, ActivityId = req.Id.Value }, req.Id, cancellation: ct), + success => + { + HttpContext.Response.Headers.Append(Constants.ETag, success.Revision.ToString()); + return SendCreatedAtAsync( + new GetActivityQuery + { + DialogId = dialog.Id, + ActivityId = req.Id.Value + }, req.Id, cancellation: ct); + }, notFound => this.NotFoundAsync(notFound, ct), gone => this.GoneAsync(gone, ct), validationError => this.BadRequestAsync(validationError, ct), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpointSummary.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpointSummary.cs index 8d005c557..b8f7f8057 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpointSummary.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogActivities/Create/CreateDialogActivityEndpointSummary.cs @@ -1,6 +1,7 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; +using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Headers; using FastEndpoints; namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.DialogActivities.Create; @@ -18,6 +19,7 @@ The activity is created with the given configuration. For more information see t ResponseExamples[StatusCodes.Status201Created] = "018bb8e5-d9d0-7434-8ec5-569a6c8e01fc"; + ResponseHeaders = [HttpResponseHeaderExamples.NewDialogETagHeader(StatusCodes.Status201Created)]; Responses[StatusCodes.Status201Created] = Constants.SwaggerSummary.Created.FormatInvariant("activity"); Responses[StatusCodes.Status400BadRequest] = Constants.SwaggerSummary.ValidationError; Responses[StatusCodes.Status401Unauthorized] = Constants.SwaggerSummary.ServiceOwnerAuthenticationFailure.FormatInvariant(AuthorizationScope.ServiceProvider); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpoint.cs index 2018e2d3b..27623c061 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpoint.cs @@ -66,7 +66,13 @@ await errors.Match( var result = await _sender.Send(updateDialogCommand, ct); await result.Match( - success => SendCreatedAtAsync(new GetTransmissionQuery { DialogId = dialog.Id, TransmissionId = req.Id.Value }, req.Id, cancellation: ct), + success => + { + HttpContext.Response.Headers.Append(Constants.ETag, success.Revision.ToString()); + return SendCreatedAtAsync( + new GetTransmissionQuery { DialogId = dialog.Id, TransmissionId = req.Id.Value }, req.Id, + cancellation: ct); + }, notFound => this.NotFoundAsync(notFound, ct), gone => this.GoneAsync(gone, ct), validationError => this.BadRequestAsync(validationError, ct), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpointSummary.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpointSummary.cs index ecb0430cd..4af3789e3 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpointSummary.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Create/CreateDialogTransmissionEndpointSummary.cs @@ -1,6 +1,7 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; +using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Headers; using FastEndpoints; namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.DialogTransmissions.Create; @@ -18,6 +19,7 @@ The transmission is created with the given configuration. For more information s ResponseExamples[StatusCodes.Status201Created] = "018bb8e5-d9d0-7434-8ec5-569a6c8e01fc"; + ResponseHeaders = [HttpResponseHeaderExamples.NewDialogETagHeader(StatusCodes.Status201Created)]; Responses[StatusCodes.Status201Created] = Constants.SwaggerSummary.Created.FormatInvariant("transmission"); Responses[StatusCodes.Status400BadRequest] = Constants.SwaggerSummary.ValidationError; Responses[StatusCodes.Status401Unauthorized] = Constants.SwaggerSummary.ServiceOwnerAuthenticationFailure.FormatInvariant(AuthorizationScope.ServiceProvider); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpoint.cs index cbc9938e7..cb6f33e38 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpoint.cs @@ -1,5 +1,6 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Create; using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get; +using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; @@ -34,7 +35,12 @@ public override async Task HandleAsync(CreateDialogCommand req, CancellationToke { var result = await _sender.Send(req, ct); await result.Match( - success => SendCreatedAtAsync(new GetDialogQuery { DialogId = success.Value }, success.Value, cancellation: ct), + success => + { + HttpContext.Response.Headers.Append(Constants.ETag, success.Revision.ToString()); + return SendCreatedAtAsync(new GetDialogQuery { DialogId = success.DialogId }, + success.DialogId, cancellation: ct); + }, domainError => this.UnprocessableEntityAsync(domainError, ct), validationError => this.BadRequestAsync(validationError, ct), forbidden => this.ForbiddenAsync(forbidden, ct)); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpointSummary.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpointSummary.cs index ae324eb51..82f7efb89 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpointSummary.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Create/CreateDialogEndpointSummary.cs @@ -1,6 +1,7 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; +using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Headers; using FastEndpoints; namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Create; @@ -18,6 +19,7 @@ The dialog is created with the given configuration. For more information see the ResponseExamples[StatusCodes.Status201Created] = "018bb8e5-d9d0-7434-8ec5-569a6c8e01fc"; + ResponseHeaders = [HttpResponseHeaderExamples.NewDialogETagHeader(StatusCodes.Status201Created)]; Responses[StatusCodes.Status201Created] = Constants.SwaggerSummary.Created.FormatInvariant("aggregate"); Responses[StatusCodes.Status400BadRequest] = Constants.SwaggerSummary.ValidationError; Responses[StatusCodes.Status401Unauthorized] = Constants.SwaggerSummary.ServiceOwnerAuthenticationFailure.FormatInvariant(AuthorizationScope.ServiceProvider); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpoint.cs index 40f91368d..d8c6445de 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpoint.cs @@ -36,7 +36,11 @@ public override async Task HandleAsync(DeleteDialogRequest req, CancellationToke var command = new DeleteDialogCommand { Id = req.DialogId, IfMatchDialogRevision = req.IfMatchDialogRevision }; var result = await _sender.Send(command, ct); await result.Match( - success => SendNoContentAsync(ct), + success => + { + HttpContext.Response.Headers.Append(Constants.ETag, success.Revision.ToString()); + return SendNoContentAsync(ct); + }, notFound => this.NotFoundAsync(notFound, ct), gone => this.GoneAsync(gone, ct), forbidden => this.ForbiddenAsync(forbidden, ct), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpointSummary.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpointSummary.cs index 9125a68de..973b9d1bb 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpointSummary.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Delete/DeleteDialogEndpointSummary.cs @@ -1,6 +1,7 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; +using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Headers; using FastEndpoints; namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Delete; @@ -18,6 +19,7 @@ Deletes a given dialog (soft delete). For more information see the documentation Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not deleted by another request in the meantime. """; + ResponseHeaders = [HttpResponseHeaderExamples.NewDialogETagHeader(StatusCodes.Status204NoContent)]; Responses[StatusCodes.Status204NoContent] = Constants.SwaggerSummary.Deleted.FormatInvariant("aggregate"); Responses[StatusCodes.Status401Unauthorized] = Constants.SwaggerSummary.ServiceOwnerAuthenticationFailure.FormatInvariant(AuthorizationScope.ServiceProvider); Responses[StatusCodes.Status403Forbidden] = Constants.SwaggerSummary.AccessDeniedToDialog.FormatInvariant("delete"); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/PatchDialogsController.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/PatchDialogsController.cs index b439574cb..f56fbb7ef 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/PatchDialogsController.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/PatchDialogsController.cs @@ -60,6 +60,7 @@ public PatchDialogsController(ISender sender, IMapper mapper) [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status412PreconditionFailed)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] + [ProducesResponseHeader(StatusCodes.Status204NoContent, Constants.ETag, "The new UUID ETag of the dialog")] public async Task Patch( [FromRoute] Guid dialogId, [FromHeader(Name = Constants.IfMatch)] Guid? etag, @@ -87,7 +88,11 @@ public async Task Patch( var command = new UpdateDialogCommand { Id = dialogId, IfMatchDialogRevision = etag, Dto = updateDialogDto }; var result = await _sender.Send(command, ct); return result.Match( - success => (IActionResult)NoContent(), + success => + { + HttpContext.Response.Headers.Append(Constants.ETag, success.Revision.ToString()); + return (IActionResult)NoContent(); + }, notFound => NotFound(HttpContext.GetResponseOrDefault(StatusCodes.Status404NotFound, notFound.ToValidationResults())), badRequest => BadRequest(HttpContext.GetResponseOrDefault(StatusCodes.Status400BadRequest, badRequest.ToValidationResults())), validationFailed => BadRequest(HttpContext.GetResponseOrDefault(StatusCodes.Status400BadRequest, validationFailed.Errors.ToList())), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderAttribute.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderAttribute.cs new file mode 100644 index 000000000..77e2d3e12 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderAttribute.cs @@ -0,0 +1,16 @@ +namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Patch; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class ProducesResponseHeaderAttribute : Attribute +{ + public ProducesResponseHeaderAttribute(int statusCode, string headerName, string description) + { + HeaderName = headerName; + StatusCode = statusCode; + Description = description; + } + + public string HeaderName { get; } + public int StatusCode { get; } + public string Description { get; } +} diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderOperationProcessor.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderOperationProcessor.cs new file mode 100644 index 000000000..26ec4387e --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Patch/ProducesResponseHeaderOperationProcessor.cs @@ -0,0 +1,29 @@ +using System.Globalization; +using System.Reflection; +using NSwag; +using NSwag.Generation.Processors; +using NSwag.Generation.Processors.Contexts; + +namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Patch; + +public sealed class ProducesResponseHeaderOperationProcessor : IOperationProcessor +{ + public bool Process(OperationProcessorContext context) + { + var headerAttribute = context.MethodInfo.GetCustomAttribute(); + if (headerAttribute == null) + { + return true; + } + + var statusCode = headerAttribute.StatusCode.ToString(CultureInfo.InvariantCulture); + var response = context.OperationDescription.Operation.Responses[statusCode]; + var header = new OpenApiHeader + { + Description = headerAttribute.Description, + }; + + response.Headers.Add(headerAttribute.HeaderName, header); + return true; + } +} diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpoint.cs index d75486f68..e8b866cca 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpoint.cs @@ -43,7 +43,11 @@ public override async Task HandleAsync(UpdateDialogRequest req, CancellationToke var updateDialogResult = await _sender.Send(command, ct); await updateDialogResult.Match( - success => SendNoContentAsync(ct), + success => + { + HttpContext.Response.Headers.Append(Constants.ETag, success.Revision.ToString()); + return SendNoContentAsync(ct); + }, notFound => this.NotFoundAsync(notFound, ct), gone => this.GoneAsync(gone, ct), validationFailed => this.BadRequestAsync(validationFailed, ct), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpointSummary.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpointSummary.cs index 055cc3eb7..d6874cf58 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpointSummary.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogEndpointSummary.cs @@ -1,6 +1,7 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; +using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Headers; using FastEndpoints; namespace Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Update; @@ -15,6 +16,7 @@ Replaces a given dialog with the supplied model. For more information see the do {Constants.SwaggerSummary.OptimisticConcurrencyNote} """; + ResponseHeaders = [HttpResponseHeaderExamples.NewDialogETagHeader(StatusCodes.Status204NoContent)]; Responses[StatusCodes.Status204NoContent] = Constants.SwaggerSummary.Updated.FormatInvariant("aggregate"); Responses[StatusCodes.Status400BadRequest] = Constants.SwaggerSummary.ValidationError; Responses[StatusCodes.Status401Unauthorized] = diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 6b58f6b5a..7674052f5 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -15,6 +15,7 @@ using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Json; using Digdir.Domain.Dialogporten.WebApi.Common.Swagger; +using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Patch; using Digdir.Library.Utils.AspNet; using FastEndpoints; using FastEndpoints.Swagger; @@ -125,6 +126,9 @@ static void BuildAndRun(string[] args, TelemetryConfiguration telemetryConfigura // generic "2" suffix duplicate names get, so we add a "SO" suffix to the serviceowner specific schemas. // This should match the operationIds used for service owners. s.AddServiceOwnerSuffixToSchemas(); + + // Adding ResponseHeaders for PATCH MVC controller + s.OperationProcessors.Add(new ProducesResponseHeaderOperationProcessor()); }; }) .AddControllers(options => options.InputFormatters.Insert(0, JsonPatchInputFormatter.Get())) diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/ActivityLogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/ActivityLogTests.cs index d5495680e..6f8ed9bc5 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/ActivityLogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/ActivityLogTests.cs @@ -19,7 +19,7 @@ public async Task Get_Dialog_ActivityLog_Should_Not_Return_User_Ids_Unhashed() var (_, createCommandResponse) = await GenerateDialogWithActivity(); // Act - var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Assert response.TryPickT0(out var result, out _).Should().BeTrue(); @@ -63,13 +63,17 @@ public async Task Get_ActivityLog_Should_Not_Return_User_Ids_Unhashed() // Arrange var (_, createCommandResponse) = await GenerateDialogWithActivity(); - var getDialogResult = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var getDialogResult = await Application.Send(new GetDialogQuery + { + DialogId = createCommandResponse.AsT0.DialogId + }); + var activityId = getDialogResult.AsT0.Activities.First().Id; // Act var response = await Application.Send(new GetActivityQuery { - DialogId = createCommandResponse.AsT0.Value, + DialogId = createCommandResponse.AsT0.DialogId, ActivityId = activityId }); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/DeletedDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/DeletedDialogTests.cs index 30e3613cc..c1be07e25 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/DeletedDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/DeletedDialogTests.cs @@ -16,7 +16,7 @@ public async Task Fetching_Deleted_Dialog_Should_Return_Gone() var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); var createDialogResponse = await Application.Send(createDialogCommand); - var dialogId = createDialogResponse.AsT0.Value; + var dialogId = createDialogResponse.AsT0.DialogId; var deleteDialogCommand = new DeleteDialogCommand { Id = dialogId }; await Application.Send(deleteDialogCommand); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/SeenLogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/SeenLogTests.cs index ab9cb0bfe..872a2356e 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/SeenLogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/SeenLogTests.cs @@ -20,7 +20,7 @@ public async Task Get_Dialog_SeenLog_Should_Not_Return_User_Ids_Unhashed() var createCommandResponse = await Application.Send(createDialogCommand); // Act - var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Assert response.TryPickT0(out var result, out _).Should().BeTrue(); @@ -42,7 +42,7 @@ public async Task Search_Dialog_SeenLog_Should_Not_Return_User_Ids_Unhashed() var createCommandResponse = await Application.Send(createDialogCommand); // Trigger SeenLog - await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Act var response = await Application.Send(new SearchDialogQuery @@ -70,13 +70,17 @@ public async Task Get_SeenLog_Should_Not_Return_User_Ids_Unhashed() var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); var createCommandResponse = await Application.Send(createDialogCommand); - var triggerSeenLogResponse = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var triggerSeenLogResponse = await Application.Send(new GetDialogQuery + { + DialogId = createCommandResponse.AsT0.DialogId + }); + var seenLogId = triggerSeenLogResponse.AsT0.SeenSinceLastUpdate.Single().Id; // Act var response = await Application.Send(new GetSeenLogQuery { - DialogId = createCommandResponse.AsT0.Value, + DialogId = createCommandResponse.AsT0.DialogId, SeenLogId = seenLogId }); @@ -97,12 +101,12 @@ public async Task Search_SeenLog_Should_Not_Return_User_Ids_Unhashed() var createCommandResponse = await Application.Send(createDialogCommand); // Trigger SeenLog - await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Act var response = await Application.Send(new SearchSeenLogQuery { - DialogId = createCommandResponse.AsT0.Value + DialogId = createCommandResponse.AsT0.DialogId }); // Assert diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs index ef91ba303..7fc55434d 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs @@ -83,7 +83,7 @@ public async Task Create_Dialog_With_ID_With_Timestamp_In_The_Past() // Assert response.TryPickT0(out var success, out _).Should().BeTrue(); success.Should().NotBeNull(); - success.Value.Should().Be(validDialogId); + success.DialogId.Should().Be(validDialogId); } [Fact] @@ -98,7 +98,7 @@ public async Task Create_CreatesDialog_WhenDialogIsSimple() // Assert response.TryPickT0(out var success, out _).Should().BeTrue(); - success.Value.Should().Be(expectedDialogId); + success.DialogId.Should().Be(expectedDialogId); } [Fact] @@ -113,7 +113,7 @@ public async Task Create_CreateDialog_WhenDialogIsComplex() // Assert result.TryPickT0(out var success, out _).Should().BeTrue(); - success.Value.Should().Be(expectedDialogId); + success.DialogId.Should().Be(expectedDialogId); } [Fact] @@ -136,7 +136,7 @@ public async Task Can_Create_Dialog_With_UpdatedAt_Supplied() // Assert createDialogResult.TryPickT0(out var dialogCreatedSuccess, out _).Should().BeTrue(); - dialogCreatedSuccess.Value.Should().Be(dialogId); + dialogCreatedSuccess.DialogId.Should().Be(dialogId); getDialogQuery.Should().NotBeNull(); getDialogResponse.TryPickT0(out var dialog, out _).Should().BeTrue(); @@ -408,6 +408,20 @@ public async Task Can_Create_MainContentRef_Content_With_Embeddable_Html_MediaTy // Assert response.TryPickT0(out var success, out _).Should().BeTrue(); success.Should().NotBeNull(); - success.Value.Should().Be(expectedDialogId); + success.DialogId.Should().Be(expectedDialogId); + } + + [Fact] + public async Task CreateDialogCommand_Should_Return_Revision() + { + // Arrange + var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); + + // Act + var response = await Application.Send(createDialogCommand); + + // Assert + response.TryPickT0(out var success, out _).Should().BeTrue(); + success.Revision.Should().NotBeEmpty(); } } diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/DeleteDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/DeleteDialogTests.cs index a225fc9a3..459033a6b 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/DeleteDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/DeleteDialogTests.cs @@ -18,7 +18,7 @@ public async Task Deleting_Dialog_Should_Set_DeletedAt() var createDialogResponse = await Application.Send(createDialogCommand); // Act - var dialogId = createDialogResponse.AsT0.Value; + var dialogId = createDialogResponse.AsT0.DialogId; var deleteDialogCommand = new DeleteDialogCommand { Id = dialogId }; await Application.Send(deleteDialogCommand); @@ -38,7 +38,7 @@ public async Task Updating_Deleted_Dialog_Should_Return_EntityDeleted() var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); var createDialogResponse = await Application.Send(createDialogCommand); - var dialogId = createDialogResponse.AsT0.Value; + var dialogId = createDialogResponse.AsT0.DialogId; var deleteDialogCommand = new DeleteDialogCommand { Id = dialogId }; await Application.Send(deleteDialogCommand); @@ -58,4 +58,26 @@ public async Task Updating_Deleted_Dialog_Should_Return_EntityDeleted() entityDeleted.Should().NotBeNull(); entityDeleted.Message.Should().Contain(dialogId.ToString()); } + + [Fact] + public async Task DeleteDialogCommand_Should_Return_New_Revision() + { + // Arrange + var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); + var createDialogResponse = await Application.Send(createDialogCommand); + + var dialogId = createDialogResponse.AsT0.DialogId; + var oldRevision = createDialogResponse.AsT0.Revision; + + // Act + var deleteDialogCommand = new DeleteDialogCommand { Id = dialogId }; + var deleteDialogResponse = await Application.Send(deleteDialogCommand); + + // Assert + deleteDialogResponse.TryPickT0(out var success, out _).Should().BeTrue(); + success.Should().NotBeNull(); + success.Revision.Should().NotBeEmpty(); + success.Revision.Should().NotBe(oldRevision); + } + } diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/UpdateDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/UpdateDialogTests.cs index d8e752f60..debac9c8c 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/UpdateDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/UpdateDialogTests.cs @@ -16,12 +16,42 @@ namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.S [Collection(nameof(DialogCqrsCollectionFixture))] public class UpdateDialogTests(DialogApplication application) : ApplicationCollectionFixture(application) { + [Fact] + public async Task UpdateDialogCommand_Should_Return_New_Revision() + { + // Arrange + var createCommandResponse = await Application.Send(DialogGenerator.GenerateSimpleFakeDialog()); + + var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }; + var getDialogDto = await Application.Send(getDialogQuery); + var oldRevision = getDialogDto.AsT0.Revision; + + var mapper = Application.GetMapper(); + var updateDialogDto = mapper.Map(getDialogDto.AsT0); + + // Update something + updateDialogDto.Progress++; + + // Act + var updateResponse = await Application.Send(new UpdateDialogCommand + { + Id = createCommandResponse.AsT0.DialogId, + Dto = updateDialogDto + }); + + // Assert + updateResponse.TryPickT0(out var success, out _).Should().BeTrue(); + success.Should().NotBeNull(); + success.Revision.Should().NotBeEmpty(); + success.Revision.Should().NotBe(oldRevision); + } + [Fact] public async Task Cannot_Include_Old_Activities_To_UpdateCommand() { // Arrange var (_, createCommandResponse) = await GenerateDialogWithActivity(); - var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }; + var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }; var getDialogDto = await Application.Send(getDialogQuery); var mapper = Application.GetMapper(); @@ -39,7 +69,11 @@ public async Task Cannot_Include_Old_Activities_To_UpdateCommand() }); // Act - var updateResponse = await Application.Send(new UpdateDialogCommand { Id = createCommandResponse.AsT0.Value, Dto = updateDialogDto }); + var updateResponse = await Application.Send(new UpdateDialogCommand + { + Id = createCommandResponse.AsT0.DialogId, + Dto = updateDialogDto + }); // Assert updateResponse.TryPickT5(out var domainError, out _).Should().BeTrue(); @@ -56,7 +90,7 @@ public async Task Cannot_Include_Old_Transmissions_In_UpdateCommand() createDialogCommand.Transmissions.Add(existingTransmission); var createCommandResponse = await Application.Send(createDialogCommand); - var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }; + var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }; var getDialogDto = await Application.Send(getDialogQuery); var mapper = Application.GetMapper(); @@ -76,7 +110,11 @@ public async Task Cannot_Include_Old_Transmissions_In_UpdateCommand() }); // Act - var updateResponse = await Application.Send(new UpdateDialogCommand { Id = createCommandResponse.AsT0.Value, Dto = updateDialogDto }); + var updateResponse = await Application.Send(new UpdateDialogCommand + { + Id = createCommandResponse.AsT0.DialogId, + Dto = updateDialogDto + }); // Assert updateResponse.TryPickT5(out var domainError, out _).Should().BeTrue(); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/ActivityLogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/ActivityLogTests.cs index 6b899cff3..a509ec024 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/ActivityLogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/ActivityLogTests.cs @@ -20,7 +20,7 @@ public async Task Get_Dialog_ActivityLog_Should_Return_User_Ids_Unhashed() var (_, createCommandResponse) = await GenerateDialogWithActivity(); // Act - var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Assert response.TryPickT0(out var result, out _).Should().BeTrue(); @@ -64,13 +64,17 @@ public async Task Get_ActivityLog_Should_Return_User_Ids_Unhashed() // Arrange var (_, createCommandResponse) = await GenerateDialogWithActivity(); - var getDialogResult = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var getDialogResult = await Application.Send(new GetDialogQuery + { + DialogId = createCommandResponse.AsT0.DialogId + }); + var activityId = getDialogResult.AsT0.Activities.First().Id; // Act var response = await Application.Send(new GetActivityQuery { - DialogId = createCommandResponse.AsT0.Value, + DialogId = createCommandResponse.AsT0.DialogId, ActivityId = activityId }); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs index cadeb8a92..6bd67650a 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs @@ -21,7 +21,7 @@ public async Task Get_ReturnsSimpleDialog_WhenDialogExists() var createCommandResponse = await Application.Send(createDialogCommand); // Act - var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Assert response.TryPickT0(out var result, out _).Should().BeTrue(); @@ -41,7 +41,7 @@ public async Task Get_ReturnsDialog_WhenDialogExists() var createCommandResponse = await Application.Send(createCommand); // Act - var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }); + var response = await Application.Send(new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }); // Assert response.TryPickT0(out var result, out _).Should().BeTrue(); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/SeenLogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/SeenLogTests.cs index 49502e2a0..0068177f9 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/SeenLogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/SeenLogTests.cs @@ -21,10 +21,13 @@ public async Task Get_Dialog_SeenLog_Should_Return_User_Ids_Unhashed() var createCommandResponse = await Application.Send(createDialogCommand); // Call EndUser API to trigger SeenLog - await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.Value }); + await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.DialogId }); // Act - var response = await Application.Send(new GetDialogQueryServiceOwner { DialogId = createCommandResponse.AsT0.Value }); + var response = await Application.Send(new GetDialogQueryServiceOwner + { + DialogId = createCommandResponse.AsT0.DialogId + }); // Assert response.TryPickT0(out var result, out _).Should().BeTrue(); @@ -45,7 +48,7 @@ public async Task Search_Dialog_SeenLog_Should_Return_User_Ids_Unhashed() var createCommandResponse = await Application.Send(createDialogCommand); // Trigger SeenLog - await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.Value }); + await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.DialogId }); // Act var response = await Application.Send(new SearchDialogQuery @@ -73,13 +76,17 @@ public async Task Get_SeenLog_Should_Return_User_Ids_Unhashed() var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); var createCommandResponse = await Application.Send(createDialogCommand); - var triggerSeenLogResponse = await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.Value }); + var triggerSeenLogResponse = await Application.Send(new GetDialogQueryEndUser + { + DialogId = createCommandResponse.AsT0.DialogId + }); + var seenLogId = triggerSeenLogResponse.AsT0.SeenSinceLastUpdate.Single().Id; // Act var response = await Application.Send(new GetSeenLogQuery { - DialogId = createCommandResponse.AsT0.Value, + DialogId = createCommandResponse.AsT0.DialogId, SeenLogId = seenLogId }); @@ -100,12 +107,12 @@ public async Task Search_SeenLog_Should_Return_User_Ids_Unhashed() var createCommandResponse = await Application.Send(createDialogCommand); // Trigger SeenLog - await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.Value }); + await Application.Send(new GetDialogQueryEndUser { DialogId = createCommandResponse.AsT0.DialogId }); // Act var response = await Application.Send(new SearchSeenLogQuery { - DialogId = createCommandResponse.AsT0.Value + DialogId = createCommandResponse.AsT0.DialogId }); // Assert diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/NotificationCondition/NotificationConditionTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/NotificationCondition/NotificationConditionTests.cs index 9c13b255c..90aa57c76 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/NotificationCondition/NotificationConditionTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/NotificationCondition/NotificationConditionTests.cs @@ -40,7 +40,7 @@ public async Task SendNotification_Should_Be_True_When_Conditions_Are_Met( var response = await Application.Send(createDialogCommand); response.TryPickT0(out var dialogId, out _); - var notificationConditionQuery = CreateNotificationConditionQuery(dialogId.Value, activityType, conditionType); + var notificationConditionQuery = CreateNotificationConditionQuery(dialogId.DialogId, activityType, conditionType); if (activityType is DialogActivityType.Values.TransmissionOpened) { @@ -93,11 +93,11 @@ public async Task Gone_Should_Be_Returned_When_Dialog_Is_Deleted() var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); var response = await Application.Send(createDialogCommand); - response.TryPickT0(out var dialogId, out _); + response.TryPickT0(out var success, out _); - await Application.Send(new DeleteDialogCommand { Id = dialogId.Value }); + await Application.Send(new DeleteDialogCommand { Id = success.DialogId }); - var notificationConditionQuery = CreateNotificationConditionQuery(dialogId.Value); + var notificationConditionQuery = CreateNotificationConditionQuery(success.DialogId); // Act var queryResult = await Application.Send(notificationConditionQuery); @@ -106,7 +106,7 @@ public async Task Gone_Should_Be_Returned_When_Dialog_Is_Deleted() queryResult.TryPickT3(out var deleted, out _); queryResult.IsT3.Should().BeTrue(); deleted.Should().NotBeNull(); - deleted.Message.Should().Contain(dialogId.Value.ToString()); + deleted.Message.Should().Contain(success.DialogId.ToString()); } private static NotificationConditionQuery CreateNotificationConditionQuery(Guid dialogId, diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs index e0cd3e275..0b52be4c7 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs @@ -30,7 +30,7 @@ public async Task Can_Create_Simple_Transmission() // Assert response.TryPickT0(out var success, out _).Should().BeTrue(); - success.Value.Should().Be(dialogId); + success.DialogId.Should().Be(dialogId); var transmissionEntities = await Application.GetDbEntities(); transmissionEntities.Should().HaveCount(1); transmissionEntities.First().DialogId.Should().Be(dialogId); @@ -62,7 +62,7 @@ public async Task Can_Create_Transmission_With_Embeddable_Content() // Assert response.TryPickT0(out var success, out _).Should().BeTrue(); - success.Value.Should().Be(dialogId); + success.DialogId.Should().Be(dialogId); var transmissionEntities = await Application.GetDbEntities(); transmissionEntities.Should().HaveCount(1); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs index a7e57c4d9..3e2c51000 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs @@ -24,7 +24,7 @@ public async Task Can_Create_Simple_Transmission_In_Update() createDialogCommand.Transmissions.Add(existingTransmission); var createCommandResponse = await Application.Send(createDialogCommand); - var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }; + var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }; var getDialogDto = await Application.Send(getDialogQuery); var mapper = Application.GetMapper(); @@ -36,7 +36,7 @@ public async Task Can_Create_Simple_Transmission_In_Update() // Act var updateResponse = await Application.Send(new UpdateDialogCommand { - Id = createCommandResponse.AsT0.Value, + Id = createCommandResponse.AsT0.DialogId, Dto = updateDialogDto }); @@ -58,7 +58,7 @@ public async Task Can_Update_Related_Transmission_With_Null_Id() createDialogCommand.Transmissions.Add(existingTransmission); var createCommandResponse = await Application.Send(createDialogCommand); - var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }; + var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }; var getDialogDto = await Application.Send(getDialogQuery); var mapper = Application.GetMapper(); @@ -76,7 +76,7 @@ public async Task Can_Update_Related_Transmission_With_Null_Id() // Act var updateResponse = await Application.Send(new UpdateDialogCommand { - Id = createCommandResponse.AsT0.Value, + Id = createCommandResponse.AsT0.DialogId, Dto = updateDialogDto }); @@ -97,7 +97,7 @@ public async Task Cannot_Include_Old_Transmissions_In_UpdateCommand() createDialogCommand.Transmissions.Add(existingTransmission); var createCommandResponse = await Application.Send(createDialogCommand); - var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.Value }; + var getDialogQuery = new GetDialogQuery { DialogId = createCommandResponse.AsT0.DialogId }; var getDialogDto = await Application.Send(getDialogQuery); var mapper = Application.GetMapper(); @@ -110,7 +110,7 @@ public async Task Cannot_Include_Old_Transmissions_In_UpdateCommand() // Act var updateResponse = await Application.Send(new UpdateDialogCommand { - Id = createCommandResponse.AsT0.Value, + Id = createCommandResponse.AsT0.DialogId, Dto = updateDialogDto });