diff --git a/docs/schema/V1/schema.verified.graphql b/docs/schema/V1/schema.verified.graphql index acfdb679e..35b41b0a6 100644 --- a/docs/schema/V1/schema.verified.graphql +++ b/docs/schema/V1/schema.verified.graphql @@ -95,6 +95,8 @@ type Dialog { serviceResourceType: String! party: String! progress: Int + process: String + precedingProcess: String extendedStatus: String externalReference: String visibleFrom: DateTime @@ -172,6 +174,8 @@ type SearchDialog { serviceResourceType: String! party: String! progress: Int + process: String + precedingProcess: String guiAttachmentCount: Int extendedStatus: String createdAt: DateTime! diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index 948818a78..edd6ed88a 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -225,6 +225,16 @@ "example": "urn:altinn:person:identifier-no:01125512345\nurn:altinn:organization:identifier-no:912345678", "type": "string" }, + "precedingProcess": { + "description": "Optional preceding process identifier to indicate the business process that preceded the process indicated in the \u0022Process\u0022 field. Cannot be set without also \u0022Process\u0022 being set.", + "nullable": true, + "type": "string" + }, + "process": { + "description": "Optional process identifier used to indicate a business process this dialog belongs to ", + "nullable": true, + "type": "string" + }, "progress": { "description": "Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come\nto a natural completion (successful or not).", "format": "int32", @@ -2035,6 +2045,16 @@ "example": "urn:altinn:person:identifier-no:01125512345\nurn:altinn:organization:identifier-no:912345678", "type": "string" }, + "precedingProcess": { + "description": "Optional preceding process identifier to indicate the business process that preceded the process indicated in the \u0022Process\u0022 field. Cannot be set without also \u0022Process\u0022 being set.", + "nullable": true, + "type": "string" + }, + "process": { + "description": "Optional process identifier used to indicate a business process this dialog belongs to", + "nullable": true, + "type": "string" + }, "progress": { "description": "Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come\nto a natural completion (successful or not).", "format": "int32", @@ -2178,6 +2198,16 @@ "example": "urn:altinn:person:identifier-no:01125512345\nurn:altinn:organization:identifier-no:912345678", "type": "string" }, + "precedingProcess": { + "description": "Optional preceding process identifier to indicate the business process that preceded the process indicated in the \u0022Process\u0022 field. Cannot be set without also \u0022Process\u0022 being set. ", + "nullable": true, + "type": "string" + }, + "process": { + "description": "Optional process identifier used to indicate a business process this dialog belongs to ", + "nullable": true, + "type": "string" + }, "progress": { "description": "Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come\nto a natural completion (successful or not).", "format": "int32", @@ -3108,6 +3138,16 @@ "example": "urn:altinn:person:identifier-no:01125512345\nurn:altinn:organization:identifier-no:912345678", "type": "string" }, + "precedingProcess": { + "description": "Optional preceding process identifier to indicate the business process that preceded the process indicated in the \u0022Process\u0022 field. Cannot be set without also \u0022Process\u0022 being set. ", + "nullable": true, + "type": "string" + }, + "process": { + "description": "Optional process identifier used to indicate a business process this dialog belongs to ", + "nullable": true, + "type": "string" + }, "progress": { "description": "Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come\nto a natural completion (successful or not).", "format": "int32", @@ -3207,6 +3247,16 @@ "example": "urn:altinn:person:identifier-no:01125512345\nurn:altinn:organization:identifier-no:912345678", "type": "string" }, + "precedingProcess": { + "description": "Optional preceding process identifier to indicate the business process that preceded the process indicated in the \u0022Process\u0022 field. Cannot be set without also \u0022Process\u0022 being set.", + "nullable": true, + "type": "string" + }, + "process": { + "description": "Optional process identifier used to indicate a business process this dialog belongs to", + "nullable": true, + "type": "string" + }, "progress": { "description": "Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come\nto a natural completion (successful or not).", "format": "int32", @@ -4170,6 +4220,15 @@ "type": "string" } }, + { + "description": "Filter by process", + "in": "query", + "name": "process", + "schema": { + "nullable": true, + "type": "string" + } + }, { "description": "Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate", "in": "query", @@ -4821,6 +4880,15 @@ "type": "string" } }, + { + "description": "Filter by process", + "in": "query", + "name": "process", + "schema": { + "nullable": true, + "type": "string" + } + }, { "description": "Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate", "in": "query", diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogActivityEventToAltinnForwarder.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogActivityEventToAltinnForwarder.cs index 30d117822..d2573e4eb 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogActivityEventToAltinnForwarder.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogActivityEventToAltinnForwarder.cs @@ -45,6 +45,14 @@ private static Dictionary GetCloudEventData(DialogActivityCreate data["relatedActivityId"] = domainEvent.RelatedActivityId.ToString()!; } + if (domainEvent.Process is not null) + { + data["process"] = domainEvent.Process; + } + if (domainEvent.PrecedingProcess is not null) + { + data["precedingProcess"] = domainEvent.PrecedingProcess; + } return data; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogEventToAltinnForwarder.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogEventToAltinnForwarder.cs index e1c640daf..1843a3c69 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogEventToAltinnForwarder.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Events/DialogEventToAltinnForwarder.cs @@ -24,7 +24,8 @@ public async Task Handle(DialogCreatedDomainEvent domainEvent, CancellationToken Resource = domainEvent.ServiceResource, ResourceInstance = domainEvent.DialogId.ToString(), Subject = domainEvent.Party, - Source = $"{SourceBaseUrl()}{domainEvent.DialogId}" + Source = $"{SourceBaseUrl()}{domainEvent.DialogId}", + Data = GetCloudEventData(domainEvent) }; await CloudEventBus.Publish(cloudEvent, cancellationToken); } @@ -39,7 +40,8 @@ public async Task Handle(DialogUpdatedDomainEvent domainEvent, CancellationToken Resource = domainEvent.ServiceResource, ResourceInstance = domainEvent.DialogId.ToString(), Subject = domainEvent.Party, - Source = $"{SourceBaseUrl()}{domainEvent.DialogId}" + Source = $"{SourceBaseUrl()}{domainEvent.DialogId}", + Data = GetCloudEventData(domainEvent) }; await CloudEventBus.Publish(cloudEvent, cancellationToken); @@ -55,7 +57,8 @@ public async Task Handle(DialogSeenDomainEvent domainEvent, CancellationToken ca Resource = domainEvent.ServiceResource, ResourceInstance = domainEvent.DialogId.ToString(), Subject = domainEvent.Party, - Source = $"{SourceBaseUrl()}{domainEvent.DialogId}" + Source = $"{SourceBaseUrl()}{domainEvent.DialogId}", + Data = GetCloudEventData(domainEvent) }; await CloudEventBus.Publish(cloudEvent, cancellationToken); @@ -71,9 +74,24 @@ public async Task Handle(DialogDeletedDomainEvent domainEvent, CancellationToken Resource = domainEvent.ServiceResource, ResourceInstance = domainEvent.DialogId.ToString(), Subject = domainEvent.Party, - Source = $"{SourceBaseUrl()}{domainEvent.DialogId}" + Source = $"{SourceBaseUrl()}{domainEvent.DialogId}", + Data = GetCloudEventData(domainEvent) }; await CloudEventBus.Publish(cloudEvent, cancellationToken); } + + private static Dictionary? GetCloudEventData(IProcessEvent domainEvent) + { + var data = new Dictionary(); + if (domainEvent.Process is not null) + { + data["process"] = domainEvent.Process; + } + if (domainEvent.PrecedingProcess is not null) + { + data["precedingProcess"] = domainEvent.PrecedingProcess; + } + return data.Count == 0 ? null : data; + } } 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 1ce7b96b0..0d24847f9 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 @@ -57,6 +57,16 @@ public sealed class GetDialogDto /// public int? Progress { get; set; } + /// + /// Optional process identifier used to indicate a business process this dialog belongs to + /// + public string? Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + public string? PrecedingProcess { get; set; } + /// /// Arbitrary string with a service-specific indicator of status, typically used to indicate a fine-grained state of /// the dialog to further specify the "status" enum. diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDtoBase.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDtoBase.cs index 8d3e30939..b236174bc 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDtoBase.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDtoBase.cs @@ -46,6 +46,16 @@ public class SearchDialogDtoBase /// public int? Progress { get; set; } + /// + /// Optional process identifier used to indicate a business process this dialog belongs to + /// + public string? Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + public string? PrecedingProcess { get; set; } + /// /// The number of attachments in the dialog made available for browser-based frontends. /// diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs index ec282dc6a..242e220b9 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs @@ -80,6 +80,11 @@ public sealed class SearchDialogQuery : SortablePaginationParameter public DateTimeOffset? DueBefore { get; init; } + /// + /// Filter by process + /// + public string? Process { get; init; } + /// /// Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate /// @@ -150,7 +155,7 @@ public async Task Handle(SearchDialogQuery request, Cancella .AsSingleQuery() .AsNoTracking() .Include(x => x.Content) - .ThenInclude(x => x.Value.Localizations) + .ThenInclude(x => x.Value.Localizations) .WhereIf(!request.Org.IsNullOrEmpty(), x => request.Org!.Contains(x.Org)) .WhereIf(!request.ServiceResource.IsNullOrEmpty(), x => request.ServiceResource!.Contains(x.ServiceResource)) .WhereIf(!request.Party.IsNullOrEmpty(), x => request.Party!.Contains(x.Party)) @@ -164,6 +169,7 @@ public async Task Handle(SearchDialogQuery request, Cancella .WhereIf(request.UpdatedBefore.HasValue, x => x.UpdatedAt <= request.UpdatedBefore) .WhereIf(request.DueAfter.HasValue, x => request.DueAfter <= x.DueAt) .WhereIf(request.DueBefore.HasValue, x => x.DueAt <= request.DueBefore) + .WhereIf(request.Process is not null, x => EF.Functions.ILike(x.Process!, request.Process!)) .WhereIf(request.Search is not null, x => x.Content.Any(x => x.Value.Localizations.AsQueryable().Any(searchExpression)) || x.SearchTags.Any(x => EF.Functions.ILike(x.Value, request.Search!)) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQueryValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQueryValidator.cs index b64b3796c..a1ca2800d 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQueryValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQueryValidator.cs @@ -44,6 +44,11 @@ public SearchDialogQueryValidator() .LessThanOrEqualTo(20) .When(x => x.ExtendedStatus is not null); + RuleFor(x => x.Process) + .Must(x => Uri.IsWellFormedUriString(x, UriKind.Absolute)) + .WithMessage("{PropertyName} must be a valid URI") + .When(x => x.Process is not null); + RuleForEach(x => x.Status).IsInEnum(); } } 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 93d5ad0a6..ca76bf84f 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 @@ -37,7 +37,7 @@ public CreateDialogCommandValidator( .MaximumLength(Constants.DefaultMaxUriLength) .Must(x => x?.StartsWith(Constants.ServiceResourcePrefix, StringComparison.InvariantCulture) ?? false) - .WithMessage($"'{{PropertyName}}' must start with '{Constants.ServiceResourcePrefix}'."); + .WithMessage($"'{{PropertyName}}' must start with '{Constants.ServiceResourcePrefix}'."); RuleFor(x => x.Party) .IsValidPartyIdentifier() @@ -56,16 +56,16 @@ public CreateDialogCommandValidator( RuleFor(x => x.ExpiresAt) .IsInFuture() .GreaterThanOrEqualTo(x => x.DueAt) - .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) - .When(x => x.DueAt.HasValue, ApplyConditionTo.CurrentValidator) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) + .When(x => x.DueAt.HasValue, ApplyConditionTo.CurrentValidator) .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) - .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) + .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.DueAt) .IsInFuture() .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) - .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) + .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.VisibleFrom) .IsInFuture(); @@ -83,15 +83,15 @@ public CreateDialogCommandValidator( .Must(x => x .EmptyIfNull() .Count(x => x.Priority == DialogGuiActionPriority.Values.Primary) <= 1) - .WithMessage("Only one primary GUI action is allowed.") + .WithMessage("Only one primary GUI action is allowed.") .Must(x => x .EmptyIfNull() .Count(x => x.Priority == DialogGuiActionPriority.Values.Secondary) <= 1) - .WithMessage("Only one secondary GUI action is allowed.") + .WithMessage("Only one secondary GUI action is allowed.") .Must(x => x .EmptyIfNull() .Count(x => x.Priority == DialogGuiActionPriority.Values.Tertiary) <= 5) - .WithMessage("Only five tertiary GUI actions are allowed.") + .WithMessage("Only five tertiary GUI actions are allowed.") .ForEach(x => x.SetValidator(guiActionValidator)); RuleForEach(x => x.ApiActions) @@ -118,6 +118,20 @@ public CreateDialogCommandValidator( dependentKeySelector: activity => activity.RelatedActivityId, principalKeySelector: activity => activity.Id) .SetValidator(activityValidator); + RuleFor(x => x.Process) + .Must(x => Uri.IsWellFormedUriString(x, UriKind.Absolute)) + .WithMessage("{PropertyName} must be a valid absolute URI.") + .When(x => x.Process is not null); + + RuleFor(x => x.Process) + .NotEmpty() + .WithMessage($"{{PropertyName}} must not be empty when {nameof(CreateDialogCommand.PrecedingProcess)} is set.") + .When(x => x.PrecedingProcess is not null); + + RuleFor(x => x.PrecedingProcess) + .Must(x => Uri.IsWellFormedUriString(x, UriKind.Absolute)) + .WithMessage("{PropertyName} must be a valid absolute URI.") + .When(x => x.PrecedingProcess is not null); } } 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 037778d46..0aaaf1312 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 @@ -65,6 +65,15 @@ public class CreateDialogDto /// 2022-12-31T23:59:59Z public DateTimeOffset? DueAt { get; set; } + /// + /// Optional process identifier used to indicate a business process this dialog belongs to + /// + public string? Process { get; set; } + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + public string? PrecedingProcess { get; set; } + /// /// The expiration date for the dialog. This is the last date when the dialog is available for the end user. /// 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 839b22436..a764cf0a4 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 @@ -50,15 +50,15 @@ public UpdateDialogDtoValidator( RuleFor(x => x.ExpiresAt) .GreaterThanOrEqualTo(x => x.DueAt) - .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) - .When(x => x.DueAt.HasValue, ApplyConditionTo.CurrentValidator) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) + .When(x => x.DueAt.HasValue, ApplyConditionTo.CurrentValidator) .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) - .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) + .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.DueAt) .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) - .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) + .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.Status) .IsInEnum(); @@ -74,15 +74,15 @@ public UpdateDialogDtoValidator( .Must(x => x .EmptyIfNull() .Count(x => x.Priority == DialogGuiActionPriority.Values.Primary) <= 1) - .WithMessage("Only one primary GUI action is allowed.") + .WithMessage("Only one primary GUI action is allowed.") .Must(x => x .EmptyIfNull() .Count(x => x.Priority == DialogGuiActionPriority.Values.Secondary) <= 1) - .WithMessage("Only one secondary GUI action is allowed.") + .WithMessage("Only one secondary GUI action is allowed.") .Must(x => x .EmptyIfNull() .Count(x => x.Priority == DialogGuiActionPriority.Values.Tertiary) <= 5) - .WithMessage("Only five tertiary GUI actions are allowed.") + .WithMessage("Only five tertiary GUI actions are allowed.") .UniqueBy(x => x.Id) .ForEach(x => x.SetValidator(guiActionValidator)); 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 7ee1465c7..462129a65 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 @@ -57,6 +57,16 @@ public sealed class GetDialogDto /// public int? Progress { get; set; } + /// + /// Optional process identifier used to indicate a business process this dialog belongs to + /// + public string? Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + public string? PrecedingProcess { get; set; } + /// /// Arbitrary string with a service-specific indicator of status, typically used to indicate a fine-grained state of /// the dialog to further specify the "status" enum. diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDtoBase.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDtoBase.cs index c4c582ac5..38c0fa4cb 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDtoBase.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDtoBase.cs @@ -46,6 +46,16 @@ public class SearchDialogDtoBase /// public int? Progress { get; set; } + /// + /// Optional process identifier used to indicate a business process this dialog belongs to + /// + public string? Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + public string? PrecedingProcess { get; set; } + /// /// The number of attachments in the dialog made available for browser-based frontends. /// diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs index 29e00c4e4..857cac2ff 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs @@ -89,6 +89,11 @@ public sealed class SearchDialogQuery : SortablePaginationParameter public DateTimeOffset? VisibleBefore { get; init; } + /// + /// Filter by process + /// + public string? Process { get; init; } + /// /// Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate /// @@ -172,6 +177,7 @@ public async Task Handle(SearchDialogQuery request, Cancella .WhereIf(request.UpdatedBefore.HasValue, x => x.UpdatedAt <= request.UpdatedBefore) .WhereIf(request.DueAfter.HasValue, x => request.DueAfter <= x.DueAt) .WhereIf(request.DueBefore.HasValue, x => x.DueAt <= request.DueBefore) + .WhereIf(request.Process is not null, x => EF.Functions.ILike(x.Process!, request.Process!)) .WhereIf(request.VisibleAfter.HasValue, x => request.VisibleAfter <= x.VisibleFrom) .WhereIf(request.VisibleBefore.HasValue, x => x.VisibleFrom <= request.VisibleBefore) .WhereIf(request.Search is not null, x => diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQueryValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQueryValidator.cs index 44af73157..5d1fb11fb 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQueryValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQueryValidator.cs @@ -51,5 +51,10 @@ public SearchDialogQueryValidator() .When(x => x.ExtendedStatus is not null); RuleForEach(x => x.Status).IsInEnum(); + + RuleFor(x => x.Process) + .Must(x => Uri.IsWellFormedUriString(x, UriKind.Absolute)) + .WithMessage("{PropertyName} must be a valid URI") + .When(x => x.Process is not null); } } diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Activities/DialogActivity.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Activities/DialogActivity.cs index b8cf688d6..1f045e314 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Activities/DialogActivity.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/Activities/DialogActivity.cs @@ -40,7 +40,7 @@ public void OnCreate(AggregateNode self, DateTimeOffset utcNow) { _domainEvents.Add(new DialogActivityCreatedDomainEvent( DialogId, Id, TypeId, Dialog.Party, - Dialog.ServiceResource, ExtendedType, + Dialog.ServiceResource, Dialog.Process, Dialog.PrecedingProcess, ExtendedType, RelatedActivityId)); } diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs index e5ce07ea8..f75195e28 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs @@ -37,6 +37,10 @@ public class DialogEntity : public DateTimeOffset? DueAt { get; set; } public DateTimeOffset? ExpiresAt { get; set; } + public string? Process { get; set; } + + public string? PrecedingProcess { get; set; } + // === Dependent relationships === public DialogStatus.Values StatusId { get; set; } public DialogStatus Status { get; set; } = null!; @@ -68,7 +72,7 @@ public class DialogEntity : public List SeenLog { get; set; } = []; public void OnCreate(AggregateNode self, DateTimeOffset utcNow) - => _domainEvents.Add(new DialogCreatedDomainEvent(Id, ServiceResource, Party)); + => _domainEvents.Add(new DialogCreatedDomainEvent(Id, ServiceResource, Party, Process, PrecedingProcess)); public void OnUpdate(AggregateNode self, DateTimeOffset utcNow) { @@ -80,12 +84,12 @@ x.Entity is not DialogSearchTag && var shouldProduceEvent = self.IsDirectlyModified() || changedChildren.Any(); if (shouldProduceEvent) { - _domainEvents.Add(new DialogUpdatedDomainEvent(Id, ServiceResource, Party)); + _domainEvents.Add(new DialogUpdatedDomainEvent(Id, ServiceResource, Party, Process, PrecedingProcess)); } } public void OnDelete(AggregateNode self, DateTimeOffset utcNow) - => _domainEvents.Add(new DialogDeletedDomainEvent(Id, ServiceResource, Party)); + => _domainEvents.Add(new DialogDeletedDomainEvent(Id, ServiceResource, Party, Process, PrecedingProcess)); public void UpdateSeenAt(string endUserId, DialogUserType.Values userTypeId, string? endUserName) { @@ -112,7 +116,7 @@ public void UpdateSeenAt(string endUserId, DialogUserType.Values userTypeId, str } }); - _domainEvents.Add(new DialogSeenDomainEvent(Id, ServiceResource, Party)); + _domainEvents.Add(new DialogSeenDomainEvent(Id, ServiceResource, Party, Process, PrecedingProcess)); } private readonly List _domainEvents = []; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/Activities/DialogActivityCreatedDomainEvent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/Activities/DialogActivityCreatedDomainEvent.cs index 359fc2050..97eee2b81 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/Activities/DialogActivityCreatedDomainEvent.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/Activities/DialogActivityCreatedDomainEvent.cs @@ -9,5 +9,7 @@ public sealed record DialogActivityCreatedDomainEvent( DialogActivityType.Values TypeId, string Party, string ServiceResource, + string? Process, + string? PrecedingProcess, Uri? ExtendedType, Guid? RelatedActivityId) : DomainEvent; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogCreatedDomainEvent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogCreatedDomainEvent.cs index 06483b28c..7389bb821 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogCreatedDomainEvent.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogCreatedDomainEvent.cs @@ -1,5 +1,6 @@ using Digdir.Domain.Dialogporten.Domain.Common; +using Digdir.Library.Entity.Abstractions.Features.EventPublisher; namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Events; -public sealed record DialogCreatedDomainEvent(Guid DialogId, string ServiceResource, string Party) : DomainEvent; +public sealed record DialogCreatedDomainEvent(Guid DialogId, string ServiceResource, string Party, string? Process, string? PrecedingProcess) : DomainEvent, IProcessEvent; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogDeletedDomainEvent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogDeletedDomainEvent.cs index da891fb40..f08e95f50 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogDeletedDomainEvent.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogDeletedDomainEvent.cs @@ -1,9 +1,11 @@ using Digdir.Domain.Dialogporten.Domain.Common; +using Digdir.Library.Entity.Abstractions.Features.EventPublisher; namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Events; public sealed record DialogDeletedDomainEvent( Guid DialogId, string ServiceResource, - string Party) : - DomainEvent; + string Party, + string? Process, + string? PrecedingProcess) : DomainEvent, IProcessEvent; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogSeenDomainEvent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogSeenDomainEvent.cs index cb4597d6c..10407e15f 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogSeenDomainEvent.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogSeenDomainEvent.cs @@ -2,4 +2,4 @@ namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Events; -public sealed record DialogSeenDomainEvent(Guid DialogId, string ServiceResource, string Party) : DomainEvent; +public sealed record DialogSeenDomainEvent(Guid DialogId, string ServiceResource, string Party, string? Process, string? PrecedingProcess) : DomainEvent, IProcessEvent; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogUpdatedDomainEvent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogUpdatedDomainEvent.cs index 662fe2d5d..04447ab55 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogUpdatedDomainEvent.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/DialogUpdatedDomainEvent.cs @@ -2,4 +2,4 @@ namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Events; -public sealed record DialogUpdatedDomainEvent(Guid DialogId, string ServiceResource, string Party) : DomainEvent; +public sealed record DialogUpdatedDomainEvent(Guid DialogId, string ServiceResource, string Party, string? Process, string? PrecedingProcess) : DomainEvent, IProcessEvent; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/IProcessEvent.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/IProcessEvent.cs new file mode 100644 index 000000000..70f74ae15 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Events/IProcessEvent.cs @@ -0,0 +1,7 @@ +namespace Digdir.Domain.Dialogporten.Domain.Dialogs.Events; + +public interface IProcessEvent +{ + string? Process { get; } + string? PrecedingProcess { get; } +} diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs index 55a922034..faba0fe06 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/ObjectTypes.cs @@ -38,6 +38,8 @@ public sealed class Dialog public string ServiceResourceType { get; set; } = null!; public string Party { get; set; } = null!; public int? Progress { get; set; } + public string? Process { get; set; } + public string? PrecedingProcess { get; set; } public string? ExtendedStatus { get; set; } public string? ExternalReference { get; set; } public DateTimeOffset? VisibleFrom { get; set; } diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs index f7ceb071f..ed6d6dc50 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs @@ -35,6 +35,8 @@ public sealed class SearchDialog public string ServiceResourceType { get; set; } = null!; public string Party { get; set; } = null!; public int? Progress { get; set; } + public string? Process { get; set; } + public string? PrecedingProcess { get; set; } public int? GuiAttachmentCount { get; set; } public string? ExtendedStatus { get; set; } public DateTimeOffset CreatedAt { get; set; } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/DialogEntityConfiguration.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/DialogEntityConfiguration.cs index db456e3bd..c93a26c41 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/DialogEntityConfiguration.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/Dialogs/DialogEntityConfiguration.cs @@ -21,5 +21,6 @@ public void Configure(EntityTypeBuilder builder) builder.HasIndex(x => x.Org); builder.HasIndex(x => x.ServiceResource); builder.HasIndex(x => x.Party); + builder.HasIndex(x => x.Process); } } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240904114609_AddProcess.Designer.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240904114609_AddProcess.Designer.cs new file mode 100644 index 000000000..aa766926a --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240904114609_AddProcess.Designer.cs @@ -0,0 +1,1793 @@ +// +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("20240904114609_AddProcess")] + partial class AddProcess + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Actors.Actor", 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.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.HasIndex("ActorTypeId"); + + b.ToTable("Actor"); + + b.HasDiscriminator().HasValue("Actor"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Actors.ActorType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("ActorType"); + + b.HasData( + new + { + Id = 1, + Name = "PartyRepresentative" + }, + new + { + Id = 2, + Name = "ServiceOwner" + }); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.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.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.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.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("RelatedActivityId") + .HasColumnType("uuid"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("RelatedActivityId"); + + b.HasIndex("TransmissionId"); + + 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.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") + .IsRequired() + .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.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("PrecedingProcess") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Process") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + 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("Process"); + + 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.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("EndUserTypeId"); + + 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.Contents.DialogTransmissionContent", 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") + .IsRequired() + .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("DialogTransmissionContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.Contents.DialogTransmissionContentType", 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("DialogTransmissionContentType"); + + 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.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("TypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DialogId"); + + b.HasIndex("RelatedTransmissionId"); + + 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.Activities.DialogActivityPerformedByActor", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Actors.Actor"); + + b.Property("ActivityId") + .HasColumnType("uuid"); + + b.HasIndex("ActivityId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogActivityPerformedByActor"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSeenLogSeenByActor", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Actors.Actor"); + + b.Property("DialogSeenLogId") + .HasColumnType("uuid"); + + b.HasIndex("DialogSeenLogId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogSeenLogSeenByActor"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionSenderActor", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Actors.Actor"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogTransmissionSenderActor"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogAttachment", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Attachments.Attachment"); + + b.Property("DialogId") + .HasColumnType("uuid"); + + b.HasIndex("DialogId"); + + b.HasDiscriminator().HasValue("DialogAttachment"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionAttachment", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Attachments.Attachment"); + + b.Property("TransmissionId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionId"); + + b.HasDiscriminator().HasValue("DialogTransmissionAttachment"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.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.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.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.Transmissions.Contents.DialogTransmissionContentValue", b => + { + b.HasBaseType("Digdir.Domain.Dialogporten.Domain.Localizations.LocalizationSet"); + + b.Property("TransmissionContentId") + .HasColumnType("uuid"); + + b.HasIndex("TransmissionContentId") + .IsUnique(); + + b.HasDiscriminator().HasValue("DialogTransmissionContentValue"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Actors.Actor", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Actors.ActorType", "ActorType") + .WithMany() + .HasForeignKey("ActorTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ActorType"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Attachments.AttachmentUrl", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Attachments.Attachment", "Attachment") + .WithMany("Urls") + .HasForeignKey("AttachmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Attachments.AttachmentUrlConsumerType", "ConsumerType") + .WithMany() + .HasForeignKey("ConsumerTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Attachment"); + + b.Navigation("ConsumerType"); + }); + + 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.Activities.DialogActivity", "RelatedActivity") + .WithMany("RelatedActivities") + .HasForeignKey("RelatedActivityId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "Transmission") + .WithMany("Activities") + .HasForeignKey("TransmissionId") + .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("RelatedActivity"); + + b.Navigation("Transmission"); + + b.Navigation("Type"); + }); + + 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.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.Navigation("Dialog"); + + b.Navigation("EndUserType"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.Contents.DialogTransmissionContent", 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.Transmissions.Contents.DialogTransmissionContentType", "Type") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Transmission"); + + b.Navigation("Type"); + }); + + 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("RelatedTransmissions") + .HasForeignKey("RelatedTransmissionId") + .OnDelete(DeleteBehavior.SetNull); + + 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("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.Activities.DialogActivityPerformedByActor", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivity", "Activity") + .WithOne("PerformedBy") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities.DialogActivityPerformedByActor", "ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Activity"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSeenLogSeenByActor", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSeenLog", "DialogSeenLog") + .WithOne("SeenBy") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.DialogSeenLogSeenByActor", "DialogSeenLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DialogSeenLog"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionSenderActor", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", "Transmission") + .WithOne("Sender") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmissionSenderActor", "TransmissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Transmission"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.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.Transmissions.DialogTransmissionAttachment", 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.Attachments.AttachmentDisplayName", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Attachments.Attachment", "Attachment") + .WithOne("DisplayName") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Attachments.AttachmentDisplayName", "AttachmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Attachment"); + }); + + 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.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.Transmissions.Contents.DialogTransmissionContentValue", b => + { + b.HasOne("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.Contents.DialogTransmissionContent", "TransmissionContent") + .WithOne("Value") + .HasForeignKey("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.Contents.DialogTransmissionContentValue", "TransmissionContentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TransmissionContent"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Attachments.Attachment", b => + { + b.Navigation("DisplayName"); + + b.Navigation("Urls"); + }); + + 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("PerformedBy") + .IsRequired(); + + b.Navigation("RelatedActivities"); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents.DialogContent", 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.DialogSeenLog", b => + { + b.Navigation("SeenBy") + .IsRequired(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.Contents.DialogTransmissionContent", b => + { + b.Navigation("Value") + .IsRequired(); + }); + + modelBuilder.Entity("Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.DialogTransmission", b => + { + b.Navigation("Activities"); + + b.Navigation("Attachments"); + + b.Navigation("Content"); + + b.Navigation("RelatedTransmissions"); + + b.Navigation("Sender") + .IsRequired(); + }); + + 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/20240904114609_AddProcess.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240904114609_AddProcess.cs new file mode 100644 index 000000000..c32cd4a4e --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20240904114609_AddProcess.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Digdir.Domain.Dialogporten.Infrastructure.Persistence.Migrations +{ + /// + public partial class AddProcess : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "PrecedingProcess", + table: "Dialog", + type: "character varying(255)", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "Process", + table: "Dialog", + type: "character varying(255)", + maxLength: 255, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Dialog_Process", + table: "Dialog", + column: "Process"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Dialog_Process", + table: "Dialog"); + + migrationBuilder.DropColumn( + name: "PrecedingProcess", + table: "Dialog"); + + migrationBuilder.DropColumn( + name: "Process", + table: "Dialog"); + } + } +} diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs index 98ef08ce7..3ce2172c2 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs @@ -627,6 +627,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character varying(255)") .UseCollation("C"); + b.Property("PrecedingProcess") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Process") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + b.Property("Progress") .HasColumnType("integer"); @@ -668,6 +676,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("Party"); + b.HasIndex("Process"); + b.HasIndex("ServiceResource"); b.HasIndex("StatusId"); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json b/src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json index b561c7066..e1067c8d2 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json +++ b/src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json @@ -74,7 +74,7 @@ "UseLocalDevelopmentCloudEventBus": true, "UseLocalDevelopmentCompactJwsGenerator": true, "DisableShortCircuitOutboxDispatcher": true, - "DisableCache": false, + "DisableCache": true, "DisableAuth": true } } diff --git a/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs b/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs index 15ffde70e..27a7d1d56 100644 --- a/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs +++ b/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs @@ -29,6 +29,7 @@ public static CreateDialogCommand GenerateFakeDialog( DateTimeOffset? updatedAt = null, DateTimeOffset? dueAt = null, DateTimeOffset? expiresAt = null, + string? process = null, DialogStatus.Values? status = null, CreateDialogContentDto? content = null, List? searchTags = null, @@ -52,6 +53,7 @@ public static CreateDialogCommand GenerateFakeDialog( updatedAt, dueAt, expiresAt, + process, status, content, searchTags, @@ -77,6 +79,7 @@ public static List GenerateFakeDialogs( DateTimeOffset? updatedAt = null, DateTimeOffset? dueAt = null, DateTimeOffset? expiresAt = null, + string? process = null, DialogStatus.Values? status = null, CreateDialogContentDto? content = null, List? searchTags = null, @@ -104,6 +107,7 @@ public static List GenerateFakeDialogs( .RuleFor(o => o.GuiActions, _ => guiActions ?? GenerateFakeDialogGuiActions()) .RuleFor(o => o.ApiActions, _ => apiActions ?? GenerateFakeDialogApiActions()) .RuleFor(o => o.Activities, _ => activities ?? GenerateFakeDialogActivities()) + .RuleFor(o => o.Process, f => process ?? GenerateFakeProcessUri()) .Generate(count); } @@ -277,6 +281,11 @@ public static List GenerateFakeDialogApi .Generate(new Randomizer().Number(min: 1, 4)); } + public static string GenerateFakeProcessUri() + { + return new Faker().Internet.UrlWithPath(); + } + public static List GenerateFakeDialogGuiActions() { var hasPrimary = false; diff --git a/tests/k6/common/dialog.js b/tests/k6/common/dialog.js index 0b602b914..c3f7b5c17 100644 --- a/tests/k6/common/dialog.js +++ b/tests/k6/common/dialog.js @@ -83,6 +83,12 @@ export function setParty(dialog, party) { dialog.party = party; } +export function setProcess(dialog, process) { + if (!isValidURI(process)) { + throw new Error("Invalid process provided. " + process); + } + dialog.process = process; +} export function setDueAt(dialog, dueAt) { if (dueAt == null) { delete dialog.dueAt; diff --git a/tests/k6/common/testimports.js b/tests/k6/common/testimports.js index 40b05e4bc..64914fba1 100644 --- a/tests/k6/common/testimports.js +++ b/tests/k6/common/testimports.js @@ -24,5 +24,6 @@ export { setParty, setDueAt, setExpiresAt, - setVisibleFrom + setVisibleFrom, + setProcess } from './dialog.js'; diff --git a/tests/k6/tests/enduser/dialogSearch.js b/tests/k6/tests/enduser/dialogSearch.js index f75f7ef13..8c5ddddba 100644 --- a/tests/k6/tests/enduser/dialogSearch.js +++ b/tests/k6/tests/enduser/dialogSearch.js @@ -14,20 +14,24 @@ import { setDueAt, setExpiresAt, setVisibleFrom, + setProcess, postSO, putSO, - purgeSO } from '../../common/testimports.js' + purgeSO +} from '../../common/testimports.js' + +import {default as dialogToInsert} from '../serviceowner/testdata/01-create-dialog.js'; +import {getDefaultEnduserOrgNo, getDefaultEnduserSsn} from '../../common/token.js'; -import { default as dialogToInsert } from '../serviceowner/testdata/01-create-dialog.js'; -import { getDefaultEnduserOrgNo, getDefaultEnduserSsn } from '../../common/token.js'; export default function () { let dialogs = []; let dialogIds = []; let titleToSearchFor = uuidv4(); + let processToSearchFor = "urn:test:process:1" let additionalInfoToSearchFor = uuidv4(); - let searchTagsToSearchFor = [ uuidv4(), uuidv4() ]; + let searchTagsToSearchFor = [uuidv4(), uuidv4()]; let extendedStatusToSearchFor = "status:" + uuidv4(); let secondExtendedStatusToSearchFor = "status:" + uuidv4(); let senderNameToSearchFor = uuidv4() @@ -44,10 +48,10 @@ export default function () { let auxOrg = "ttd"; describe('Arrange: Create some dialogs to test against', () => { - for (let i = 0; i < 15; i++) { let d = dialogToInsert(); - setTitle(d, "e2e-test-dialog eu #" + (i+1), "nn_NO"); + setTitle(d, "e2e-test-dialog eu #" + (i + 1), "nn_NO"); + setProcess(d, ("urn:test:process:" + (i + 1))); setParty(d, defaultParty); setVisibleFrom(d, null); dialogs.push(d); @@ -74,18 +78,18 @@ export default function () { dialogs[++d].id = idForCustomOrg; - setTitle(dialogs[dialogs.length-1], titleForLastItem); + setTitle(dialogs[dialogs.length - 1], titleForLastItem); let tokenOptions = {}; dialogs.forEach((d) => { - tokenOptions = (d.id == idForCustomOrg) ? { orgName: auxOrg } : {}; + tokenOptions = (d.id == idForCustomOrg) ? {orgName: auxOrg} : {}; let r = postSO("dialogs", d, null, tokenOptions); expectStatusFor(r).to.equal(201); dialogIds.push(r.json()); }); - let penultimateDialog = dialogs[dialogs.length-2]; - let penultimateDialogId = dialogIds[dialogIds.length-2]; + let penultimateDialog = dialogs[dialogs.length - 2]; + let penultimateDialogId = dialogIds[dialogIds.length - 2]; setTitle(penultimateDialog, titleForUpdatedItem); let r = putSO("dialogs/" + penultimateDialogId, penultimateDialog); expectStatusFor(r).to.equal(204); @@ -192,6 +196,21 @@ export default function () { expect(r.json().items[0], 'party').to.have.property("serviceResource").that.equals(auxResource); }); + describe('List with invalid process filter', () => { + let r = getEU('dialogs/' + defaultFilter + '&process=.,.'); + expectStatusFor(r).to.equal(400); + expect(r, 'response').to.have.validJsonBody(); + expect(r.json(), 'response json').to.have.property("errors"); + expect(r.json().errors, 'errors').to.have.property("Process").with.lengthOf(1); + }) + + describe('List with process filter', () => { + let r = getEU('dialogs/' + defaultFilter + '&process=' + processToSearchFor); + expectStatusFor(r).to.equal(200); + expect(r, 'response').to.have.validJsonBody(); + expect(r.json(), 'response json').to.have.property("items").with.lengthOf(1); + expect(r.json().items[0], 'process').to.have.property("process").that.equals(processToSearchFor); + }) /* Disabled for now. Dialogporten doesn't have proper TTD handling as of yet. diff --git a/tests/k6/tests/serviceowner/all-tests.js b/tests/k6/tests/serviceowner/all-tests.js index 54d955943..df5c1d0b6 100644 --- a/tests/k6/tests/serviceowner/all-tests.js +++ b/tests/k6/tests/serviceowner/all-tests.js @@ -4,6 +4,7 @@ import { default as authorization } from './authorization.js'; import { default as concurrency } from './concurrency.js'; import { default as dialogCreateExternalResource } from './dialogCreateExternalResource.js'; import { default as dialogCreateInvalidActionCount } from './dialogCreateInvalidActionCount.js'; +import { default as dialogCreateInvalidProcess } from './dialogCreateInvalidProcess.js'; import { default as dialogCreatePatchDelete } from './dialogCreatePatchDelete.js'; import { default as dialogSearch } from './dialogSearch.js'; @@ -13,6 +14,7 @@ export default function() { concurrency(); dialogCreateExternalResource(); dialogCreateInvalidActionCount(); + dialogCreateInvalidProcess(); dialogCreatePatchDelete(); dialogSearch(); } diff --git a/tests/k6/tests/serviceowner/dialogCreateInvalidActionCount.js b/tests/k6/tests/serviceowner/dialogCreateInvalidActionCount.js index 5bf9217f8..e18ae24a6 100644 --- a/tests/k6/tests/serviceowner/dialogCreateInvalidActionCount.js +++ b/tests/k6/tests/serviceowner/dialogCreateInvalidActionCount.js @@ -23,6 +23,8 @@ export default function () { return dialog; }; + + describe('Attempt dialog create with two primary actions', () => { expectGuiActionErrorResponseForDialog(createDialogWithGuiActions(2, "primary")); diff --git a/tests/k6/tests/serviceowner/dialogCreateInvalidProcess.js b/tests/k6/tests/serviceowner/dialogCreateInvalidProcess.js new file mode 100644 index 000000000..bbf9f8598 --- /dev/null +++ b/tests/k6/tests/serviceowner/dialogCreateInvalidProcess.js @@ -0,0 +1,15 @@ +import { describe, expect, expectStatusFor, postSO } from '../../common/testimports.js' +import { default as dialogToInsert } from './testdata/01-create-dialog.js'; + + +export default function (){ + + describe ('Attempt to create dialog with invalid URI', () => { + let dialog = dialogToInsert(); + dialog.process = '.,.'; + let r = postSO('dialogs', dialog) + expectStatusFor(r).to.equal(400); + expect(r, 'response').to.have.validJsonBody(); + expect(r.json(), 'response body').to.have.property('errors'); + }) +} diff --git a/tests/k6/tests/serviceowner/dialogSearch.js b/tests/k6/tests/serviceowner/dialogSearch.js index b0a695c39..fa1a1c9a2 100644 --- a/tests/k6/tests/serviceowner/dialogSearch.js +++ b/tests/k6/tests/serviceowner/dialogSearch.js @@ -12,6 +12,7 @@ import { setServiceResource, setParty, setDueAt, + setProcess, setExpiresAt, setVisibleFrom, postSO, @@ -28,6 +29,7 @@ export default function () { let dialogIds = []; let titleToSearchFor = uuidv4(); + let processToSeachFor = "urn:test:process:1"; let additionalInfoToSearchFor = uuidv4(); let searchTagsToSearchFor = [ uuidv4(), uuidv4() ]; let extendedStatusToSearchFor = "status:" + uuidv4(); @@ -47,6 +49,7 @@ export default function () { for (let i = 0; i < 20; i++) { let d = dialogToInsert(); setTitle(d, "e2e-test-dialog #" + (i+1), "nn_NO"); + setProcess(d, "urn:test:process:" + (i+1)) dialogs.push(d); } @@ -173,7 +176,21 @@ export default function () { expect(r.json(), 'response json').to.have.property("items").with.lengthOf(1); expect(r.json().items[0], 'party').to.have.property("serviceResource").that.equals(auxResource); }); + + describe('List with invalid process', () => { + let r = getSO('dialogs/?CreatedAfter=' + createdAfter + '&process=.,.'); + expectStatusFor(r).to.equal(400); + expect(r, 'response').to.have.validJsonBody(); + expect(r.json(), 'response json').to.have.property("errors"); + }) + describe('List with process', () => { + let r = getSO('dialogs/?CreatedAfter=' + createdAfter + '&process=' + processToSeachFor); + expectStatusFor(r).to.equal(200); + expect(r, 'response').to.have.validJsonBody(); + expect(r.json(), 'response json').to.have.property("items").with.lengthOf(1); + expect(r.json().items[0], 'process').to.have.property("process").that.equals(processToSeachFor); + }) describe("Cleanup", () => { dialogIds.forEach((d) => { let r = purgeSO("dialogs/" + d); diff --git a/tests/k6/tests/serviceowner/testdata/01-create-dialog.js b/tests/k6/tests/serviceowner/testdata/01-create-dialog.js index 72b0a96da..dffaad574 100644 --- a/tests/k6/tests/serviceowner/testdata/01-create-dialog.js +++ b/tests/k6/tests/serviceowner/testdata/01-create-dialog.js @@ -10,6 +10,7 @@ export default function () { "dueAt": "2033-11-25T06:37:54.2920190Z", // must be UTC "expiresAt": "2053-11-25T06:37:54.2920190Z", // must be UTC "visibleFrom": "2032-11-25T06:37:54.2920190Z", // must be UTC + "process": "urn:test:process:1", "searchTags": [ { "value": "something searchable" }, { "value": "something else searchable" }