diff --git a/docs/schema/V1/schema.verified.graphql b/docs/schema/V1/schema.verified.graphql index def1f4701..460699eae 100644 --- a/docs/schema/V1/schema.verified.graphql +++ b/docs/schema/V1/schema.verified.graphql @@ -107,6 +107,7 @@ type Dialog { apiActions: [ApiAction!]! activities: [Activity!]! seenSinceLastUpdate: [SeenLog!]! + transmissions: [Transmission!]! } type DialogByIdDeleted implements DialogByIdError { @@ -198,6 +199,24 @@ type SeenLog { isCurrentEndUser: Boolean! } +type Transmission { + id: UUID! + createdAt: DateTime! + authorizationAttribute: String + isAuthorized: Boolean! + extendedType: String + relatedTransmissionId: UUID + type: TransmissionType! + sender: Actor! + content: TransmissionContent! + attachments: [Attachment!]! +} + +type TransmissionContent { + title: ContentValue! + summary: ContentValue! +} + input SearchDialogInput { "Filter by one or more service owner codes" org: [String!] @@ -293,6 +312,25 @@ enum HttpVerb { CONNECT } +enum TransmissionType { + "For general information, not related to any submissions" + INFORMATION + "Feedback\/receipt accepting a previous submission" + ACCEPTANCE + "Feedback\/error message rejecting a previous submission" + REJECTION + "Question\/request for more information" + REQUEST + "Critical information about the process" + ALERT + "Information about a formal decision (\"resolution\")" + DECISION + "A normal submission of some information\/form" + SUBMISSION + "A submission correcting\/overriding some previously submitted information" + CORRECTION +} + directive @authorize("The name of the authorization policy that determines access to the annotated resource." policy: String "Roles that are allowed to access the annotated resource." roles: [String!] "Defines when when the authorize directive shall be applied.By default the authorize directives are applied during the validation phase." apply: ApplyPolicy! = BEFORE_RESOLVER) repeatable on OBJECT | FIELD_DEFINITION "The `DateTime` scalar represents an ISO-8601 compliant date time type." diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index 5bcc04dc3..f047723d7 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -1967,6 +1967,12 @@ "$ref": "#/components/schemas/UpdateDialogSearchTagDto" } }, + "transmissions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateDialogDialogTransmissionDto" + } + }, "attachments": { "type": "array", "items": { @@ -2018,16 +2024,16 @@ "additionalProperties": false, "properties": { "title": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "summary": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "senderName": { "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2035,7 +2041,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2043,7 +2049,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2051,13 +2057,13 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] } } }, - "DialogContentValueDto": { + "ContentValueDto": { "type": "object", "additionalProperties": false, "properties": { @@ -2093,7 +2099,113 @@ } } }, - "UpdateDialogDialogAttachmentDto": { + "UpdateDialogDialogTransmissionDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "authorizationAttribute": { + "type": "string", + "nullable": true + }, + "extendedType": { + "type": "string", + "nullable": true + }, + "relatedTransmissionId": { + "type": "string", + "format": "guid", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/DialogTransmissionType_Values" + }, + "sender": { + "$ref": "#/components/schemas/UpdateDialogDialogTransmissionActorDto" + }, + "content": { + "$ref": "#/components/schemas/UpdateDialogDialogTransmissionContentDto" + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateDialogTransmissionAttachmentDto" + } + } + } + }, + "DialogTransmissionType_Values": { + "type": "string", + "description": "", + "x-enumNames": [ + "Information", + "Acceptance", + "Rejection", + "Request", + "Alert", + "Decision", + "Submission", + "Correction" + ], + "enum": [ + "Information", + "Acceptance", + "Rejection", + "Request", + "Alert", + "Decision", + "Submission", + "Correction" + ] + }, + "UpdateDialogDialogTransmissionActorDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "actorType": { + "$ref": "#/components/schemas/DialogActorType_Values" + }, + "actorName": { + "type": "string" + }, + "actorId": { + "type": "string" + } + } + }, + "DialogActorType_Values": { + "type": "string", + "description": "", + "x-enumNames": [ + "PartyRepresentative", + "ServiceOwner" + ], + "enum": [ + "PartyRepresentative", + "ServiceOwner" + ] + }, + "UpdateDialogDialogTransmissionContentDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "title": { + "$ref": "#/components/schemas/ContentValueDto" + }, + "summary": { + "$ref": "#/components/schemas/ContentValueDto" + } + } + }, + "UpdateDialogTransmissionAttachmentDto": { "type": "object", "additionalProperties": false, "properties": { @@ -2111,12 +2223,12 @@ "urls": { "type": "array", "items": { - "$ref": "#/components/schemas/UpdateDialogDialogAttachmentUrlDto" + "$ref": "#/components/schemas/UpdateDialogTransmissionAttachmentUrlDto" } } } }, - "UpdateDialogDialogAttachmentUrlDto": { + "UpdateDialogTransmissionAttachmentUrlDto": { "type": "object", "additionalProperties": false, "properties": { @@ -2134,11 +2246,11 @@ "nullable": true }, "consumerType": { - "$ref": "#/components/schemas/DialogAttachmentUrlConsumerType_Values" + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" } } }, - "DialogAttachmentUrlConsumerType_Values": { + "AttachmentUrlConsumerType_Values": { "type": "string", "description": "", "x-enumNames": [ @@ -2150,6 +2262,51 @@ "Api" ] }, + "UpdateDialogDialogAttachmentDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid", + "nullable": true + }, + "displayName": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationDto" + } + }, + "urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateDialogDialogAttachmentUrlDto" + } + } + } + }, + "UpdateDialogDialogAttachmentUrlDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid", + "nullable": true + }, + "url": { + "type": "string", + "format": "uri" + }, + "mediaType": { + "type": "string", + "nullable": true + }, + "consumerType": { + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" + } + } + }, "UpdateDialogDialogGuiActionDto": { "type": "object", "additionalProperties": false, @@ -2383,18 +2540,6 @@ } } }, - "DialogActorType_Values": { - "type": "string", - "description": "", - "x-enumNames": [ - "PartyRepresentative", - "ServiceOwner" - ], - "enum": [ - "PartyRepresentative", - "ServiceOwner" - ] - }, "PaginatedListOfSearchDialogDtoSO": { "type": "object", "additionalProperties": false, @@ -2590,16 +2735,16 @@ "additionalProperties": false, "properties": { "title": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "summary": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "senderName": { "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2607,7 +2752,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] } @@ -2697,6 +2842,12 @@ "$ref": "#/components/schemas/GetDialogDialogAttachmentDtoSO" } }, + "transmissions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogDialogTransmissionDtoSO" + } + }, "guiActions": { "type": "array", "items": { @@ -2730,16 +2881,16 @@ "additionalProperties": false, "properties": { "title": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "summary": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "senderName": { "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2747,7 +2898,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2755,7 +2906,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -2763,7 +2914,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] } @@ -2817,7 +2968,122 @@ "nullable": true }, "consumerType": { - "$ref": "#/components/schemas/DialogAttachmentUrlConsumerType_Values" + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" + } + } + }, + "GetDialogDialogTransmissionDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "authorizationAttribute": { + "type": "string", + "nullable": true + }, + "isAuthorized": { + "type": "boolean" + }, + "extendedType": { + "type": "string", + "nullable": true + }, + "relatedTransmissionId": { + "type": "string", + "format": "guid", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/DialogTransmissionType_Values" + }, + "sender": { + "$ref": "#/components/schemas/GetDialogDialogTransmissionActorDtoSO" + }, + "content": { + "$ref": "#/components/schemas/GetDialogDialogTransmissionContentDtoSO" + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogTransmissionAttachmentDtoSO" + } + } + } + }, + "GetDialogDialogTransmissionActorDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "actorType": { + "$ref": "#/components/schemas/DialogActorType_Values" + }, + "actorName": { + "type": "string" + }, + "actorId": { + "type": "string" + } + } + }, + "GetDialogDialogTransmissionContentDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "title": { + "$ref": "#/components/schemas/ContentValueDto" + }, + "summary": { + "$ref": "#/components/schemas/ContentValueDto" + } + } + }, + "GetDialogTransmissionAttachmentDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "displayName": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationDto" + } + }, + "urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogTransmissionAttachmentUrlDtoSO" + } + } + } + }, + "GetDialogTransmissionAttachmentUrlDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "url": { + "type": "string", + "format": "uri" + }, + "mediaType": { + "type": "string", + "nullable": true + }, + "consumerType": { + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" } } }, @@ -3078,6 +3344,12 @@ "$ref": "#/components/schemas/CreateDialogDialogAttachmentDto" } }, + "transmissions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateDialogDialogTransmissionDto" + } + }, "guiActions": { "type": "array", "items": { @@ -3103,16 +3375,16 @@ "additionalProperties": false, "properties": { "title": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "summary": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "senderName": { "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3120,7 +3392,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3128,7 +3400,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3136,7 +3408,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] } @@ -3187,7 +3459,118 @@ "nullable": true }, "consumerType": { - "$ref": "#/components/schemas/DialogAttachmentUrlConsumerType_Values" + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" + } + } + }, + "CreateDialogDialogTransmissionDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "authorizationAttribute": { + "type": "string", + "nullable": true + }, + "extendedType": { + "type": "string", + "format": "uri", + "nullable": true + }, + "relatedTransmissionId": { + "type": "string", + "format": "guid", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/DialogTransmissionType_Values" + }, + "sender": { + "$ref": "#/components/schemas/CreateDialogDialogTransmissionActorDto" + }, + "content": { + "$ref": "#/components/schemas/CreateDialogDialogTransmissionContentDto" + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateDialogTransmissionAttachmentDto" + } + } + } + }, + "CreateDialogDialogTransmissionActorDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "actorType": { + "$ref": "#/components/schemas/DialogActorType_Values" + }, + "actorName": { + "type": "string" + }, + "actorId": { + "type": "string" + } + } + }, + "CreateDialogDialogTransmissionContentDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "title": { + "$ref": "#/components/schemas/ContentValueDto" + }, + "summary": { + "$ref": "#/components/schemas/ContentValueDto" + } + } + }, + "CreateDialogTransmissionAttachmentDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid", + "nullable": true + }, + "displayName": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationDto" + } + }, + "urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateDialogTransmissionAttachmentUrlDto" + } + } + } + }, + "CreateDialogTransmissionAttachmentUrlDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "mediaType": { + "type": "string", + "nullable": true + }, + "consumerType": { + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" } } }, @@ -3692,16 +4075,16 @@ "additionalProperties": false, "properties": { "title": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "summary": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "senderName": { "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3709,7 +4092,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] } @@ -3791,6 +4174,12 @@ "$ref": "#/components/schemas/GetDialogDialogAttachmentDto" } }, + "transmissions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogDialogTransmissionDto" + } + }, "guiActions": { "type": "array", "items": { @@ -3822,16 +4211,16 @@ "additionalProperties": false, "properties": { "title": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "summary": { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" }, "senderName": { "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3839,7 +4228,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3847,7 +4236,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] }, @@ -3855,7 +4244,7 @@ "nullable": true, "oneOf": [ { - "$ref": "#/components/schemas/DialogContentValueDto" + "$ref": "#/components/schemas/ContentValueDto" } ] } @@ -3900,7 +4289,122 @@ "nullable": true }, "consumerType": { - "$ref": "#/components/schemas/DialogAttachmentUrlConsumerType_Values" + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" + } + } + }, + "GetDialogDialogTransmissionDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "authorizationAttribute": { + "type": "string", + "nullable": true + }, + "isAuthorized": { + "type": "boolean" + }, + "extendedType": { + "type": "string", + "nullable": true + }, + "relatedTransmissionId": { + "type": "string", + "format": "guid", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/DialogTransmissionType_Values" + }, + "sender": { + "$ref": "#/components/schemas/GetDialogDialogTransmissionActorDto" + }, + "content": { + "$ref": "#/components/schemas/GetDialogDialogTransmissionContentDto" + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogTransmissionAttachmentDto" + } + } + } + }, + "GetDialogDialogTransmissionActorDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "actorType": { + "$ref": "#/components/schemas/DialogActorType_Values" + }, + "actorName": { + "type": "string" + }, + "actorId": { + "type": "string" + } + } + }, + "GetDialogDialogTransmissionContentDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "title": { + "$ref": "#/components/schemas/ContentValueDto" + }, + "summary": { + "$ref": "#/components/schemas/ContentValueDto" + } + } + }, + "GetDialogTransmissionAttachmentDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "displayName": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationDto" + } + }, + "urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogTransmissionAttachmentUrlDto" + } + } + } + }, + "GetDialogTransmissionAttachmentUrlDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "url": { + "type": "string", + "format": "uri" + }, + "mediaType": { + "type": "string", + "nullable": true + }, + "consumerType": { + "$ref": "#/components/schemas/AttachmentUrlConsumerType_Values" } } }, @@ -4166,4 +4670,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs b/src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs index a506f0d45..188869408 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore; using System.Linq.Expressions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; namespace Digdir.Domain.Dialogporten.Application.Externals; @@ -14,11 +15,13 @@ public interface IDialogDbContext DbSet Dialogs { get; } DbSet DialogStatuses { get; } DbSet DialogActivities { get; } + DbSet DialogTransmissions { get; } + DbSet DialogApiActions { get; } DbSet DialogApiActionEndpoints { get; } DbSet DialogGuiActions { get; } DbSet DialogAttachments { get; } - DbSet DialogAttachmentUrls { get; } + DbSet AttachmentUrls { get; } DbSet DialogGuiActionTypes { get; } DbSet DialogActivityTypes { get; } @@ -27,7 +30,7 @@ public interface IDialogDbContext DbSet DialogSeenLog { get; } /// - /// Validate a property on the using a lambda + /// Validate a property on the using a lambda /// expression to specify the predicate only when the property is modified. /// /// diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentValueDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs similarity index 90% rename from src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentValueDto.cs rename to src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs index ba05739b7..f4a095aa2 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentValueDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs @@ -3,7 +3,7 @@ namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; -public class DialogContentValueDto +public class ContentValueDto { public List Value { get; set; } = []; public string MediaType { get; set; } = MediaTypes.PlainText; 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 new file mode 100644 index 000000000..87b02f2a3 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDtoValidator.cs @@ -0,0 +1,59 @@ +using Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation; +using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations; +using Digdir.Domain.Dialogporten.Domain; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using FluentValidation; + +namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; + +// DialogContentValueDtoValidator has constructor parameter input, and can't be registered in DI assembly scan +// This interface is used to ignore the class when scanning for validators +// The validator is manually created in the Create and Update validators +internal interface IIgnoreOnAssemblyScan; + +internal sealed class ContentValueDtoValidator : AbstractValidator, IIgnoreOnAssemblyScan +{ + public ContentValueDtoValidator(TransmissionContentType contentType) + { + RuleFor(x => x.MediaType) + .NotEmpty() + .Must(value => value is not null && contentType.AllowedMediaTypes.Contains(value)) + .WithMessage($"{{PropertyName}} '{{PropertyValue}}' is not allowed for content type {contentType.Name}. " + + $"Allowed media types are {string.Join(", ", contentType.AllowedMediaTypes.Select(x => $"'{x}'"))}"); + RuleForEach(x => x.Value) + .ContainsValidHtml() + .When(x => x.MediaType is not null && x.MediaType == MediaTypes.Html); + RuleForEach(x => x.Value) + .ContainsValidMarkdown() + .When(x => x.MediaType is not null && x.MediaType == MediaTypes.Markdown); + RuleForEach(x => x.Value) + .Must(x => Uri.TryCreate(x.Value, UriKind.Absolute, out var uri) && uri.Scheme == Uri.UriSchemeHttps) + .When(x => x.MediaType is not null && x.MediaType.StartsWith(MediaTypes.EmbeddablePrefix, StringComparison.InvariantCultureIgnoreCase)) + .WithMessage("{PropertyName} must be a valid HTTPS URL for embeddable content types"); + RuleFor(x => x.Value) + .NotEmpty() + .SetValidator(_ => new LocalizationDtosValidator(contentType.MaxLength)); + } + + public ContentValueDtoValidator(DialogContentType contentType) + { + RuleFor(x => x.MediaType) + .NotEmpty() + .Must(value => value is not null && contentType.AllowedMediaTypes.Contains(value)) + .WithMessage($"{{PropertyName}} '{{PropertyValue}}' is not allowed for content type {contentType.Name}. " + + $"Allowed media types are {string.Join(", ", contentType.AllowedMediaTypes.Select(x => $"'{x}'"))}"); + RuleForEach(x => x.Value) + .ContainsValidHtml() + .When(x => x.MediaType is not null && x.MediaType == MediaTypes.Html); + RuleForEach(x => x.Value) + .ContainsValidMarkdown() + .When(x => x.MediaType is not null && x.MediaType == MediaTypes.Markdown); + RuleForEach(x => x.Value) + .Must(x => Uri.TryCreate(x.Value, UriKind.Absolute, out var uri) && uri.Scheme == Uri.UriSchemeHttps) + .When(x => x.MediaType is not null && x.MediaType.StartsWith(MediaTypes.EmbeddablePrefix, StringComparison.InvariantCultureIgnoreCase)) + .WithMessage("{PropertyName} must be a valid HTTPS URL for embeddable content types"); + RuleFor(x => x.Value) + .NotEmpty() + .SetValidator(_ => new LocalizationDtosValidator(contentType.MaxLength)); + } +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentInputConverter.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentInputConverter.cs index 9789b3490..a6c9797bb 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentInputConverter.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentInputConverter.cs @@ -3,7 +3,8 @@ using Digdir.Domain.Dialogporten.Application.Common.Extensions.Enumerables; using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations; using Digdir.Domain.Dialogporten.Domain; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +// ReSharper disable ClassNeverInstantiated.Global namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; @@ -39,7 +40,7 @@ internal class DialogContentInputConverter : continue; } - if (sourceProperty.GetValue(source) is not DialogContentValueDto sourceValue) + if (sourceProperty.GetValue(source) is not ContentValueDto sourceValue) { continue; } @@ -85,13 +86,14 @@ internal class DialogContentOutputConverter : continue; } - property.SetValue(destination, context.Mapper.Map(source)); + property.SetValue(destination, context.Mapper.Map(source)); } return destination; } } +// ReSharper disable once ClassNeverInstantiated.Local file class PropertyCache { public static readonly Dictionary PropertyByName = typeof(T) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentValueDtoValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentValueDtoValidator.cs deleted file mode 100644 index de7de6fbc..000000000 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/DialogContentValueDtoValidator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation; -using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations; -using Digdir.Domain.Dialogporten.Domain; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; -using FluentValidation; - -namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; - -// DialogContentValueDtoValidator has constructor parameter input, and can't be registered in DI assembly scan -// This interface is used to ignore the class when scanning for validators -// The validator is manually created in the Create and Update validators -internal interface IIgnoreOnAssemblyScan; - -internal sealed class DialogContentValueDtoValidator : AbstractValidator, IIgnoreOnAssemblyScan -{ - public DialogContentValueDtoValidator(DialogContentType dialogContentType) - { - RuleFor(x => x.MediaType) - .NotEmpty() - .Must(value => value is not null && dialogContentType.AllowedMediaTypes.Contains(value)) - .WithMessage($"{{PropertyName}} '{{PropertyValue}}' is not allowed for content type {dialogContentType.Name}. " + - $"Allowed media types are {string.Join(", ", dialogContentType.AllowedMediaTypes.Select(x => $"'{x}'"))}"); - RuleForEach(x => x.Value) - .ContainsValidHtml() - .When(x => x.MediaType is not null && x.MediaType == MediaTypes.Html); - RuleForEach(x => x.Value) - .ContainsValidMarkdown() - .When(x => x.MediaType is not null && x.MediaType == MediaTypes.Markdown); - RuleForEach(x => x.Value) - .Must(x => Uri.TryCreate(x.Value, UriKind.Absolute, out var uri) && uri.Scheme == Uri.UriSchemeHttps) - .When(x => x.MediaType is not null && x.MediaType.StartsWith(MediaTypes.EmbeddablePrefix, StringComparison.InvariantCultureIgnoreCase)) - .WithMessage("{PropertyName} must be a valid HTTPS URL for embeddable content types"); - RuleFor(x => x.Value) - .NotEmpty() - .SetValidator(_ => new LocalizationDtosValidator(dialogContentType.MaxLength)); - } -} diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/MappingProfile.cs index ad1c998ef..49cbc9616 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/MappingProfile.cs @@ -1,5 +1,5 @@ using AutoMapper; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; @@ -8,7 +8,9 @@ public class MappingProfile : Profile public MappingProfile() { // See IntermediateDialogContent + CreateMap(); CreateMap(); - CreateMap(); + CreateMap(); + CreateMap(); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/TransmissionContentInputConverter.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/TransmissionContentInputConverter.cs new file mode 100644 index 000000000..e41a4e241 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/TransmissionContentInputConverter.cs @@ -0,0 +1,106 @@ +using AutoMapper; +using System.Reflection; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using Digdir.Domain.Dialogporten.Application.Common.Extensions.Enumerables; +using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations; +using Digdir.Domain.Dialogporten.Domain; + +// ReSharper disable ClassNeverInstantiated.Global + +namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; + +/// +/// TODO: Discuss this with the team later. It works for now +/// This class is used to map bewteen the incoming dto object and the internal transmission content structure. +/// Value needs to be mapped from a list of LocalizationDto in order for merging to work. +/// +/// We might want to consider combining this class with DialogContentInputConverter later. +/// + +internal class IntermediateTransmissionContent +{ + public TransmissionContentType.Values TypeId { get; set; } + public List Value { get; set; } = null!; + public string MediaType { get; set; } = MediaTypes.PlainText; +} + +internal class TransmissionContentInputConverter : + ITypeConverter?> + where TTransmissionContent : class, new() +{ + public List? Convert(TTransmissionContent? source, List? destinations, ResolutionContext context) + { + if (source is null) + { + return null; + } + + var sources = new List(); + + foreach (var transmissionContentType in TransmissionContentType.GetValues()) + { + if (!PropertyCache.PropertyByName.TryGetValue(transmissionContentType.Name, out var sourceProperty)) + { + continue; + } + + if (sourceProperty.GetValue(source) is not ContentValueDto sourceValue) + { + continue; + } + + sources.Add(new IntermediateTransmissionContent + { + TypeId = transmissionContentType.Id, + Value = sourceValue.Value, + MediaType = sourceValue.MediaType + }); + } + + destinations ??= []; + destinations + .Merge(sources, + destinationKeySelector: x => x.TypeId, + sourceKeySelector: x => x.TypeId, + create: context.Mapper.Map>, + update: context.Mapper.Update, + delete: DeleteDelegate.NoOp); + + return destinations; + } +} + +internal class TransmissionContentOutputConverter : + ITypeConverter?, TTransmissionContent?> + where TTransmissionContent : class, new() +{ + public TTransmissionContent? Convert(List? sources, TTransmissionContent? destination, ResolutionContext context) + { + if (sources is null) + { + return null; + } + + destination ??= new TTransmissionContent(); + + foreach (var source in sources) + { + if (!PropertyCache.PropertyByName.TryGetValue(source.TypeId.ToString(), out var property)) + { + continue; + } + + property.SetValue(destination, context.Mapper.Map(source)); + } + + return destination; + } +} + +// ReSharper disable once ClassNeverInstantiated.Local +file class PropertyCache +{ + public static readonly Dictionary PropertyByName = typeof(T) + .GetProperties() + .ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase); +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs index 4f28a2431..d4fbccfcf 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs @@ -5,6 +5,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using Digdir.Domain.Dialogporten.Domain.Http; namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get; @@ -32,11 +33,26 @@ public sealed class GetDialogDto public string? DialogToken { get; set; } public List Attachments { get; set; } = []; + public List Transmissions { get; set; } = []; public List GuiActions { get; set; } = []; public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; public List SeenSinceLastUpdate { get; set; } = []; +} + +public sealed class GetDialogDialogTransmissionDto +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public string? AuthorizationAttribute { get; set; } + public bool IsAuthorized { get; set; } + public string? ExtendedType { get; set; } + public Guid? RelatedTransmissionId { get; set; } + public DialogTransmissionType.Values Type { get; set; } + public GetDialogDialogTransmissionActorDto Sender { get; set; } = null!; + public GetDialogDialogTransmissionContentDto Content { get; set; } = null!; + public List Attachments { get; set; } = []; } public sealed class GetDialogDialogSeenLogDto @@ -56,14 +72,27 @@ public sealed class GetDialogDialogSeenLogActorDto public string ActorId { get; set; } = null!; } +public sealed class GetDialogDialogTransmissionActorDto +{ + public DialogActorType.Values ActorType { get; set; } + public string ActorName { get; set; } = null!; + public string ActorId { get; set; } = null!; +} + public sealed class GetDialogContentDto { - public DialogContentValueDto Title { get; set; } = null!; - public DialogContentValueDto Summary { get; set; } = null!; - public DialogContentValueDto? SenderName { get; set; } - public DialogContentValueDto? AdditionalInfo { get; set; } - public DialogContentValueDto? ExtendedStatus { get; set; } - public DialogContentValueDto? MainContentReference { get; set; } + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; + public ContentValueDto? SenderName { get; set; } + public ContentValueDto? AdditionalInfo { get; set; } + public ContentValueDto? ExtendedStatus { get; set; } + public ContentValueDto? MainContentReference { get; set; } +} + +public sealed class GetDialogDialogTransmissionContentDto +{ + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; } public sealed class GetDialogDialogActivityDto @@ -140,5 +169,22 @@ public sealed class GetDialogDialogAttachmentUrlDto public Uri Url { get; set; } = null!; public string? MediaType { get; set; } = null!; - public DialogAttachmentUrlConsumerType.Values ConsumerType { get; set; } + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } +} + +public sealed class GetDialogTransmissionAttachmentDto +{ + public Guid Id { get; set; } + + public List DisplayName { get; set; } = []; + public List Urls { get; set; } = []; +} + +public sealed class GetDialogTransmissionAttachmentUrlDto +{ + public Guid Id { get; set; } + public Uri Url { get; set; } = null!; + public string? MediaType { get; set; } = null!; + + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs index 01abb0fe7..f9039bc36 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs @@ -69,6 +69,12 @@ public async Task Handle(GetDialogQuery request, CancellationTo .ThenInclude(x => x!.Prompt!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode)) .Include(x => x.ApiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id)) .ThenInclude(x => x.Endpoints.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id)) + .Include(x => x.Transmissions) + .ThenInclude(x => x.Content) + .ThenInclude(x => x.Value.Localizations) + .Include(x => x.Transmissions).ThenInclude(x => x.Sender) + .Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.Urls) + .Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.DisplayName!.Localizations) .Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations) .Include(x => x.Activities).ThenInclude(x => x.PerformedBy) .Include(x => x.SeenLog diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs index 9f0b2115c..0f6e91388 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs @@ -6,7 +6,8 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get; @@ -43,11 +44,25 @@ public MappingProfile() CreateMap(); - CreateMap() + CreateMap() .ForMember(dest => dest.ConsumerType, opt => opt.MapFrom(src => src.ConsumerTypeId)); CreateMap?, GetDialogContentDto?>() .ConvertUsing>(); + + CreateMap() + .ForMember(dest => dest.ActorType, opt => opt.MapFrom(src => src.ActorTypeId)) + .ForMember(dest => dest.ActorId, opt => opt.MapFrom(src => IdentifierMasker.GetMaybeMaskedIdentifier(src.ActorId))); + + CreateMap?, GetDialogDialogTransmissionContentDto?>() + .ConvertUsing>(); + + CreateMap() + .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.TypeId)); + + CreateMap(); + CreateMap() + .ForMember(dest => dest.ConsumerType, opt => opt.MapFrom(src => src.ConsumerTypeId)); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs index b3e78c7c3..dc0d19744 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs @@ -5,7 +5,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search; @@ -26,7 +26,7 @@ public MappingProfile() )) .ForMember(dest => dest.GuiAttachmentCount, opt => opt.MapFrom(src => src.Attachments .Count(x => x.Urls - .Any(url => url.ConsumerTypeId == DialogAttachmentUrlConsumerType.Values.Gui)))) + .Any(url => url.ConsumerTypeId == AttachmentUrlConsumerType.Values.Gui)))) .ForMember(dest => dest.Content, opt => opt.MapFrom(src => src.Content.Where(x => x.Type.OutputInList))) .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs index be8300e0b..c42fd5fb0 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search; @@ -12,10 +12,10 @@ public sealed class SearchDialogDto : SearchDialogDtoBase public sealed class SearchDialogContentDto { - public DialogContentValueDto Title { get; set; } = null!; - public DialogContentValueDto Summary { get; set; } = null!; - public DialogContentValueDto? SenderName { get; set; } - public DialogContentValueDto? ExtendedStatus { get; set; } + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; + public ContentValueDto? SenderName { get; set; } + public ContentValueDto? ExtendedStatus { get; set; } } /// diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs index de5b32144..162fa2ce7 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs @@ -7,7 +7,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; using Digdir.Domain.Dialogporten.Domain.Http; using FluentValidation; @@ -16,6 +16,7 @@ namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialog internal sealed class CreateDialogCommandValidator : AbstractValidator { public CreateDialogCommandValidator( + IValidator transmissionValidator, IValidator attachmentValidator, IValidator guiActionValidator, IValidator apiActionValidator, @@ -97,6 +98,14 @@ public CreateDialogCommandValidator( RuleForEach(x => x.Attachments) .SetValidator(attachmentValidator); + RuleFor(x => x.Transmissions) + .UniqueBy(x => x.Id); + RuleForEach(x => x.Transmissions) + .IsIn(x => x.Transmissions, + dependentKeySelector: transmission => transmission.RelatedTransmissionId, + principalKeySelector: transmission => transmission.Id) + .SetValidator(transmissionValidator); + RuleFor(x => x.Activities) .UniqueBy(x => x.Id); RuleForEach(x => x.Activities) @@ -107,6 +116,42 @@ public CreateDialogCommandValidator( } } +internal sealed class CreateDialogDialogTransmissionDtoValidator : AbstractValidator +{ + public CreateDialogDialogTransmissionDtoValidator( + IValidator actorValidator, + IValidator contentValidator, + IValidator attachmentValidator) + { + RuleFor(x => x.Id) + .NotEqual(default(Guid)); + RuleFor(x => x.CreatedAt) + .IsInPast(); + RuleFor(x => x.ExtendedType) + .IsValidUri() + .MaximumLength(Constants.DefaultMaxUriLength) + .When(x => x.ExtendedType is not null); + RuleFor(x => x.Type) + .IsInEnum(); + RuleFor(x => x.RelatedTransmissionId) + .NotEqual(x => x.Id) + .WithMessage(x => $"A transmission cannot reference itself ({nameof(x.RelatedTransmissionId)} is equal to {nameof(x.Id)}, '{x.Id}').") + .When(x => x.RelatedTransmissionId.HasValue); + RuleFor(x => x.Sender) + .NotNull() + .SetValidator(actorValidator); + RuleFor(x => x.AuthorizationAttribute) + .MaximumLength(Constants.DefaultMaxStringLength); + RuleFor(x => x.Attachments) + .UniqueBy(x => x.Id); + RuleForEach(x => x.Attachments) + .SetValidator(attachmentValidator); + RuleFor(x => x.Content) + .NotEmpty() + .SetValidator(contentValidator); + } +} + internal sealed class CreateDialogContentDtoValidator : AbstractValidator { private static readonly Dictionary SourcePropertyMetaDataByName = typeof(CreateDialogContentDto) @@ -127,15 +172,15 @@ public CreateDialogContentDtoValidator() switch (propMetadata.NullabilityInfo.WriteState) { case NullabilityState.NotNull: - RuleFor(x => propMetadata.Property.GetValue(x) as DialogContentValueDto) + RuleFor(x => propMetadata.Property.GetValue(x) as ContentValueDto) .NotNull() .WithMessage($"{propertyName} must not be empty.") - .SetValidator(new DialogContentValueDtoValidator( + .SetValidator(new ContentValueDtoValidator( DialogContentType.GetContentType(propertyName))!); break; case NullabilityState.Nullable: - RuleFor(x => propMetadata.Property.GetValue(x) as DialogContentValueDto) - .SetValidator(new DialogContentValueDtoValidator( + RuleFor(x => propMetadata.Property.GetValue(x) as ContentValueDto) + .SetValidator(new ContentValueDtoValidator( DialogContentType.GetContentType(propertyName))!) .When(x => propMetadata.Property.GetValue(x) is not null); break; @@ -148,6 +193,24 @@ public CreateDialogContentDtoValidator() } } +internal sealed class CreateDialogDialogTransmissionContentDtoValidator : AbstractValidator +{ + private static readonly Dictionary SourcePropertyMetaDataByName = typeof(CreateDialogDialogTransmissionContentDto) + .GetProperties() + .ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase); + + public CreateDialogDialogTransmissionContentDtoValidator() + { + foreach (var (propertyName, propMetadata) in SourcePropertyMetaDataByName) + { + RuleFor(x => propMetadata.GetValue(x) as ContentValueDto) + .NotNull() + .WithMessage($"{propertyName} must not be empty.") + .SetValidator(new ContentValueDtoValidator(TransmissionContentType.GetContentType(propertyName))!); + } + } +} + internal sealed class CreateDialogDialogAttachmentDtoValidator : AbstractValidator { public CreateDialogDialogAttachmentDtoValidator( @@ -177,6 +240,35 @@ public CreateDialogDialogAttachmentUrlDtoValidator() } } +internal sealed class CreateDialogTransmissionAttachmentDtoValidator : AbstractValidator +{ + public CreateDialogTransmissionAttachmentDtoValidator( + IValidator> localizationsValidator, + IValidator urlValidator) + { + RuleFor(x => x.Id) + .NotEqual(default(Guid)); + RuleFor(x => x.DisplayName) + .SetValidator(localizationsValidator); + RuleFor(x => x.Urls) + .NotEmpty() + .ForEach(x => x.SetValidator(urlValidator)); + } +} + +internal sealed class CreateDialogTransmissionAttachmentUrlDtoValidator : AbstractValidator +{ + public CreateDialogTransmissionAttachmentUrlDtoValidator() + { + RuleFor(x => x.Url) + .NotNull() + .IsValidUri() + .MaximumLength(Constants.DefaultMaxUriLength); + RuleFor(x => x.ConsumerType) + .IsInEnum(); + } +} + internal sealed class CreateDialogSearchTagDtoValidator : AbstractValidator { public CreateDialogSearchTagDtoValidator() @@ -293,6 +385,28 @@ public CreateDialogDialogActivityDtoValidator( } } +internal sealed class CreateDialogDialogTransmissionActorDtoValidator : AbstractValidator +{ + public CreateDialogDialogTransmissionActorDtoValidator() + { + RuleFor(x => x.ActorType) + .IsInEnum(); + + RuleFor(x => x.ActorId) + .Must((dto, value) => value is null || dto.ActorName is null) + .WithMessage("Only one of 'ActorId' or 'ActorName' can be set, but not both."); + + RuleFor(x => x.ActorType) + .Must((dto, value) => (value == DialogActorType.Values.ServiceOwner && dto.ActorId is null && dto.ActorName is null) || + (value != DialogActorType.Values.ServiceOwner && (dto.ActorId is not null || dto.ActorName is not null))) + .WithMessage("If 'ActorType' is 'ServiceOwner', both 'ActorId' and 'ActorName' must be null. Otherwise, one of them must be set."); + + RuleFor(x => x.ActorId!) + .IsValidPartyIdentifier() + .When(x => x.ActorId is not null); + } +} + internal sealed class CreateDialogDialogActivityActorDtoValidator : AbstractValidator { public CreateDialogDialogActivityActorDtoValidator() 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 2736a578d..c6b0514eb 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 @@ -5,6 +5,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using Digdir.Domain.Dialogporten.Domain.Http; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Create; @@ -27,19 +28,42 @@ public class CreateDialogDto public List SearchTags { get; set; } = []; public List Attachments { get; set; } = []; + public List Transmissions { get; set; } = []; public List GuiActions { get; set; } = []; public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; } +public class CreateDialogDialogTransmissionDto +{ + public Guid? Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public string? AuthorizationAttribute { get; set; } + public Uri? ExtendedType { get; set; } + public Guid? RelatedTransmissionId { get; set; } + + public DialogTransmissionType.Values Type { get; set; } + + public CreateDialogDialogTransmissionActorDto Sender { get; set; } = null!; + + public CreateDialogDialogTransmissionContentDto Content { get; set; } = null!; + public List Attachments { get; set; } = []; +} + public sealed class CreateDialogContentDto { - public DialogContentValueDto Title { get; set; } = null!; - public DialogContentValueDto Summary { get; set; } = null!; - public DialogContentValueDto? SenderName { get; set; } - public DialogContentValueDto? AdditionalInfo { get; set; } - public DialogContentValueDto? ExtendedStatus { get; set; } - public DialogContentValueDto? MainContentReference { get; set; } + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; + public ContentValueDto? SenderName { get; set; } + public ContentValueDto? AdditionalInfo { get; set; } + public ContentValueDto? ExtendedStatus { get; set; } + public ContentValueDto? MainContentReference { get; set; } +} + +public sealed class CreateDialogDialogTransmissionContentDto +{ + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; } public sealed class CreateDialogSearchTagDto @@ -68,6 +92,13 @@ public sealed class CreateDialogDialogActivityActorDto public string? ActorId { get; set; } } +public sealed class CreateDialogDialogTransmissionActorDto +{ + public DialogActorType.Values ActorType { get; set; } + public string ActorName { get; set; } = null!; + public string ActorId { get; set; } = null!; +} + public sealed class CreateDialogDialogApiActionDto { public string Action { get; set; } = null!; @@ -114,5 +145,20 @@ public sealed class CreateDialogDialogAttachmentUrlDto public Uri Url { get; set; } = null!; public string? MediaType { get; set; } = null!; - public DialogAttachmentUrlConsumerType.Values ConsumerType { get; set; } + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } +} + +public sealed class CreateDialogTransmissionAttachmentDto +{ + public Guid? Id { get; set; } + public List DisplayName { get; set; } = []; + public List Urls { get; set; } = []; +} + +public sealed class CreateDialogTransmissionAttachmentUrlDto +{ + public Uri Url { get; set; } = null!; + public string? MediaType { get; set; } = null!; + + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/MappingProfile.cs index 2ee647356..fc3b83d9d 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/MappingProfile.cs @@ -5,7 +5,8 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Create; @@ -16,12 +17,10 @@ public MappingProfile() CreateMap() .ForMember(dest => dest.Status, opt => opt.Ignore()) .ForMember(dest => dest.StatusId, opt => opt.MapFrom(src => src.Status)); - - CreateMap(); - CreateMap(); - CreateMap() + CreateMap(); + CreateMap() .ForMember(dest => dest.ConsumerType, opt => opt.Ignore()) .ForMember(dest => dest.ConsumerTypeId, opt => opt.MapFrom(src => src.ConsumerType)); @@ -47,5 +46,21 @@ public MappingProfile() CreateMap?>() .ConvertUsing>(); + + CreateMap?>() + .ConvertUsing>(); + + CreateMap() + .ForMember(dest => dest.ActorType, opt => opt.Ignore()) + .ForMember(dest => dest.ActorTypeId, opt => opt.MapFrom(src => src.ActorType)); + + CreateMap() + .ForMember(dest => dest.Type, opt => opt.Ignore()) + .ForMember(dest => dest.TypeId, opt => opt.MapFrom(src => src.Type)); + + CreateMap(); + CreateMap() + .ForMember(dest => dest.ConsumerType, opt => opt.Ignore()) + .ForMember(dest => dest.ConsumerTypeId, opt => opt.MapFrom(src => src.ConsumerType)); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/MappingProfile.cs index 1e6afe90d..2b1c45885 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/MappingProfile.cs @@ -7,7 +7,8 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Update; @@ -49,7 +50,7 @@ public MappingProfile() CreateMap() .IgnoreComplexDestinationProperties(); - CreateMap() + CreateMap() .IgnoreComplexDestinationProperties() .ForMember(x => x.Id, opt => opt.Ignore()) .ForMember(dest => dest.ConsumerType, opt => opt.Ignore()) @@ -58,8 +59,8 @@ public MappingProfile() CreateMap?>() .ConvertUsing>(); - // Since this is append only, we don't need to merge with existing - // activity records and thus can map complex properties + // Since these are append only, we don't need to merge with existing + // activity/transmission records and thus can map complex properties CreateMap() .ForMember(dest => dest.Type, opt => opt.Ignore()) .ForMember(dest => dest.TypeId, opt => opt.MapFrom(src => src.Type)); @@ -68,13 +69,34 @@ public MappingProfile() .ForMember(dest => dest.ActorType, opt => opt.Ignore()) .ForMember(dest => dest.ActorTypeId, opt => opt.MapFrom(src => src.ActorType)); + CreateMap?>() + .ConvertUsing>(); + + CreateMap() + .ForMember(dest => dest.ActorType, opt => opt.Ignore()) + .ForMember(dest => dest.ActorTypeId, opt => opt.MapFrom(src => src.ActorType)); + + CreateMap() + .ForMember(dest => dest.Type, opt => opt.Ignore()) + .ForMember(dest => dest.TypeId, opt => opt.MapFrom(src => src.Type)); + + CreateMap() + .IgnoreComplexDestinationProperties(); + + CreateMap() + .IgnoreComplexDestinationProperties() + .ForMember(x => x.Id, opt => opt.Ignore()) + .ForMember(dest => dest.ConsumerType, opt => opt.Ignore()) + .ForMember(dest => dest.ConsumerTypeId, opt => opt.MapFrom(src => src.ConsumerType)); + // =========================================== // ================== Patch ================== // =========================================== CreateMap() - // Remove all existing activities, since this list is append only and - // existing activities should not be considered in the update request. - .ForMember(dest => dest.Activities, opt => opt.Ignore()); + // Remove all existing activities and transmissions, since these lists are append only and + // existing activities/transmissions should not be considered in the update request. + .ForMember(dest => dest.Activities, opt => opt.Ignore()) + .ForMember(dest => dest.Transmissions, opt => opt.Ignore()); CreateMap(); CreateMap(); CreateMap(); 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 dd5331f5a..b58b14a2e 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 @@ -8,6 +8,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using FluentValidation.Results; using MediatR; using Microsoft.EntityFrameworkCore; @@ -69,6 +70,7 @@ public async Task Handle(UpdateDialogCommand request, Cancel .ThenInclude(x => x!.Prompt!.Localizations) .Include(x => x.ApiActions) .ThenInclude(x => x.Endpoints) + .Include(x => x.Transmissions) .IgnoreQueryFilters() .Where(x => resourceIds.Contains(x.ServiceResource)) .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken); @@ -107,9 +109,13 @@ public async Task Handle(UpdateDialogCommand request, Cancel // Update primitive properties _mapper.Map(request.Dto, dialog); ValidateTimeFields(dialog); + AppendActivity(dialog, request.Dto); VerifyActivityRelations(dialog); + AppendTransmission(dialog, request.Dto); + VerifyTransmissionRelations(dialog); + dialog.SearchTags .Merge(request.Dto.SearchTags, destinationKeySelector: x => x.Value, @@ -246,6 +252,49 @@ private void VerifyActivityRelations(DialogEntity dialog) } } + private void AppendTransmission(DialogEntity dialog, UpdateDialogDto dto) + { + var newDialogTransmissions = _mapper.Map>(dto.Transmissions); + + var existingIds = dialog.Transmissions.Select(x => x.Id).ToList(); + + existingIds = existingIds.Intersect(newDialogTransmissions.Select(x => x.Id)).ToList(); + if (existingIds.Count != 0) + { + _domainContext.AddError( + nameof(UpdateDialogDto.Transmissions), + $"Entity '{nameof(DialogTransmission)}' with the following key(s) already exists: ({string.Join(", ", existingIds)})."); + return; + } + + dialog.Transmissions.AddRange(newDialogTransmissions); + + // Tell ef explicitly to add transmissions as new to the database. + _db.DialogTransmissions.AddRange(newDialogTransmissions); + } + + private void VerifyTransmissionRelations(DialogEntity dialog) + { + var relatedTransmissionIds = dialog.Transmissions.Where(x => x.RelatedTransmissionId is not null).Select(x => x.RelatedTransmissionId).ToList(); + if (relatedTransmissionIds.Count == 0) + { + return; + } + + var transmissionIds = dialog.Transmissions.Select(x => x.Id).ToList(); + + var invalidRelatedTransmissionIds = relatedTransmissionIds + .Where(id => !transmissionIds.Contains(id!.Value)) + .ToList(); + + if (invalidRelatedTransmissionIds.Count != 0) + { + _domainContext.AddError( + nameof(UpdateDialogDto.Transmissions), + $"Invalid '{nameof(DialogTransmission.RelatedTransmissionId)}, entity '{nameof(DialogTransmission)}' with the following key(s) does not exist: ({string.Join(", ", invalidRelatedTransmissionIds)})."); + } + } + private IEnumerable CreateApiActions(IEnumerable creatables) { return creatables.Select(x => @@ -278,7 +327,7 @@ private async Task> CreateAttachments(IEnumerable< foreach (var atttachmentDto in creatables) { var attachment = _mapper.Map(atttachmentDto); - attachment.Urls = _mapper.Map>(atttachmentDto.Urls); + attachment.Urls = _mapper.Map>(atttachmentDto.Urls); attachments.Add(attachment); } @@ -301,7 +350,7 @@ private Task UpdateAttachments(IEnumerable x.Id, sourceKeySelector: x => x.Id, - create: _mapper.Map>, + create: _mapper.Map>, update: _mapper.Update, delete: DeleteDelegate.NoOp); } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs index ff1f5fb69..24cfe888b 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs @@ -7,7 +7,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; using Digdir.Domain.Dialogporten.Domain.Http; using FluentValidation; @@ -28,6 +28,7 @@ public UpdateDialogCommandValidator(IValidator updateDialogDtoV internal sealed class UpdateDialogDtoValidator : AbstractValidator { public UpdateDialogDtoValidator( + IValidator transmissionValidator, IValidator attachmentValidator, IValidator guiActionValidator, IValidator apiActionValidator, @@ -92,6 +93,11 @@ public UpdateDialogDtoValidator( RuleForEach(x => x.Attachments) .SetValidator(attachmentValidator); + RuleFor(x => x.Transmissions) + .UniqueBy(x => x.Id); + RuleForEach(x => x.Transmissions) + .SetValidator(transmissionValidator); + RuleFor(x => x.Activities) .UniqueBy(x => x.Id); RuleForEach(x => x.Activities) @@ -99,6 +105,113 @@ public UpdateDialogDtoValidator( } } +internal sealed class UpdateDialogTransmissionAttachmentDtoValidator : AbstractValidator +{ + public UpdateDialogTransmissionAttachmentDtoValidator( + IValidator> localizationsValidator, + IValidator urlValidator) + { + RuleFor(x => x.Id) + .NotEqual(default(Guid)); + RuleFor(x => x.DisplayName) + .SetValidator(localizationsValidator); + RuleFor(x => x.Urls) + .UniqueBy(x => x.Id); + RuleFor(x => x.Urls) + .NotEmpty() + .ForEach(x => x.SetValidator(urlValidator)); + } +} + +internal sealed class UpdateDialogTransmissionAttachmentUrlDtoValidator : AbstractValidator +{ + public UpdateDialogTransmissionAttachmentUrlDtoValidator() + { + RuleFor(x => x.Url) + .NotNull() + .IsValidUri() + .MaximumLength(Constants.DefaultMaxUriLength); + RuleFor(x => x.ConsumerType) + .IsInEnum(); + } +} + +internal sealed class UpdateDialogDialogTransmissionActorDtoValidator : AbstractValidator +{ + public UpdateDialogDialogTransmissionActorDtoValidator() + { + RuleFor(x => x.ActorType) + .IsInEnum(); + + RuleFor(x => x.ActorId) + .Must((dto, value) => value is null || dto.ActorName is null) + .WithMessage("Only one of 'ActorId' or 'ActorName' can be set, but not both."); + + RuleFor(x => x.ActorType) + .Must((dto, value) => (value == DialogActorType.Values.ServiceOwner && dto.ActorId is null && dto.ActorName is null) || + (value != DialogActorType.Values.ServiceOwner && (dto.ActorId is not null || dto.ActorName is not null))) + .WithMessage("If 'ActorType' is 'ServiceOwner', both 'ActorId' and 'ActorName' must be null. Otherwise, one of them must be set."); + + RuleFor(x => x.ActorId!) + .IsValidPartyIdentifier() + .When(x => x.ActorId is not null); + } +} + +internal sealed class UpdateDialogDialogTransmissionContentDtoValidator : AbstractValidator +{ + private static readonly Dictionary SourcePropertyMetaDataByName = typeof(UpdateDialogDialogTransmissionContentDto) + .GetProperties() + .ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase); + + public UpdateDialogDialogTransmissionContentDtoValidator() + { + foreach (var (propertyName, propMetadata) in SourcePropertyMetaDataByName) + { + RuleFor(x => propMetadata.GetValue(x) as ContentValueDto) + .NotNull() + .WithMessage($"{propertyName} must not be empty.") + .SetValidator(new ContentValueDtoValidator(TransmissionContentType.GetContentType(propertyName))!); + } + } +} + +internal sealed class UpdateDialogDialogTransmissionDtoValidator : AbstractValidator +{ + public UpdateDialogDialogTransmissionDtoValidator( + IValidator actorValidator, + IValidator contentValidator, + IValidator attachmentValidator) + { + RuleFor(x => x.Id) + .NotEqual(default(Guid)); + RuleFor(x => x.CreatedAt) + .IsInPast(); + RuleFor(x => x.ExtendedType) + .IsValidUri() + .MaximumLength(Constants.DefaultMaxUriLength) + .When(x => x.ExtendedType is not null); + RuleFor(x => x.Type) + .IsInEnum(); + RuleFor(x => x.RelatedTransmissionId) + .NotEqual(x => x.Id) + .WithMessage(x => $"A transmission cannot reference itself ({nameof(x.RelatedTransmissionId)} is equal to {nameof(x.Id)}, '{x.Id}').") + .When(x => x.RelatedTransmissionId.HasValue); + RuleFor(x => x.Sender) + .NotNull() + .SetValidator(actorValidator); + RuleFor(x => x.AuthorizationAttribute) + .MaximumLength(Constants.DefaultMaxStringLength); + RuleFor(x => x.Attachments) + .UniqueBy(x => x.Id); + RuleForEach(x => x.Attachments) + .SetValidator(attachmentValidator); + RuleFor(x => x.Content) + .NotEmpty() + .SetValidator(contentValidator); + } +} + internal sealed class UpdateDialogContentDtoValidator : AbstractValidator { private static readonly Dictionary SourcePropertyMetaDataByName = @@ -119,16 +232,16 @@ public UpdateDialogContentDtoValidator() switch (propMetadata.NullabilityInfo.WriteState) { case NullabilityState.NotNull: - RuleFor(x => propMetadata.Property.GetValue(x) as DialogContentValueDto) + RuleFor(x => propMetadata.Property.GetValue(x) as ContentValueDto) .NotNull() .WithMessage($"{propertyName} must not be empty.") .SetValidator( - new DialogContentValueDtoValidator(DialogContentType.GetContentType(propertyName))!); + new ContentValueDtoValidator(DialogContentType.GetContentType(propertyName))!); break; case NullabilityState.Nullable: - RuleFor(x => propMetadata.Property.GetValue(x) as DialogContentValueDto) + RuleFor(x => propMetadata.Property.GetValue(x) as ContentValueDto) .SetValidator( - new DialogContentValueDtoValidator(DialogContentType.GetContentType(propertyName))!) + new ContentValueDtoValidator(DialogContentType.GetContentType(propertyName))!) .When(x => propMetadata.Property.GetValue(x) is not null); break; case NullabilityState.Unknown: diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogDto.cs index 23f16e0c2..a99fbe784 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogDto.cs @@ -5,6 +5,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using Digdir.Domain.Dialogporten.Domain.Http; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Update; @@ -24,20 +25,51 @@ public sealed class UpdateDialogDto public List SearchTags { get; set; } = []; + public List Transmissions { get; set; } = []; public List Attachments { get; set; } = []; public List GuiActions { get; set; } = []; public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; } +public class UpdateDialogDialogTransmissionDto +{ + public Guid? Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public string? AuthorizationAttribute { get; set; } + public string? ExtendedType { get; set; } + public Guid? RelatedTransmissionId { get; set; } + + public DialogTransmissionType.Values Type { get; set; } + + public UpdateDialogDialogTransmissionActorDto Sender { get; set; } = null!; + + public UpdateDialogDialogTransmissionContentDto Content { get; set; } = null!; + + public List Attachments { get; set; } = []; +} + +public class UpdateDialogDialogTransmissionContentDto +{ + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; +} + +public class UpdateDialogDialogTransmissionActorDto +{ + public DialogActorType.Values ActorType { get; set; } + public string ActorName { get; set; } = null!; + public string ActorId { get; set; } = null!; +} + public sealed class UpdateDialogContentDto { - public DialogContentValueDto Title { get; set; } = null!; - public DialogContentValueDto Summary { get; set; } = null!; - public DialogContentValueDto? SenderName { get; set; } - public DialogContentValueDto? AdditionalInfo { get; set; } - public DialogContentValueDto? ExtendedStatus { get; set; } - public DialogContentValueDto? MainContentReference { get; set; } + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; + public ContentValueDto? SenderName { get; set; } + public ContentValueDto? AdditionalInfo { get; set; } + public ContentValueDto? ExtendedStatus { get; set; } + public ContentValueDto? MainContentReference { get; set; } } public sealed class UpdateDialogSearchTagDto @@ -117,5 +149,21 @@ public sealed class UpdateDialogDialogAttachmentUrlDto public Uri Url { get; set; } = null!; public string? MediaType { get; set; } = null!; - public DialogAttachmentUrlConsumerType.Values ConsumerType { get; set; } + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } +} + +public class UpdateDialogTransmissionAttachmentDto +{ + public Guid? Id { get; set; } + public List DisplayName { get; set; } = []; + public List Urls { get; set; } = []; +} + +public sealed class UpdateDialogTransmissionAttachmentUrlDto +{ + public Guid? Id { get; set; } + public Uri Url { get; set; } = null!; + public string? MediaType { get; set; } = null!; + + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs index cfb73f88f..3c0ae0700 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs @@ -5,6 +5,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using Digdir.Domain.Dialogporten.Domain.Http; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get; @@ -34,12 +35,30 @@ public sealed class GetDialogDto public List? SearchTags { get; set; } public List Attachments { get; set; } = []; + public List Transmissions { get; set; } = []; public List GuiActions { get; set; } = []; public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; public List SeenSinceLastUpdate { get; set; } = []; } +public sealed class GetDialogDialogTransmissionDto +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public string? AuthorizationAttribute { get; set; } + public bool IsAuthorized { get; set; } + public string? ExtendedType { get; set; } + public Guid? RelatedTransmissionId { get; set; } + + public DialogTransmissionType.Values Type { get; set; } + + public GetDialogDialogTransmissionActorDto Sender { get; set; } = null!; + + public GetDialogDialogTransmissionContentDto Content { get; set; } = null!; + public List Attachments { get; set; } = []; +} + public sealed class GetDialogDialogSeenLogDto { public Guid Id { get; set; } @@ -56,14 +75,27 @@ public sealed class GetDialogDialogSeenLogActorDto public string ActorId { get; set; } = null!; } +public sealed class GetDialogDialogTransmissionActorDto +{ + public DialogActorType.Values ActorType { get; set; } + public string ActorName { get; set; } = null!; + public string ActorId { get; set; } = null!; +} + public sealed class GetDialogContentDto { - public DialogContentValueDto Title { get; set; } = null!; - public DialogContentValueDto Summary { get; set; } = null!; - public DialogContentValueDto? SenderName { get; set; } - public DialogContentValueDto? AdditionalInfo { get; set; } - public DialogContentValueDto? ExtendedStatus { get; set; } - public DialogContentValueDto? MainContentReference { get; set; } + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; + public ContentValueDto? SenderName { get; set; } + public ContentValueDto? AdditionalInfo { get; set; } + public ContentValueDto? ExtendedStatus { get; set; } + public ContentValueDto? MainContentReference { get; set; } +} + +public sealed class GetDialogDialogTransmissionContentDto +{ + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; } public sealed class GetDialogSearchTagDto @@ -142,5 +174,22 @@ public sealed class GetDialogDialogAttachmentUrlDto public Uri Url { get; set; } = null!; public string? MediaType { get; set; } = null!; - public DialogAttachmentUrlConsumerType.Values ConsumerType { get; set; } + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } +} + +public sealed class GetDialogTransmissionAttachmentDto +{ + public Guid Id { get; set; } + + public List DisplayName { get; set; } = []; + public List Urls { get; set; } = []; +} + +public sealed class GetDialogTransmissionAttachmentUrlDto +{ + public Guid Id { get; set; } + public Uri Url { get; set; } = null!; + public string? MediaType { get; set; } = null!; + + public AttachmentUrlConsumerType.Values ConsumerType { get; set; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs index 2ba826e71..c8258fa63 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs @@ -55,6 +55,12 @@ public async Task Handle(GetDialogQuery request, CancellationTo .ThenInclude(x => x!.Prompt!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode)) .Include(x => x.ApiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id)) .ThenInclude(x => x.Endpoints.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id)) + .Include(x => x.Transmissions) + .ThenInclude(x => x.Content) + .ThenInclude(x => x.Value.Localizations) + .Include(x => x.Transmissions).ThenInclude(x => x.Sender) + .Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.Urls) + .Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.DisplayName!.Localizations) .Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations) .Include(x => x.Activities).ThenInclude(x => x.PerformedBy) .Include(x => x.SeenLog diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs index 127a9043b..7b2b01610 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs @@ -5,7 +5,8 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get; @@ -18,19 +19,16 @@ public MappingProfile() .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)) .ForMember(dest => dest.SeenSinceLastUpdate, opt => opt.Ignore()); + CreateMap(); CreateMap() .ForMember(dest => dest.SeenAt, opt => opt.MapFrom(src => src.CreatedAt)); - CreateMap(); - CreateMap() .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.TypeId)); - CreateMap() .ForMember(dest => dest.ActorType, opt => opt.MapFrom(src => src.ActorTypeId)); CreateMap(); - CreateMap() .ForMember(dest => dest.HttpMethod, opt => opt.MapFrom(src => src.HttpMethodId)); @@ -39,8 +37,7 @@ public MappingProfile() .ForMember(dest => dest.HttpMethod, opt => opt.MapFrom(src => src.HttpMethodId)); CreateMap(); - - CreateMap() + CreateMap() .ForMember(dest => dest.ConsumerType, opt => opt.MapFrom(src => src.ConsumerTypeId)); CreateMap(); @@ -48,5 +45,17 @@ public MappingProfile() CreateMap?, GetDialogContentDto?>() .ConvertUsing>(); + CreateMap() + .ForMember(dest => dest.ActorType, opt => opt.MapFrom(src => src.ActorTypeId)); + + CreateMap?, GetDialogDialogTransmissionContentDto?>() + .ConvertUsing>(); + + CreateMap() + .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.TypeId)); + + CreateMap(); + CreateMap() + .ForMember(dest => dest.ConsumerType, opt => opt.MapFrom(src => src.ConsumerTypeId)); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs index 6a8d1cdaa..a6d6c13ed 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs @@ -4,7 +4,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Search; @@ -25,7 +25,7 @@ public MappingProfile() )) .ForMember(dest => dest.GuiAttachmentCount, opt => opt.MapFrom(src => src.Attachments .Count(x => x.Urls - .Any(url => url.ConsumerTypeId == DialogAttachmentUrlConsumerType.Values.Gui)))) + .Any(url => url.ConsumerTypeId == AttachmentUrlConsumerType.Values.Gui)))) .ForMember(dest => dest.Content, opt => opt.MapFrom(src => src.Content.Where(x => x.Type.OutputInList))) .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs index 95d9773a9..8ff024a35 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Content; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Search; @@ -12,10 +12,10 @@ public sealed class SearchDialogDto : SearchDialogDtoBase public sealed class SearchDialogContentDto { - public DialogContentValueDto Title { get; set; } = null!; - public DialogContentValueDto Summary { get; set; } = null!; - public DialogContentValueDto? SenderName { get; set; } - public DialogContentValueDto? ExtendedStatus { get; set; } + public ContentValueDto Title { get; set; } = null!; + public ContentValueDto Summary { get; set; } = null!; + public ContentValueDto? SenderName { get; set; } + public ContentValueDto? ExtendedStatus { get; set; } } /// diff --git a/src/Digdir.Domain.Dialogporten.Domain/Common/Extensions/AggregateNodeExtensions.cs b/src/Digdir.Domain.Dialogporten.Domain/Common/Extensions/AggregateNodeExtensions.cs index bdfa5a2f9..118504209 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Common/Extensions/AggregateNodeExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Common/Extensions/AggregateNodeExtensions.cs @@ -3,7 +3,7 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; using Digdir.Domain.Dialogporten.Domain.Localizations; using Digdir.Library.Entity.Abstractions.Features.Aggregate; using Digdir.Library.Entity.Abstractions.Features.Identifiable; @@ -54,14 +54,13 @@ private static IEnumerable ToLocalizationPathStrings(this LocalizationSe { DialogEntity => "dialog", DialogAttachment => "attachment", - DialogAttachmentUrl => "url", + AttachmentUrl => "url", DialogApiAction => "apiAction", DialogApiActionEndpoint => "endpoint", DialogGuiAction => "guiAction", DialogActivity => "activity", - DialogContent => "content", - DialogContentValue => "contentValue", + DialogContent => "content", DialogActivityDescription => "description", AttachmentDisplayName => "displayName", DialogGuiActionTitle => "title", diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachment.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/Attachment.cs similarity index 51% rename from src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachment.cs rename to src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/Attachment.cs index ebca0f016..4b6bf586d 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachment.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/Attachment.cs @@ -1,29 +1,38 @@ -using Digdir.Domain.Dialogporten.Domain.Localizations; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; +using Digdir.Domain.Dialogporten.Domain.Localizations; using Digdir.Library.Entity.Abstractions; using Digdir.Library.Entity.Abstractions.Features.Aggregate; namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -public class DialogAttachment : IEntity +public sealed class DialogAttachment : Attachment +{ + public Guid DialogId { get; set; } + public DialogEntity Dialog { get; set; } = null!; +} + +public sealed class TransmissionAttachment : Attachment +{ + public Guid TransmissionId { get; set; } + public DialogTransmission Transmission { get; set; } = null!; +} + +public abstract class Attachment : IEntity { public Guid Id { get; set; } public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset UpdatedAt { get; set; } - // === Dependent relationships === - public Guid DialogId { get; set; } - public DialogEntity Dialog { get; set; } = null!; - // === Principal relationships === [AggregateChild] - public AttachmentDisplayName? DisplayName { get; set; } + public List Urls { get; set; } = []; [AggregateChild] - public List Urls { get; set; } = []; + public AttachmentDisplayName? DisplayName { get; set; } } -public class AttachmentDisplayName : LocalizationSet +public sealed class AttachmentDisplayName : LocalizationSet { public Guid AttachmentId { get; set; } - public DialogAttachment Attachment { get; set; } = null!; + public Attachment Attachment { get; set; } = null!; } diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/AttachmentUrl.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/AttachmentUrl.cs new file mode 100644 index 000000000..8105672d4 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/AttachmentUrl.cs @@ -0,0 +1,20 @@ +using Digdir.Library.Entity.Abstractions; + +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; + +public sealed class AttachmentUrl : IEntity +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public DateTimeOffset UpdatedAt { get; set; } + + public string? MediaType { get; set; } = null!; + public Uri Url { get; set; } = null!; + + // === Dependent relationships === + public AttachmentUrlConsumerType.Values ConsumerTypeId { get; set; } + public AttachmentUrlConsumerType ConsumerType { get; set; } = null!; + + public Guid AttachmentId { get; set; } + public Attachment Attachment { get; set; } = null!; +} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/AttachmentUrlConsumerType.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/AttachmentUrlConsumerType.cs new file mode 100644 index 000000000..b0ee5d1cd --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/AttachmentUrlConsumerType.cs @@ -0,0 +1,15 @@ +using Digdir.Library.Entity.Abstractions.Features.Lookup; + +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; + +public class AttachmentUrlConsumerType : AbstractLookupEntity +{ + public AttachmentUrlConsumerType(Values id) : base(id) { } + public override AttachmentUrlConsumerType MapValue(Values id) => new(id); + + public enum Values + { + Gui = 1, + Api = 2 + } +} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachmentUrl.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachmentUrl.cs deleted file mode 100644 index 52c75b3bf..000000000 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachmentUrl.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Digdir.Library.Entity.Abstractions; - -namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; - -public class DialogAttachmentUrl : IEntity -{ - public Guid Id { get; set; } - public DateTimeOffset CreatedAt { get; set; } - public DateTimeOffset UpdatedAt { get; set; } - - public string? MediaType { get; set; } = null!; - public Uri Url { get; set; } = null!; - - // === Dependent relationships === - public DialogAttachmentUrlConsumerType.Values ConsumerTypeId { get; set; } - public DialogAttachmentUrlConsumerType ConsumerType { get; set; } = null!; - - public Guid DialogAttachmentId { get; set; } - public DialogAttachment DialogAttachment { get; set; } = null!; -} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachmentUrlConsumerType.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachmentUrlConsumerType.cs deleted file mode 100644 index 3316c9f97..000000000 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Attachments/DialogAttachmentUrlConsumerType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Digdir.Library.Entity.Abstractions.Features.Lookup; - -namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; - -public class DialogAttachmentUrlConsumerType : AbstractLookupEntity -{ - public DialogAttachmentUrlConsumerType(Values id) : base(id) { } - public override DialogAttachmentUrlConsumerType MapValue(Values id) => new(id); - - public enum Values - { - Gui = 1, - Api = 2 - } -} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Content/DialogContent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/DialogContent.cs similarity index 86% rename from src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Content/DialogContent.cs rename to src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/DialogContent.cs index 452397155..d6423064d 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Content/DialogContent.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/DialogContent.cs @@ -2,9 +2,9 @@ using Digdir.Library.Entity.Abstractions; using Digdir.Library.Entity.Abstractions.Features.Aggregate; -namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; -public class DialogContent : IEntity +public sealed class DialogContent : IEntity { public Guid Id { get; set; } public DateTimeOffset CreatedAt { get; set; } @@ -12,7 +12,6 @@ public class DialogContent : IEntity public string? MediaType { get; set; } - // === Dependent relationships === public Guid DialogId { get; set; } public DialogEntity Dialog { get; set; } = null!; @@ -24,7 +23,7 @@ public class DialogContent : IEntity public DialogContentValue Value { get; set; } = null!; } -public class DialogContentValue : LocalizationSet +public sealed class DialogContentValue : LocalizationSet { public Guid DialogContentId { get; set; } public DialogContent DialogContent { get; set; } = null!; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Content/DialogContentType.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/DialogContentType.cs similarity index 99% rename from src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Content/DialogContentType.cs rename to src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/DialogContentType.cs index 29b1e00ad..b70da623b 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Content/DialogContentType.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/DialogContentType.cs @@ -1,7 +1,7 @@ using Digdir.Domain.Dialogporten.Domain.Common; using Digdir.Library.Entity.Abstractions.Features.Lookup; -namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; public class DialogContentType : AbstractLookupEntity { @@ -18,6 +18,7 @@ public enum Values public bool Required { get; private init; } public bool OutputInList { get; private init; } + public int MaxLength { get; private init; } public string[] AllowedMediaTypes { get; init; } = []; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/TransmissionContent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/TransmissionContent.cs new file mode 100644 index 000000000..fe44c9740 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/TransmissionContent.cs @@ -0,0 +1,32 @@ +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; +using Digdir.Domain.Dialogporten.Domain.Localizations; +using Digdir.Library.Entity.Abstractions; +using Digdir.Library.Entity.Abstractions.Features.Aggregate; + +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; + +public sealed class TransmissionContent : IEntity +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public DateTimeOffset UpdatedAt { get; set; } + + public string? MediaType { get; set; } + + // === Principal relationships === + public Guid TransmissionId { get; set; } + public DialogTransmission Transmission { get; set; } = null!; + + public TransmissionContentType.Values TypeId { get; set; } + public TransmissionContentType Type { get; set; } = null!; + + // === Principal relationships === + [AggregateChild] + public TransmissionContentValue Value { get; set; } = null!; +} + +public sealed class TransmissionContentValue : LocalizationSet +{ + public Guid TransmissionContentId { get; set; } + public TransmissionContent TransmissionContent { get; set; } = null!; +} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/TransmissionContentType.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/TransmissionContentType.cs new file mode 100644 index 000000000..007a40c1e --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Contents/TransmissionContentType.cs @@ -0,0 +1,48 @@ +using Digdir.Domain.Dialogporten.Domain.Common; +using Digdir.Library.Entity.Abstractions.Features.Lookup; + +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; + +public class TransmissionContentType : AbstractLookupEntity +{ + public TransmissionContentType(Values id) : base(id) { } + public enum Values + { + Title = 1, + Summary = 2 + } + + public bool Required { get; private init; } + public int MaxLength { get; private init; } + + public string[] AllowedMediaTypes { get; init; } = []; + + public static TransmissionContentType GetContentType(string contentType) => contentType switch + { + nameof(Values.Title) => GetValue(Values.Title), + nameof(Values.Summary) => GetValue(Values.Summary), + _ => throw new ArgumentOutOfRangeException(nameof(contentType), contentType, null) + }; + + public override TransmissionContentType MapValue(Values id) => id switch + { + Values.Title => new(id) + { + Required = true, + MaxLength = Constants.DefaultMaxStringLength, + AllowedMediaTypes = [MediaTypes.PlainText] + }, + Values.Summary => new(id) + { + Required = true, + MaxLength = Constants.DefaultMaxStringLength, + AllowedMediaTypes = [MediaTypes.PlainText] + }, + _ => throw new ArgumentOutOfRangeException(nameof(id), id, null) + }; + + public static readonly Values[] RequiredTypes = GetValues() + .Where(x => x.Required) + .Select(x => x.Id) + .ToArray(); +} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs index 9ac8adff3..a71c5d6fe 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs @@ -2,7 +2,8 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Events; using Digdir.Library.Entity.Abstractions; using Digdir.Library.Entity.Abstractions.Features.Aggregate; @@ -41,6 +42,10 @@ public class DialogEntity : public DialogStatus Status { get; set; } = null!; // === Principal relationships === + + [AggregateChild] + public List Transmissions { get; set; } = []; + [AggregateChild] public List Content { get; set; } = []; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Transmissions/DialogTransmission.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Transmissions/DialogTransmission.cs new file mode 100644 index 000000000..2cd28439c --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Transmissions/DialogTransmission.cs @@ -0,0 +1,33 @@ +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using Digdir.Library.Entity.Abstractions.Features.Immutable; + +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; + +public class DialogTransmission : IImmutableEntity +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + + public string? AuthorizationAttribute { get; set; } + + public DialogActor Sender { get; set; } = null!; + + public Uri? ExtendedType { get; set; } + + public DialogTransmissionType.Values TypeId { get; set; } + public DialogTransmissionType Type { get; set; } = null!; + + // === Principal relationships === + public List Content { get; set; } = []; + + public List Attachments { get; set; } = []; + + // === Dependent relationships === + public Guid DialogId { get; set; } + public DialogEntity Dialog { get; set; } = null!; + + public Guid? RelatedTransmissionId { get; set; } + public DialogTransmission? RelatedTransmission { get; set; } +} diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Transmissions/DialogTransmissionType.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Transmissions/DialogTransmissionType.cs new file mode 100644 index 000000000..497e0761f --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Transmissions/DialogTransmissionType.cs @@ -0,0 +1,52 @@ +using Digdir.Library.Entity.Abstractions.Features.Lookup; + +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; + +public class DialogTransmissionType : AbstractLookupEntity +{ + public DialogTransmissionType(Values id) : base(id) { } + public override DialogTransmissionType MapValue(Values id) => new(id); + + public enum Values + { + /// + /// For general information, not related to any submissions + /// + Information = 1, + + /// + /// Feedback/receipt accepting a previous submission + /// + Acceptance = 2, + + /// + /// Feedback/error message rejecting a previous submission + /// + Rejection = 3, + + /// + /// Question/request for more information + /// + Request = 4, + + /// + /// Critical information about the process + /// + Alert = 5, + + /// + /// Information about a formal decision ("resolution") + /// + Decision = 6, + + /// + /// A normal submission of some information/form + /// + Submission = 7, + + /// + /// A submission correcting/overriding some previously submitted information + /// + Correction = 8, + } +} diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Common/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Common/MappingProfile.cs index 324ff7dd1..1d368f1e6 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Common/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Common/MappingProfile.cs @@ -12,7 +12,7 @@ public MappingProfile() { CreateMap(); - CreateMap(); + CreateMap(); CreateMap(); CreateMap(); diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/MappingProfile.cs index 8276fdd2e..43e53ad72 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/MappingProfile.cs @@ -24,7 +24,14 @@ public MappingProfile() .ForMember(dest => dest.HttpMethod, opt => opt.MapFrom(src => src.HttpMethod)); CreateMap(); - CreateMap(); + + CreateMap() + .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.Type)); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(dest => dest.ConsumerType, opt => opt.MapFrom(src => src.ConsumerType)); + CreateMap(); } } diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs index b3146fb6f..4ab151ece 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs @@ -56,6 +56,49 @@ public sealed class Dialog public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; public List SeenSinceLastUpdate { get; set; } = []; + public List Transmissions { get; set; } = []; +} + +public sealed class Transmission +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public string? AuthorizationAttribute { get; set; } + public bool IsAuthorized { get; set; } + public string? ExtendedType { get; set; } + public Guid? RelatedTransmissionId { get; set; } + + public TransmissionType Type { get; set; } + public Actor Sender { get; set; } = null!; + public TransmissionContent Content { get; set; } = null!; + public List Attachments { get; set; } = []; +} + +public enum TransmissionType +{ + [GraphQLDescription("For general information, not related to any submissions")] + Information = 1, + + [GraphQLDescription("Feedback/receipt accepting a previous submission")] + Acceptance = 2, + + [GraphQLDescription("Feedback/error message rejecting a previous submission")] + Rejection = 3, + + [GraphQLDescription("Question/request for more information")] + Request = 4, + + [GraphQLDescription("Critical information about the process")] + Alert = 5, + + [GraphQLDescription("Information about a formal decision (\"resolution\")")] + Decision = 6, + + [GraphQLDescription("A normal submission of some information/form")] + Submission = 7, + + [GraphQLDescription("A submission correcting/overriding some previously submitted information")] + Correction = 8, } public sealed class Content @@ -68,6 +111,12 @@ public sealed class Content public ContentValue? MainContentReference { get; set; } } +public sealed class TransmissionContent +{ + public ContentValue Title { get; set; } = null!; + public ContentValue Summary { get; set; } = null!; +} + public sealed class ApiAction { public Guid Id { get; set; } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/Content/DialogContentConfiguration.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/Content/DialogContentConfiguration.cs index cad12296f..6465d7457 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/Content/DialogContentConfiguration.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/Content/DialogContentConfiguration.cs @@ -1,4 +1,4 @@ -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -8,3 +8,9 @@ internal class DialogContentConfiguration : IEntityTypeConfiguration builder) => builder.HasIndex(x => new { x.DialogId, x.TypeId }).IsUnique(); } + +internal class TransmissionContentConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + => builder.HasIndex(x => new { x.TransmissionId, x.TypeId }).IsUnique(); +} diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs index 344c24458..37f89fa77 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs @@ -3,7 +3,6 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; using Digdir.Domain.Dialogporten.Domain.Outboxes; using Digdir.Domain.Dialogporten.Infrastructure.Persistence.ValueConverters; using Digdir.Library.Entity.Abstractions.Features.Identifiable; @@ -14,6 +13,8 @@ using System.Linq.Expressions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; namespace Digdir.Domain.Dialogporten.Infrastructure.Persistence; @@ -24,15 +25,16 @@ public DialogDbContext(DbContextOptions options) : base(options public DbSet Dialogs => Set(); public DbSet DialogStatuses => Set(); public DbSet DialogActivities => Set(); + public DbSet DialogActivityTypes => Set(); public DbSet DialogApiActions => Set(); public DbSet DialogApiActionEndpoints => Set(); public DbSet DialogGuiActions => Set(); public DbSet DialogAttachments => Set(); - public DbSet DialogAttachmentUrls => Set(); + public DbSet AttachmentUrls => Set(); public DbSet DialogGuiActionTypes => Set(); - public DbSet DialogActivityTypes => Set(); + public DbSet DialogTransmissions => Set(); public DbSet DialogSeenLog => Set(); - public DbSet DialogContentTypes => Set(); + public DbSet ContentTypes => Set(); public DbSet DialogContent => Set(); public DbSet DialogActors => Set(); diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240729223752_AddTransmissions.Designer.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240729223752_AddTransmissions.Designer.cs new file mode 100644 index 000000000..d0fe13583 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240729223752_AddTransmissions.Designer.cs @@ -0,0 +1,1700 @@ +// +using System; +using Digdir.Domain.Dialogporten.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Digdir.Domain.Dialogporten.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(DialogDbContext))] + [Migration("20240729223752_AddTransmissions")] + partial class AddTransmissions + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AuthorizationAttribute") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.ToTable("DialogApiAction"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiActionEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("ActionId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Deprecated") + .HasColumnType("boolean"); + + b.Property("DocumentationUrl") + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("HttpMethodId") + .HasColumnType("integer"); + + b.Property("RequestSchema") + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("ResponseSchema") + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("SunsetAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("Version") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.HasIndex("ActionId"); + + b.HasIndex("HttpMethodId"); + + b.ToTable("DialogApiActionEndpoint"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AuthorizationAttribute") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("HttpMethodId") + .HasColumnType("integer"); + + b.Property("IsDeleteDialogAction") + .HasColumnType("boolean"); + + b.Property("PriorityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("HttpMethodId"); + + b.HasIndex("PriorityId"); + + b.ToTable("DialogGuiAction"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPriority", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogGuiActionPriority"); + + b.HasData( + new + { + Id = 1, + Name = "Primary" + }, + new + { + Id = 2, + Name = "Secondary" + }, + new + { + Id = 3, + Name = "Tertiary" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("ExtendedType") + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("PerformedById") + .HasColumnType("uuid"); + + b.Property("RelatedActivityId") + .HasColumnType("uuid"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("PerformedById"); + + b.HasIndex("RelatedActivityId"); + + b.HasIndex("TypeId"); + + b.ToTable("DialogActivity"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivityType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogActivityType"); + + b.HasData( + new + { + Id = 1, + Name = "DialogCreated" + }, + new + { + Id = 2, + Name = "DialogClosed" + }, + new + { + Id = 3, + Name = "Information" + }, + new + { + Id = 4, + Name = "TransmissionOpened" + }, + new + { + Id = 5, + Name = "PaymentMade" + }, + new + { + Id = 6, + Name = "SignatureProvided" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("ActorId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ActorName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ActorTypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ActorTypeId"); + + b.ToTable("DialogActor"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActorType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogActorType"); + + b.HasData( + new + { + Id = 1, + Name = "PartyRepresentative" + }, + new + { + Id = 2, + Name = "ServiceOwner" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.HasKey("Id"); + + b.ToTable("Attachment"); + + b.HasDiscriminator().HasValue("Attachment"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrl", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("AttachmentId") + .HasColumnType("uuid"); + + b.Property("ConsumerTypeId") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("MediaType") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.HasKey("Id"); + + b.HasIndex("AttachmentId"); + + b.HasIndex("ConsumerTypeId"); + + b.ToTable("AttachmentUrl"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrlConsumerType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("AttachmentUrlConsumerType"); + + b.HasData( + new + { + Id = 1, + Name = "Gui" + }, + new + { + Id = 2, + Name = "Api" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("MediaType") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.HasIndex("DialogId", "TypeId") + .IsUnique(); + + b.ToTable("DialogContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AllowedMediaTypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("MaxLength") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("OutputInList") + .HasColumnType("boolean"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("DialogContentType"); + + b.HasData( + new + { + Id = 1, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "Title", + OutputInList = true, + Required = true + }, + new + { + Id = 2, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "SenderName", + OutputInList = true, + Required = false + }, + new + { + Id = 3, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "Summary", + OutputInList = true, + Required = true + }, + new + { + Id = 4, + AllowedMediaTypes = new[] { "text/html", "text/plain", "text/markdown" }, + MaxLength = 1023, + Name = "AdditionalInfo", + OutputInList = false, + Required = false + }, + new + { + Id = 5, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 20, + Name = "ExtendedStatus", + OutputInList = true, + Required = false + }, + new + { + Id = 6, + AllowedMediaTypes = new[] { "application/vnd.dialogporten.frontchannelembed+json;type=markdown" }, + MaxLength = 1023, + Name = "MainContentReference", + OutputInList = false, + Required = false + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("MediaType") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.HasIndex("TransmissionId", "TypeId") + .IsUnique(); + + b.ToTable("TransmissionContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AllowedMediaTypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("MaxLength") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("TransmissionContentType"); + + b.HasData( + new + { + Id = 1, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "Title", + Required = true + }, + new + { + Id = 2, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "Summary", + Required = true + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Deleted") + .HasColumnType("boolean"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DueAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExtendedStatus") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ExternalReference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Org") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .UseCollation("C"); + + b.Property("Party") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .UseCollation("C"); + + b.Property("Progress") + .HasColumnType("integer"); + + b.Property("Revision") + .IsConcurrencyToken() + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("ServiceResource") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .UseCollation("C"); + + b.Property("ServiceResourceType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("StatusId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("VisibleFrom") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("DueAt"); + + b.HasIndex("Org"); + + b.HasIndex("Party"); + + b.HasIndex("ServiceResource"); + + b.HasIndex("StatusId"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("Dialog", (string)null); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSearchTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(63) + .HasColumnType("character varying(63)"); + + b.HasKey("Id"); + + b.HasIndex("DialogId", "Value") + .IsUnique(); + + b.ToTable("DialogSearchTag"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSeenLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("EndUserTypeId") + .HasColumnType("integer"); + + b.Property("IsViaServiceOwner") + .HasColumnType("boolean"); + + b.Property("SeenById") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("EndUserTypeId"); + + b.HasIndex("SeenById"); + + b.ToTable("DialogSeenLog"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogStatus", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogStatus"); + + b.HasData( + new + { + Id = 1, + Name = "New" + }, + new + { + Id = 2, + Name = "InProgress" + }, + new + { + Id = 3, + Name = "Signing" + }, + new + { + Id = 4, + Name = "Processing" + }, + new + { + Id = 5, + Name = "RequiresAttention" + }, + new + { + Id = 6, + Name = "Completed" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogUserType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogUserType"); + + b.HasData( + new + { + Id = 0, + Name = "Unknown" + }, + new + { + Id = 1, + Name = "Person" + }, + new + { + Id = 2, + Name = "LegacySystemUser" + }, + new + { + Id = 3, + Name = "SystemUser" + }, + new + { + Id = 4, + Name = "ServiceOwner" + }, + new + { + Id = 5, + Name = "ServiceOwnerOnBehalfOfPerson" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("AuthorizationAttribute") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("ExtendedType") + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("RelatedTransmissionId") + .HasColumnType("uuid"); + + b.Property("SenderId") + .HasColumnType("uuid"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("RelatedTransmissionId"); + + b.HasIndex("SenderId"); + + b.HasIndex("TypeId"); + + b.ToTable("DialogTransmission"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogTransmissionType"); + + b.HasData( + new + { + Id = 1, + Name = "Information" + }, + new + { + Id = 2, + Name = "Acceptance" + }, + new + { + Id = 3, + Name = "Rejection" + }, + new + { + Id = 4, + Name = "Request" + }, + new + { + Id = 5, + Name = "Alert" + }, + new + { + Id = 6, + Name = "Decision" + }, + new + { + Id = 7, + Name = "Submission" + }, + new + { + Id = 8, + Name = "Correction" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Http.HttpVerb", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("HttpVerb"); + + b.HasData( + new + { + Id = 1, + Name = "GET" + }, + new + { + Id = 2, + Name = "POST" + }, + new + { + Id = 3, + Name = "PUT" + }, + new + { + Id = 4, + Name = "PATCH" + }, + new + { + Id = 5, + Name = "DELETE" + }, + new + { + Id = 6, + Name = "HEAD" + }, + new + { + Id = 7, + Name = "OPTIONS" + }, + new + { + Id = 8, + Name = "TRACE" + }, + new + { + Id = 9, + Name = "CONNECT" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Localizations.Localization", b => + { + b.Property("LocalizationSetId") + .HasColumnType("uuid"); + + b.Property("LanguageCode") + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(4095) + .HasColumnType("character varying(4095)"); + + b.HasKey("LocalizationSetId", "LanguageCode"); + + b.ToTable("Localization"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("LocalizationSet"); + + b.HasDiscriminator().HasValue("LocalizationSet"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Outboxes.OutboxMessage", b => + { + b.Property("EventId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CorrelationId") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("EventPayload") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("EventId"); + + b.ToTable("OutboxMessage"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Outboxes.OutboxMessageConsumer", b => + { + b.Property("EventId") + .HasColumnType("uuid"); + + b.Property("ConsumerName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("EventId", "ConsumerName"); + + b.ToTable("OutboxMessageConsumer"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.HasIndex("DialogId"); + + b.HasDiscriminator().HasValue("DialogAttachment"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.TransmissionAttachment", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionId"); + + b.HasDiscriminator().HasValue("TransmissionAttachment"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPrompt", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("GuiActionId") + .HasColumnType("uuid"); + + b.HasIndex("GuiActionId") + .IsUnique(); + + b.ToTable("LocalizationSet", t => + { + t.Property("GuiActionId") + .HasColumnName("DialogGuiActionPrompt_GuiActionId"); + }); + + b.HasDiscriminator().HasValue("DialogGuiActionPrompt"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionTitle", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("GuiActionId") + .HasColumnType("uuid"); + + b.HasIndex("GuiActionId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogGuiActionTitle"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivityDescription", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("ActivityId") + .HasColumnType("uuid"); + + b.HasIndex("ActivityId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogActivityDescription"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentDisplayName", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("AttachmentId") + .HasColumnType("uuid"); + + b.HasIndex("AttachmentId") + .IsUnique(); + + b.HasDiscriminator().HasValue("AttachmentDisplayName"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentValue", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("DialogContentId") + .HasColumnType("uuid"); + + b.HasIndex("DialogContentId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogContentValue"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentValue", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("TransmissionContentId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionContentId") + .IsUnique(); + + b.HasDiscriminator().HasValue("TransmissionContentValue"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiAction", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("ApiActions") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Dialog"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiActionEndpoint", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiAction", "Action") + .WithMany("Endpoints") + .HasForeignKey("ActionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Http.HttpVerb", "HttpMethod") + .WithMany() + .HasForeignKey("HttpMethodId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Action"); + + b.Navigation("HttpMethod"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiAction", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("GuiActions") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Http.HttpVerb", "HttpMethod") + .WithMany() + .HasForeignKey("HttpMethodId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPriority", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Dialog"); + + b.Navigation("HttpMethod"); + + b.Navigation("Priority"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivity", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("Activities") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActor", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivity", "RelatedActivity") + .WithMany("RelatedActivities") + .HasForeignKey("RelatedActivityId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivityType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Dialog"); + + b.Navigation("PerformedBy"); + + b.Navigation("RelatedActivity"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActor", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActorType", "ActorType") + .WithMany() + .HasForeignKey("ActorTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ActorType"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrl", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", "Attachment") + .WithMany("Urls") + .HasForeignKey("AttachmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrlConsumerType", "ConsumerType") + .WithMany() + .HasForeignKey("ConsumerTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Attachment"); + + b.Navigation("ConsumerType"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("Content") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Dialog"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "Transmission") + .WithMany("Content") + .HasForeignKey("TransmissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Transmission"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogStatus", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSearchTag", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("SearchTags") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Dialog"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSeenLog", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("SeenLog") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogUserType", "EndUserType") + .WithMany() + .HasForeignKey("EndUserTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActor", "SeenBy") + .WithMany() + .HasForeignKey("SeenById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Dialog"); + + b.Navigation("EndUserType"); + + b.Navigation("SeenBy"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("Transmissions") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "RelatedTransmission") + .WithMany() + .HasForeignKey("RelatedTransmissionId"); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActor", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Dialog"); + + b.Navigation("RelatedTransmission"); + + b.Navigation("Sender"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Localizations.Localization", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet", "LocalizationSet") + .WithMany("Localizations") + .HasForeignKey("LocalizationSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LocalizationSet"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Outboxes.OutboxMessageConsumer", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Outboxes.OutboxMessage", "OutboxMessage") + .WithMany("OutboxMessageConsumers") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OutboxMessage"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("Attachments") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Dialog"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.TransmissionAttachment", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "Transmission") + .WithMany("Attachments") + .HasForeignKey("TransmissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Transmission"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPrompt", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiAction", "GuiAction") + .WithOne("Prompt") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPrompt", "GuiActionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuiAction"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionTitle", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiAction", "GuiAction") + .WithOne("Title") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionTitle", "GuiActionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuiAction"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivityDescription", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivity", "Activity") + .WithOne("Description") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivityDescription", "ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Activity"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentDisplayName", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", "Attachment") + .WithOne("DisplayName") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentDisplayName", "AttachmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Attachment"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentValue", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", "DialogContent") + .WithOne("Value") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentValue", "DialogContentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DialogContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentValue", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", "TransmissionContent") + .WithOne("Value") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentValue", "TransmissionContentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TransmissionContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiAction", b => + { + b.Navigation("Endpoints"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiAction", b => + { + b.Navigation("Prompt"); + + b.Navigation("Title"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivity", b => + { + b.Navigation("Description"); + + b.Navigation("RelatedActivities"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", b => + { + b.Navigation("DisplayName"); + + b.Navigation("Urls"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", b => + { + b.Navigation("Value") + .IsRequired(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", b => + { + b.Navigation("Value") + .IsRequired(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", b => + { + b.Navigation("Activities"); + + b.Navigation("ApiActions"); + + b.Navigation("Attachments"); + + b.Navigation("Content"); + + b.Navigation("GuiActions"); + + b.Navigation("SearchTags"); + + b.Navigation("SeenLog"); + + b.Navigation("Transmissions"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.Navigation("Attachments"); + + b.Navigation("Content"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet", b => + { + b.Navigation("Localizations"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Outboxes.OutboxMessage", b => + { + b.Navigation("OutboxMessageConsumers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240729223752_AddTransmissions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240729223752_AddTransmissions.cs new file mode 100644 index 000000000..659827afc --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240729223752_AddTransmissions.cs @@ -0,0 +1,493 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Digdir.Domain.Dialogporten.Infrastructure.Persistence.Migrations +{ + /// + public partial class AddTransmissions : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_DialogAttachment_Dialog_DialogId", + table: "DialogAttachment"); + + migrationBuilder.DropForeignKey( + name: "FK_LocalizationSet_DialogAttachment_AttachmentId", + table: "LocalizationSet"); + + migrationBuilder.DropTable( + name: "DialogAttachmentUrl"); + + migrationBuilder.DropTable( + name: "DialogAttachmentUrlConsumerType"); + + migrationBuilder.DropPrimaryKey( + name: "PK_DialogAttachment", + table: "DialogAttachment"); + + migrationBuilder.RenameTable( + name: "DialogAttachment", + newName: "Attachment"); + + migrationBuilder.RenameIndex( + name: "IX_DialogAttachment_DialogId", + table: "Attachment", + newName: "IX_Attachment_DialogId"); + + migrationBuilder.AddColumn( + name: "TransmissionContentId", + table: "LocalizationSet", + type: "uuid", + nullable: true); + + migrationBuilder.AlterColumn( + name: "DialogId", + table: "Attachment", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AddColumn( + name: "Discriminator", + table: "Attachment", + type: "character varying(255)", + maxLength: 255, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "TransmissionId", + table: "Attachment", + type: "uuid", + nullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_Attachment", + table: "Attachment", + column: "Id"); + + migrationBuilder.CreateTable( + name: "AttachmentUrlConsumerType", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + Name = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AttachmentUrlConsumerType", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "DialogTransmissionType", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + Name = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DialogTransmissionType", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TransmissionContentType", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + Required = table.Column(type: "boolean", nullable: false), + MaxLength = table.Column(type: "integer", nullable: false), + AllowedMediaTypes = table.Column(type: "text[]", nullable: false), + Name = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TransmissionContentType", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AttachmentUrl", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + MediaType = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + Url = table.Column(type: "character varying(1023)", maxLength: 1023, nullable: false), + ConsumerTypeId = table.Column(type: "integer", nullable: false), + AttachmentId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AttachmentUrl", x => x.Id); + table.ForeignKey( + name: "FK_AttachmentUrl_AttachmentUrlConsumerType_ConsumerTypeId", + column: x => x.ConsumerTypeId, + principalTable: "AttachmentUrlConsumerType", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_AttachmentUrl_Attachment_AttachmentId", + column: x => x.AttachmentId, + principalTable: "Attachment", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "DialogTransmission", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + AuthorizationAttribute = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + SenderId = table.Column(type: "uuid", nullable: false), + ExtendedType = table.Column(type: "character varying(1023)", maxLength: 1023, nullable: true), + TypeId = table.Column(type: "integer", nullable: false), + DialogId = table.Column(type: "uuid", nullable: false), + RelatedTransmissionId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DialogTransmission", x => x.Id); + table.ForeignKey( + name: "FK_DialogTransmission_DialogActor_SenderId", + column: x => x.SenderId, + principalTable: "DialogActor", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_DialogTransmission_DialogTransmissionType_TypeId", + column: x => x.TypeId, + principalTable: "DialogTransmissionType", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_DialogTransmission_DialogTransmission_RelatedTransmissionId", + column: x => x.RelatedTransmissionId, + principalTable: "DialogTransmission", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_DialogTransmission_Dialog_DialogId", + column: x => x.DialogId, + principalTable: "Dialog", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TransmissionContent", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + MediaType = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + TransmissionId = table.Column(type: "uuid", nullable: false), + TypeId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TransmissionContent", x => x.Id); + table.ForeignKey( + name: "FK_TransmissionContent_DialogTransmission_TransmissionId", + column: x => x.TransmissionId, + principalTable: "DialogTransmission", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TransmissionContent_TransmissionContentType_TypeId", + column: x => x.TypeId, + principalTable: "TransmissionContentType", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.InsertData( + table: "AttachmentUrlConsumerType", + columns: new[] { "Id", "Name" }, + values: new object[,] + { + { 1, "Gui" }, + { 2, "Api" } + }); + + migrationBuilder.InsertData( + table: "DialogTransmissionType", + columns: new[] { "Id", "Name" }, + values: new object[,] + { + { 1, "Information" }, + { 2, "Acceptance" }, + { 3, "Rejection" }, + { 4, "Request" }, + { 5, "Alert" }, + { 6, "Decision" }, + { 7, "Submission" }, + { 8, "Correction" } + }); + + migrationBuilder.InsertData( + table: "TransmissionContentType", + columns: new[] { "Id", "AllowedMediaTypes", "MaxLength", "Name", "Required" }, + values: new object[,] + { + { 1, new[] { "text/plain" }, 255, "Title", true }, + { 2, new[] { "text/plain" }, 255, "Summary", true } + }); + + migrationBuilder.CreateIndex( + name: "IX_LocalizationSet_TransmissionContentId", + table: "LocalizationSet", + column: "TransmissionContentId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Attachment_TransmissionId", + table: "Attachment", + column: "TransmissionId"); + + migrationBuilder.CreateIndex( + name: "IX_AttachmentUrl_AttachmentId", + table: "AttachmentUrl", + column: "AttachmentId"); + + migrationBuilder.CreateIndex( + name: "IX_AttachmentUrl_ConsumerTypeId", + table: "AttachmentUrl", + column: "ConsumerTypeId"); + + migrationBuilder.CreateIndex( + name: "IX_DialogTransmission_DialogId", + table: "DialogTransmission", + column: "DialogId"); + + migrationBuilder.CreateIndex( + name: "IX_DialogTransmission_RelatedTransmissionId", + table: "DialogTransmission", + column: "RelatedTransmissionId"); + + migrationBuilder.CreateIndex( + name: "IX_DialogTransmission_SenderId", + table: "DialogTransmission", + column: "SenderId"); + + migrationBuilder.CreateIndex( + name: "IX_DialogTransmission_TypeId", + table: "DialogTransmission", + column: "TypeId"); + + migrationBuilder.CreateIndex( + name: "IX_TransmissionContent_TransmissionId_TypeId", + table: "TransmissionContent", + columns: new[] { "TransmissionId", "TypeId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_TransmissionContent_TypeId", + table: "TransmissionContent", + column: "TypeId"); + + migrationBuilder.AddForeignKey( + name: "FK_Attachment_DialogTransmission_TransmissionId", + table: "Attachment", + column: "TransmissionId", + principalTable: "DialogTransmission", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Attachment_Dialog_DialogId", + table: "Attachment", + column: "DialogId", + principalTable: "Dialog", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_LocalizationSet_Attachment_AttachmentId", + table: "LocalizationSet", + column: "AttachmentId", + principalTable: "Attachment", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_LocalizationSet_TransmissionContent_TransmissionContentId", + table: "LocalizationSet", + column: "TransmissionContentId", + principalTable: "TransmissionContent", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Attachment_DialogTransmission_TransmissionId", + table: "Attachment"); + + migrationBuilder.DropForeignKey( + name: "FK_Attachment_Dialog_DialogId", + table: "Attachment"); + + migrationBuilder.DropForeignKey( + name: "FK_LocalizationSet_Attachment_AttachmentId", + table: "LocalizationSet"); + + migrationBuilder.DropForeignKey( + name: "FK_LocalizationSet_TransmissionContent_TransmissionContentId", + table: "LocalizationSet"); + + migrationBuilder.DropTable( + name: "AttachmentUrl"); + + migrationBuilder.DropTable( + name: "TransmissionContent"); + + migrationBuilder.DropTable( + name: "AttachmentUrlConsumerType"); + + migrationBuilder.DropTable( + name: "DialogTransmission"); + + migrationBuilder.DropTable( + name: "TransmissionContentType"); + + migrationBuilder.DropTable( + name: "DialogTransmissionType"); + + migrationBuilder.DropIndex( + name: "IX_LocalizationSet_TransmissionContentId", + table: "LocalizationSet"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Attachment", + table: "Attachment"); + + migrationBuilder.DropIndex( + name: "IX_Attachment_TransmissionId", + table: "Attachment"); + + migrationBuilder.DropColumn( + name: "TransmissionContentId", + table: "LocalizationSet"); + + migrationBuilder.DropColumn( + name: "Discriminator", + table: "Attachment"); + + migrationBuilder.DropColumn( + name: "TransmissionId", + table: "Attachment"); + + migrationBuilder.RenameTable( + name: "Attachment", + newName: "DialogAttachment"); + + migrationBuilder.RenameIndex( + name: "IX_Attachment_DialogId", + table: "DialogAttachment", + newName: "IX_DialogAttachment_DialogId"); + + migrationBuilder.AlterColumn( + name: "DialogId", + table: "DialogAttachment", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_DialogAttachment", + table: "DialogAttachment", + column: "Id"); + + migrationBuilder.CreateTable( + name: "DialogAttachmentUrlConsumerType", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + Name = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DialogAttachmentUrlConsumerType", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "DialogAttachmentUrl", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), + ConsumerTypeId = table.Column(type: "integer", nullable: false), + DialogAttachmentId = table.Column(type: "uuid", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + MediaType = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"), + Url = table.Column(type: "character varying(1023)", maxLength: 1023, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DialogAttachmentUrl", x => x.Id); + table.ForeignKey( + name: "FK_DialogAttachmentUrl_DialogAttachmentUrlConsumerType_Consume~", + column: x => x.ConsumerTypeId, + principalTable: "DialogAttachmentUrlConsumerType", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_DialogAttachmentUrl_DialogAttachment_DialogAttachmentId", + column: x => x.DialogAttachmentId, + principalTable: "DialogAttachment", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + table: "DialogAttachmentUrlConsumerType", + columns: new[] { "Id", "Name" }, + values: new object[,] + { + { 1, "Gui" }, + { 2, "Api" } + }); + + migrationBuilder.CreateIndex( + name: "IX_DialogAttachmentUrl_ConsumerTypeId", + table: "DialogAttachmentUrl", + column: "ConsumerTypeId"); + + migrationBuilder.CreateIndex( + name: "IX_DialogAttachmentUrl_DialogAttachmentId", + table: "DialogAttachmentUrl", + column: "DialogAttachmentId"); + + migrationBuilder.AddForeignKey( + name: "FK_DialogAttachment_Dialog_DialogId", + table: "DialogAttachment", + column: "DialogId", + principalTable: "Dialog", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_LocalizationSet_DialogAttachment_AttachmentId", + table: "LocalizationSet", + column: "AttachmentId", + principalTable: "DialogAttachment", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs index 8c219bef2..9450d9eb1 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs @@ -343,7 +343,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -355,8 +355,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("timestamp with time zone") .HasDefaultValueSql("current_timestamp at time zone 'utc'"); - b.Property("DialogId") - .HasColumnType("uuid"); + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); b.Property("UpdatedAt") .ValueGeneratedOnAdd() @@ -365,18 +367,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("DialogId"); + b.ToTable("Attachment"); - b.ToTable("DialogAttachment"); + b.HasDiscriminator().HasValue("Attachment"); + + b.UseTphMappingStrategy(); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachmentUrl", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrl", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid") .HasDefaultValueSql("gen_random_uuid()"); + b.Property("AttachmentId") + .HasColumnType("uuid"); + b.Property("ConsumerTypeId") .HasColumnType("integer"); @@ -385,9 +392,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("timestamp with time zone") .HasDefaultValueSql("current_timestamp at time zone 'utc'"); - b.Property("DialogAttachmentId") - .HasColumnType("uuid"); - b.Property("MediaType") .HasMaxLength(255) .HasColumnType("character varying(255)"); @@ -404,14 +408,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ConsumerTypeId"); + b.HasIndex("AttachmentId"); - b.HasIndex("DialogAttachmentId"); + b.HasIndex("ConsumerTypeId"); - b.ToTable("DialogAttachmentUrl"); + b.ToTable("AttachmentUrl"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachmentUrlConsumerType", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrlConsumerType", b => { b.Property("Id") .HasColumnType("integer"); @@ -423,7 +427,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.ToTable("DialogAttachmentUrlConsumerType"); + b.ToTable("AttachmentUrlConsumerType"); b.HasData( new @@ -438,7 +442,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContent", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -475,7 +479,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("DialogContent"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContentType", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentType", b => { b.Property("Id") .HasColumnType("integer"); @@ -559,6 +563,86 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("MediaType") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.HasIndex("TransmissionId", "TypeId") + .IsUnique(); + + b.ToTable("TransmissionContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AllowedMediaTypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("MaxLength") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("TransmissionContentType"); + + b.HasData( + new + { + Id = 1, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "Title", + Required = true + }, + new + { + Id = 2, + AllowedMediaTypes = new[] { "text/plain" }, + MaxLength = 255, + Name = "Summary", + Required = true + }); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", b => { b.Property("Id") @@ -810,6 +894,108 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("AuthorizationAttribute") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("current_timestamp at time zone 'utc'"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.Property("ExtendedType") + .HasMaxLength(1023) + .HasColumnType("character varying(1023)"); + + b.Property("RelatedTransmissionId") + .HasColumnType("uuid"); + + b.Property("SenderId") + .HasColumnType("uuid"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("RelatedTransmissionId"); + + b.HasIndex("SenderId"); + + b.HasIndex("TypeId"); + + b.ToTable("DialogTransmission"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("DialogTransmissionType"); + + b.HasData( + new + { + Id = 1, + Name = "Information" + }, + new + { + Id = 2, + Name = "Acceptance" + }, + new + { + Id = 3, + Name = "Rejection" + }, + new + { + Id = 4, + Name = "Request" + }, + new + { + Id = 5, + Name = "Alert" + }, + new + { + Id = 6, + Name = "Decision" + }, + new + { + Id = 7, + Name = "Submission" + }, + new + { + Id = 8, + Name = "Correction" + }); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Http.HttpVerb", b => { b.Property("Id") @@ -973,6 +1159,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("OutboxMessageConsumer"); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.HasIndex("DialogId"); + + b.HasDiscriminator().HasValue("DialogAttachment"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.TransmissionAttachment", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionId"); + + b.HasDiscriminator().HasValue("TransmissionAttachment"); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPrompt", b => { b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); @@ -1031,7 +1241,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("AttachmentDisplayName"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContentValue", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentValue", b => { b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); @@ -1044,6 +1254,19 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("DialogContentValue"); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentValue", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("TransmissionContentId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionContentId") + .IsUnique(); + + b.HasDiscriminator().HasValue("TransmissionContentValue"); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiAction", b => { b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") @@ -1146,37 +1369,26 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("ActorType"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrl", b => { - b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") - .WithMany("Attachments") - .HasForeignKey("DialogId") + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", "Attachment") + .WithMany("Urls") + .HasForeignKey("AttachmentId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Dialog"); - }); - - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachmentUrl", b => - { - b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachmentUrlConsumerType", "ConsumerType") + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentUrlConsumerType", "ConsumerType") .WithMany() .HasForeignKey("ConsumerTypeId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", "DialogAttachment") - .WithMany("Urls") - .HasForeignKey("DialogAttachmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + b.Navigation("Attachment"); b.Navigation("ConsumerType"); - - b.Navigation("DialogAttachment"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContent", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", b => { b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") .WithMany("Content") @@ -1184,7 +1396,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContentType", "Type") + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentType", "Type") .WithMany() .HasForeignKey("TypeId") .OnDelete(DeleteBehavior.Restrict) @@ -1195,6 +1407,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Type"); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "Transmission") + .WithMany("Content") + .HasForeignKey("TransmissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Transmission"); + + b.Navigation("Type"); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", b => { b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogStatus", "Status") @@ -1244,6 +1475,39 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("SeenBy"); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("Transmissions") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "RelatedTransmission") + .WithMany() + .HasForeignKey("RelatedTransmissionId"); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actors.DialogActor", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Dialog"); + + b.Navigation("RelatedTransmission"); + + b.Navigation("Sender"); + + b.Navigation("Type"); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Localizations.Localization", b => { b.HasOne("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet", "LocalizationSet") @@ -1266,6 +1530,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("OutboxMessage"); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogEntity", "Dialog") + .WithMany("Attachments") + .HasForeignKey("DialogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Dialog"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.TransmissionAttachment", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "Transmission") + .WithMany("Attachments") + .HasForeignKey("TransmissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Transmission"); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiActionPrompt", b => { b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogGuiAction", "GuiAction") @@ -1301,7 +1587,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentDisplayName", b => { - b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", "Attachment") + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", "Attachment") .WithOne("DisplayName") .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.AttachmentDisplayName", "AttachmentId") .OnDelete(DeleteBehavior.Cascade) @@ -1310,17 +1596,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Attachment"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContentValue", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentValue", b => { - b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContent", "DialogContent") + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", "DialogContent") .WithOne("Value") - .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContentValue", "DialogContentId") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContentValue", "DialogContentId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("DialogContent"); }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentValue", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", "TransmissionContent") + .WithOne("Value") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContentValue", "TransmissionContentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TransmissionContent"); + }); + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions.DialogApiAction", b => { b.Navigation("Endpoints"); @@ -1340,14 +1637,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("RelatedActivities"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.DialogAttachment", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Attachments.Attachment", b => { b.Navigation("DisplayName"); b.Navigation("Urls"); }); - modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content.DialogContent", b => + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", b => + { + b.Navigation("Value") + .IsRequired(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.TransmissionContent", b => { b.Navigation("Value") .IsRequired(); @@ -1368,6 +1671,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("SearchTags"); b.Navigation("SeenLog"); + + b.Navigation("Transmissions"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.Navigation("Attachments"); + + b.Navigation("Content"); }); modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet", b => diff --git a/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs b/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs index 851737ae9..84116a7a1 100644 --- a/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs +++ b/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs @@ -291,7 +291,7 @@ public static List GenerateFakeDialogAttachm { return new Faker() .RuleFor(o => o.Url, f => new Uri(f.Internet.UrlWithPath())) - .RuleFor(o => o.ConsumerType, f => f.PickRandom()) + .RuleFor(o => o.ConsumerType, f => f.PickRandom()) .Generate(new Randomizer().Number(1, 3)); } diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs index 97f295673..5f0198754 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs @@ -128,7 +128,7 @@ public async Task Creates_CloudEvent_When_Attachments_Updates() DisplayName = DialogGenerator.GenerateFakeLocalizations(3), Urls = [new() { - ConsumerType = DialogAttachmentUrlConsumerType.Values.Gui, + ConsumerType = AttachmentUrlConsumerType.Values.Gui, Url = new Uri("https://example.com") }] }]; diff --git a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Features/V1/Common/DialogContentTypeTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Features/V1/Common/ContentTypeTests.cs similarity index 52% rename from tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Features/V1/Common/DialogContentTypeTests.cs rename to tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Features/V1/Common/ContentTypeTests.cs index c30c4dbad..1ac4f5726 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Features/V1/Common/DialogContentTypeTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Features/V1/Common/ContentTypeTests.cs @@ -1,19 +1,19 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Create; using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Update; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; -using GetDialogContentDtoEU = - Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get.GetDialogContentDto; -using GetDialogContentDtoSO = - Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get.GetDialogContentDto; -using SearchDialogContentDtoEU = - Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search.SearchDialogContentDto; -using SearchDialogDtoContentSO = - Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Search.SearchDialogContentDto; +using GetDialogContentDtoEU = Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get.GetDialogContentDto; +using GetDialogContentDtoSO = Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get.GetDialogContentDto; + +using SearchDialogContentDtoEU = Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search.SearchDialogContentDto; +using SearchDialogDtoContentSO = Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Search.SearchDialogContentDto; + +using GetDialogDialogTransmissionContentDtoSO = Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get.GetDialogDialogTransmissionContentDto; +using GetDialogDialogTransmissionContentDtoEU = Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get.GetDialogDialogTransmissionContentDto; namespace Digdir.Domain.Dialogporten.Application.Unit.Tests.Features.V1.Common; -public class DialogContentTypeTests +public class ContentTypeTests { [Fact] public void DialogContentType_Names_Should_Match_Props_On_All_DTOs() @@ -73,4 +73,34 @@ public void OutPutInList_DialogContentType_Names_Should_Match_Props_On_All_Searc } } } + + [Fact] + public void TransmissionContentType_Names_Should_Match_Props_On_All_DTOs() + { + // Arrange + var transmissionContentTypeNames = TransmissionContentType.GetValues() + .Select(x => x.Name) + .ToList(); + + var dtoTypes = new[] + { + typeof(CreateDialogDialogTransmissionContentDto), + typeof(UpdateDialogDialogTransmissionContentDto), + typeof(GetDialogDialogTransmissionContentDtoSO), + typeof(GetDialogDialogTransmissionContentDtoEU), + }; + + foreach (var dtoType in dtoTypes) + { + var dtoPropertyNames = dtoType.GetProperties() + .Select(p => p.Name) + .ToList(); + + Assert.Equal(transmissionContentTypeNames.Count, dtoPropertyNames.Count); + foreach (var contentTypeName in transmissionContentTypeNames) + { + Assert.Contains(contentTypeName, dtoPropertyNames, StringComparer.OrdinalIgnoreCase); + } + } + } } diff --git a/tests/Digdir.Domain.Dialogporten.GraphQl.Unit.Tests/ObjectTypes/ContentTypeTests.cs b/tests/Digdir.Domain.Dialogporten.GraphQl.Unit.Tests/ObjectTypes/ContentTypeTests.cs index 3516ff35c..9b0d54b4d 100644 --- a/tests/Digdir.Domain.Dialogporten.GraphQl.Unit.Tests/ObjectTypes/ContentTypeTests.cs +++ b/tests/Digdir.Domain.Dialogporten.GraphQl.Unit.Tests/ObjectTypes/ContentTypeTests.cs @@ -1,6 +1,6 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; -using Digdir.Domain.Dialogporten.GraphQL.EndUser.DialogById; +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents; +using Content = Digdir.Domain.Dialogporten.GraphQL.EndUser.DialogById.Content; namespace Digdir.Domain.Dialogporten.GraphQl.Unit.Tests.ObjectTypes;