From 45638c1dbd1a87e2cb17401d41ce9fffe038f9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 9 Oct 2024 11:08:05 +0200 Subject: [PATCH 1/5] ads --- .../Content/ContentValueDtoValidator.cs | 26 +++----- .../MediaTypes.cs | 1 + .../Dialogs/Commands/CreateDialogTests.cs | 65 ++++++++++++++++++- 3 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs index e3f77d40c..2b0ad77be 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Digdir.Domain.Dialogporten.Application.Common.Authorization; using Digdir.Domain.Dialogporten.Application.Common.Extensions; using Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation; @@ -68,22 +69,15 @@ x.MediaType is not null .SetValidator(_ => new LocalizationDtosValidator(contentType.MaxLength)); } + [SuppressMessage("Style", "IDE0072:Add missing cases")] private static string[] GetAllowedMediaTypes(DialogContentType contentType, IUser? user) - { - if (user == null) - { - return contentType.AllowedMediaTypes; - } - - if (contentType.Id != DialogContentType.Values.AdditionalInfo) + => contentType.Id switch { - return contentType.AllowedMediaTypes; - } - - var allowHtmlSupport = user.GetPrincipal().HasScope(Constants.LegacyHtmlScope); - - return allowHtmlSupport - ? contentType.AllowedMediaTypes.Append(LegacyHtmlMediaType).ToArray() - : contentType.AllowedMediaTypes; - } + DialogContentType.Values.AdditionalInfo when UserHasLegacyHtmlScope(user) + => contentType.AllowedMediaTypes.Append(LegacyHtmlMediaType).ToArray(), + DialogContentType.Values.MainContentReference when UserHasLegacyHtmlScope(user) + => contentType.AllowedMediaTypes.Append(MediaTypes.LegacyEmbeddableHtml).ToArray(), + _ => contentType.AllowedMediaTypes + }; + private static bool UserHasLegacyHtmlScope(IUser? user) => user is not null && user.GetPrincipal().HasScope(Constants.LegacyHtmlScope); } diff --git a/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs b/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs index e89f528c5..da3ab4823 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs @@ -4,6 +4,7 @@ public static class MediaTypes { public const string EmbeddablePrefix = "application/vnd.dialogporten.frontchannelembed"; public const string EmbeddableMarkdown = $"{EmbeddablePrefix}+json;type=markdown"; + public const string LegacyEmbeddableHtml = $"{EmbeddablePrefix}+json;type=html"; public const string Markdown = "text/markdown"; public const string PlainText = "text/plain"; 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 3b5fc68ac..0bf0f44f4 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 @@ -4,6 +4,7 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations; using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get; using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common; +using Digdir.Domain.Dialogporten.Domain; using Digdir.Tool.Dialogporten.GenerateFakeData; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; @@ -330,7 +331,11 @@ public async Task Cannot_Create_Title_Content_With_Html_MediaType_With_Correct_S { // Arrange var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); - createDialogCommand.Content.Title = CreateHtmlContentValueDto(); + createDialogCommand.Content.Title = new ContentValueDto + { + MediaType = MediaTypes.LegacyEmbeddableHtml, + Value = [new LocalizationDto { LanguageCode = "en", Value = "https://external.html" }] + }; var userWithLegacyScope = new IntegrationTestUser([new("scope", Constants.LegacyHtmlScope)]); Application.ConfigureServiceCollection(services => @@ -350,4 +355,62 @@ public async Task Cannot_Create_Title_Content_With_Html_MediaType_With_Correct_S .Should() .Be(1); } + + [Fact] + public async Task Cannot_Create_Title_Content_With_Embeddable_Html_MediaType_With_Correct_Scope() + { + // Arrange + var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); + createDialogCommand.Content.Title = new ContentValueDto + { + MediaType = MediaTypes.LegacyEmbeddableHtml, + Value = [new LocalizationDto { LanguageCode = "en", Value = "https://external.html" }] + }; + + var userWithLegacyScope = new IntegrationTestUser([new("scope", Constants.LegacyHtmlScope)]); + Application.ConfigureServiceCollection(services => + { + services.RemoveAll(); + services.AddSingleton(userWithLegacyScope); + }); + + // Act + var response = await Application.Send(createDialogCommand); + + // Assert + response.TryPickT2(out var validationError, out _).Should().BeTrue(); + validationError.Should().NotBeNull(); + validationError.Errors + .Count(e => e.AttemptedValue.Equals(MediaTypes.LegacyEmbeddableHtml)) + .Should() + .Be(1); + } + + [Fact] + public async Task Can_Create_MainContentRef_Content_With_Embeddable_Html_MediaType_With_Correct_Scope() + { + // Arrange + var expectedDialogId = GenerateBigEndianUuidV7(); + var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(id: expectedDialogId); + createDialogCommand.Content.MainContentReference = new ContentValueDto + { + MediaType = MediaTypes.LegacyEmbeddableHtml, + Value = [new LocalizationDto { LanguageCode = "en", Value = "https://external.html" }] + }; + + var userWithLegacyScope = new IntegrationTestUser([new("scope", Constants.LegacyHtmlScope)]); + Application.ConfigureServiceCollection(services => + { + services.RemoveAll(); + services.AddSingleton(userWithLegacyScope); + }); + + // Act + var response = await Application.Send(createDialogCommand); + + // Assert + response.TryPickT0(out var success, out _).Should().BeTrue(); + success.Should().NotBeNull(); + success.Value.Should().Be(expectedDialogId); + } } From 7af2951da62cf7c6aabb68d35c00751da9ebe76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 9 Oct 2024 11:09:31 +0200 Subject: [PATCH 2/5] woops --- .../V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) 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 0bf0f44f4..b6f2affc8 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 @@ -331,11 +331,7 @@ public async Task Cannot_Create_Title_Content_With_Html_MediaType_With_Correct_S { // Arrange var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(); - createDialogCommand.Content.Title = new ContentValueDto - { - MediaType = MediaTypes.LegacyEmbeddableHtml, - Value = [new LocalizationDto { LanguageCode = "en", Value = "https://external.html" }] - }; + createDialogCommand.Content.Title = CreateHtmlContentValueDto(); var userWithLegacyScope = new IntegrationTestUser([new("scope", Constants.LegacyHtmlScope)]); Application.ConfigureServiceCollection(services => From 4f3eab0aa96b330f9f8feddb0d589aec96dcb010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 9 Oct 2024 12:38:27 +0200 Subject: [PATCH 3/5] fix? --- docs/schema/V1/swagger.verified.json | 15 +++++++-------- .../Features/V1/Common/Content/ContentValueDto.cs | 5 ----- .../Dialogs/Commands/Create/CreateDialogDto.cs | 14 ++++++++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index b382f4cf1..5493bb968 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -70,7 +70,6 @@ "properties": { "mediaType": { "description": "Media type of the content (plaintext, Markdown). Can also indicate that the content is embeddable.", - "example": "text/plain\ntext/markdown\napplication/vnd.dialogporten.frontchannelembed", "type": "string" }, "value": { @@ -297,7 +296,7 @@ "additionalProperties": false, "properties": { "additionalInfo": { - "description": "Additional information about the dialog, this may contain Markdown.", + "description": "Additional information about the dialog.\nSupported media types: text/plain, text/markdown", "nullable": true, "oneOf": [ { @@ -306,7 +305,7 @@ ] }, "extendedStatus": { - "description": "Used as the human-readable label used to describe the \u0022ExtendedStatus\u0022 field. Must be text/plain.", + "description": "Used as the human-readable label used to describe the \u0022ExtendedStatus\u0022 field.\nSupported media types: text/plain", "nullable": true, "oneOf": [ { @@ -315,7 +314,7 @@ ] }, "mainContentReference": { - "description": "Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL.", + "description": "Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL.\nSupported media types: application/vnd.dialogporten.frontchannelembed\u002Bjson;type=markdown", "nullable": true, "oneOf": [ { @@ -324,7 +323,7 @@ ] }, "senderName": { - "description": "Overridden sender name. If not supplied, assume \u0022org\u0022 as the sender name. Must be text/plain if supplied.", + "description": "Overridden sender name. If not supplied, assume \u0022org\u0022 as the sender name. Must be text/plain if supplied.\nSupported media types: text/plain", "nullable": true, "oneOf": [ { @@ -333,7 +332,7 @@ ] }, "summary": { - "description": "A short summary of the dialog and its current state. Must be text/plain.", + "description": "A short summary of the dialog and its current state.\nSupported media types: text/plain", "oneOf": [ { "$ref": "#/components/schemas/ContentValueDto" @@ -341,7 +340,7 @@ ] }, "title": { - "description": "The title of the dialog. Must be text/plain.", + "description": "The title of the dialog.\nSupported media types: text/plain", "oneOf": [ { "$ref": "#/components/schemas/ContentValueDto" @@ -6474,4 +6473,4 @@ "url": "https://altinn-dev-api.azure-api.net/dialogporten" } ] -} \ No newline at end of file +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs index b322d74cf..2c6a9f77a 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs @@ -13,10 +13,5 @@ public sealed class ContentValueDto /// /// Media type of the content (plaintext, Markdown). Can also indicate that the content is embeddable. /// - /// - /// text/plain - /// text/markdown - /// application/vnd.dialogporten.frontchannelembed - /// public string MediaType { get; set; } = MediaTypes.PlainText; } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogDto.cs index 3d706fe9f..d59f59cda 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogDto.cs @@ -209,32 +209,38 @@ public sealed class CreateDialogDialogTransmissionDto public sealed class CreateDialogContentDto { /// - /// The title of the dialog. Must be text/plain. + /// The title of the dialog. + /// Supported media types: text/plain /// public ContentValueDto Title { get; set; } = null!; /// - /// A short summary of the dialog and its current state. Must be text/plain. + /// A short summary of the dialog and its current state. + /// Supported media types: text/plain /// public ContentValueDto Summary { get; set; } = null!; /// /// Overridden sender name. If not supplied, assume "org" as the sender name. Must be text/plain if supplied. + /// Supported media types: text/plain /// public ContentValueDto? SenderName { get; set; } /// - /// Additional information about the dialog, this may contain Markdown. + /// Additional information about the dialog. + /// Supported media types: text/plain, text/markdown /// public ContentValueDto? AdditionalInfo { get; set; } /// - /// Used as the human-readable label used to describe the "ExtendedStatus" field. Must be text/plain. + /// Used as the human-readable label used to describe the "ExtendedStatus" field. + /// Supported media types: text/plain /// public ContentValueDto? ExtendedStatus { get; set; } /// /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. + /// Supported media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown /// public ContentValueDto? MainContentReference { get; set; } } From c5f7760a4c4bdc22a3c31826b78e55bc37d617b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 9 Oct 2024 15:44:56 +0200 Subject: [PATCH 4/5] move legacy html to mediatypes class --- .../Features/V1/Common/Content/ContentValueDtoValidator.cs | 3 +-- src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs | 1 + .../V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs index 2b0ad77be..330b777be 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs @@ -18,7 +18,6 @@ internal interface IIgnoreOnAssemblyScan; internal sealed class ContentValueDtoValidator : AbstractValidator, IIgnoreOnAssemblyScan { - public const string LegacyHtmlMediaType = "text/html"; public ContentValueDtoValidator(DialogTransmissionContentType contentType) { @@ -74,7 +73,7 @@ private static string[] GetAllowedMediaTypes(DialogContentType contentType, IUse => contentType.Id switch { DialogContentType.Values.AdditionalInfo when UserHasLegacyHtmlScope(user) - => contentType.AllowedMediaTypes.Append(LegacyHtmlMediaType).ToArray(), + => contentType.AllowedMediaTypes.Append(MediaTypes.LegacyHtmlMediaType).ToArray(), DialogContentType.Values.MainContentReference when UserHasLegacyHtmlScope(user) => contentType.AllowedMediaTypes.Append(MediaTypes.LegacyEmbeddableHtml).ToArray(), _ => contentType.AllowedMediaTypes diff --git a/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs b/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs index da3ab4823..7702b3288 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs @@ -6,6 +6,7 @@ public static class MediaTypes public const string EmbeddableMarkdown = $"{EmbeddablePrefix}+json;type=markdown"; public const string LegacyEmbeddableHtml = $"{EmbeddablePrefix}+json;type=html"; + public const string LegacyHtmlMediaType = "text/html"; public const string Markdown = "text/markdown"; public const string PlainText = "text/plain"; } 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 b6f2affc8..003932562 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 @@ -277,7 +277,7 @@ public async Task Cannot_Create_Transmission_With_Empty_Content_Localization_Val .Be(2); } - private const string LegacyHtmlMediaType = ContentValueDtoValidator.LegacyHtmlMediaType; + private const string LegacyHtmlMediaType = MediaTypes.LegacyHtmlMediaType; private static ContentValueDto CreateHtmlContentValueDto() => new() { From a6d6ec67f3d8c23fc65c333bfa766841fe6b73a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 9 Oct 2024 15:46:47 +0200 Subject: [PATCH 5/5] remove "mediatype" from const --- .../Features/V1/Common/Content/ContentValueDtoValidator.cs | 2 +- src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs | 2 +- .../V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs index 330b777be..cffa0a34b 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs @@ -73,7 +73,7 @@ private static string[] GetAllowedMediaTypes(DialogContentType contentType, IUse => contentType.Id switch { DialogContentType.Values.AdditionalInfo when UserHasLegacyHtmlScope(user) - => contentType.AllowedMediaTypes.Append(MediaTypes.LegacyHtmlMediaType).ToArray(), + => contentType.AllowedMediaTypes.Append(MediaTypes.LegacyHtml).ToArray(), DialogContentType.Values.MainContentReference when UserHasLegacyHtmlScope(user) => contentType.AllowedMediaTypes.Append(MediaTypes.LegacyEmbeddableHtml).ToArray(), _ => contentType.AllowedMediaTypes diff --git a/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs b/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs index 7702b3288..6e2c53f9e 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/MediaTypes.cs @@ -6,7 +6,7 @@ public static class MediaTypes public const string EmbeddableMarkdown = $"{EmbeddablePrefix}+json;type=markdown"; public const string LegacyEmbeddableHtml = $"{EmbeddablePrefix}+json;type=html"; - public const string LegacyHtmlMediaType = "text/html"; + public const string LegacyHtml = "text/html"; public const string Markdown = "text/markdown"; public const string PlainText = "text/plain"; } 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 003932562..54f08226b 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 @@ -277,7 +277,7 @@ public async Task Cannot_Create_Transmission_With_Empty_Content_Localization_Val .Be(2); } - private const string LegacyHtmlMediaType = MediaTypes.LegacyHtmlMediaType; + private const string LegacyHtmlMediaType = MediaTypes.LegacyHtml; private static ContentValueDto CreateHtmlContentValueDto() => new() {