From a0c6af480811090b05bcee57e60e204448dbc460 Mon Sep 17 00:00:00 2001 From: CelineTrammi <61122289+CelineTrammi@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:19:38 +0200 Subject: [PATCH] Feat: Add confirmation requirement `IsConfirmationNeeded` to correspondence (#387) * fix: if correspondence is not available, return 404 regardless of requested status * delete old InitializedCorrespondenceFactory * Add IsConfirmationNeeded field to CorrespondenceEntity, requests, responses, and DB * logic for handling IsConfirmationNeeded added * Add tests for archived and purged correspondence * fix: exclaimation mark used twice in condition check * Add extension method for checking if a correspondence has had a specific status * fix: map correctly IsConfirmationNeeded in response for GET calls * Update postman collection * make IsConfirmationNeeded not required, as default becomes false * add workflow for checking label for new PRs (#384) * add workflow for checking label for new PRs * rerun job when PR is set to ready for review * add better name to workflow * Update .github/workflows/check-label-for-pr.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/check-label-for-pr.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * add more triggers on PR to run workflow * fix: remove ignore-for-release in labels list --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Fix Maskinporten token error (#386) * OnChallenge modifies response object. Instead, use exception from authentication failure to short-circuit onchallenge handler when failure source is known (used Maskinporten token on Altinn token endpoint), and set the response there instead. * Seal it at least * Null handle * Async should be awaited * Legacy - authorize multiple recipients (#388) * Accessmanagement to enable multiple recipients * cleanup and improvements --------- Co-authored-by: Hammerbeck * Make DueDateTime nullable * Add IsConfirmationNeeded field to CorrespondenceEntity, requests, responses, and DB * logic for handling IsConfirmationNeeded added * rebase fix: delete duplicate IsConfirmationNeeded migration * make DueDateTime required if IsConfirmationNeeded is used * add boolean param to WithConfirmationNeeded --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Roar Mjelde <36594318+Ceredron@users.noreply.github.com> Co-authored-by: Andreas Hammerbeck Co-authored-by: Hammerbeck --- .../CorrespondenceControllerTests.cs | 134 ++++- .../Factories/CorrespondenceBuilder.cs | 10 +- .../InitializeCorrespondenceFactory.cs | 339 ------------ altinn-correspondence-postman-collection.json | 15 +- .../Mappers/CorrespondenceDetailsMapper.cs | 3 +- .../Mappers/CorrespondenceOverviewMapper.cs | 3 +- .../InitializeCorrespondencesMapper.cs | 1 + .../Mappers/MigrateCorrespondenceMapper.cs | 1 + .../Models/BaseCorrespondenceExt.cs | 6 + .../CheckNotificationHandler.cs | 3 +- .../CorrespondenceDueDateHandler.cs | 9 +- .../Errors.cs | 2 + .../GetCorrespondenceDetailsHandler.cs | 3 +- .../GetCorrespondenceDetailsResponse.cs | 2 + .../GetCorrespondenceOverviewHandler.cs | 3 +- .../GetCorrespondenceOverviewResponse.cs | 2 + .../Helpers/AttachmentExtensions.cs | 5 + .../Helpers/CorrespondenceExtensions.cs | 5 +- .../Helpers/InitializeCorrespondenceHelper.cs | 2 +- .../InitializeCorrespondencesHandler.cs | 5 + .../MigrateUploadAttachmentHandler.cs | 2 +- .../PurgeAttachment/PurgeAttachmentHandler.cs | 2 +- .../PurgeCorrespondenceHandler.cs | 6 +- .../UpdateCorrespondenceStatusHandler.cs | 6 +- .../UpdateMarkAsUnreadHandler.cs | 2 +- .../UploadAttachmentHandler.cs | 2 +- .../Models/Entities/CorrespondenceEntity.cs | 2 + ...3535_AddedIsConfirmationNeeded.Designer.cs | 510 ++++++++++++++++++ ...0241024103535_AddedIsConfirmationNeeded.cs | 31 ++ .../ApplicationDbContextModelSnapshot.cs | 3 + 30 files changed, 741 insertions(+), 378 deletions(-) delete mode 100644 Test/Altinn.Correspondence.Tests/Factories/InitializeCorrespondenceFactory.cs create mode 100644 src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.Designer.cs create mode 100644 src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.cs diff --git a/Test/Altinn.Correspondence.Tests/CorrespondenceControllerTests.cs b/Test/Altinn.Correspondence.Tests/CorrespondenceControllerTests.cs index c83dd943..59c10db1 100644 --- a/Test/Altinn.Correspondence.Tests/CorrespondenceControllerTests.cs +++ b/Test/Altinn.Correspondence.Tests/CorrespondenceControllerTests.cs @@ -321,6 +321,37 @@ public async Task InitializeCorrespondence_AllowSystemDeleteAfter_PriorDueDate_R Assert.Equal(HttpStatusCode.BadRequest, initializeCorrespondenceResponse.StatusCode); } + [Fact] + public async Task InitializeCorrespondence_WithConfirmationNeeded_Without_DueDate_Returns_BadRequest() + { + // Arrange + var payload = new CorrespondenceBuilder() + .CreateCorrespondence() + .WithConfirmationNeeded(true) + .Build(); + + // Act + var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", payload); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, initializeCorrespondenceResponse.StatusCode); + } + + [Fact] + public async Task InitializeCorrespondence_With_RequestedPublishTime_Null() + { + // Arrange + var correspondence = new CorrespondenceBuilder() + .CreateCorrespondence() + .WithRequestedPublishTime(null) + .Build(); + + var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", correspondence); + + // Assert + Assert.Equal(HttpStatusCode.OK, initializeCorrespondenceResponse.StatusCode); + } + [Fact] public async Task UploadCorrespondence_Gives_Ok() { @@ -921,6 +952,50 @@ public async Task ReceiverMarkActions_CorrespondencePublished_ReturnOk() Assert.True(overview?.MarkedUnread == true); } + [Fact] + public async Task UpdateCorrespondenceStatus_ToArchived_WithoutConfirmation_WhenConfirmationNeeded_ReturnsBadRequest() + { + // Arrange + var payload = new CorrespondenceBuilder() + .CreateCorrespondence() + .WithDueDateTime(DateTimeOffset.UtcNow.AddDays(1)) + .WithConfirmationNeeded(true) + .Build(); + var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", payload); + var correspondenceResponse = await initializeCorrespondenceResponse.Content.ReadFromJsonAsync(_responseSerializerOptions); + Assert.Equal(CorrespondenceStatus.Published, correspondenceResponse?.Correspondences?.FirstOrDefault()?.Status); + var correspondenceId = correspondenceResponse?.Correspondences?.FirstOrDefault()?.CorrespondenceId; + + // Act + var archiveResponse = await _recipientClient.PostAsync($"correspondence/api/v1/correspondence/{correspondenceId}/archive", null); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, archiveResponse.StatusCode); + } + + [Fact] + public async Task UpdateCorrespondenceStatus_ToArchived_WithConfirmation_WhenConfirmationNeeded_GivesOk() + { + // Arrange + var payload = new CorrespondenceBuilder() + .CreateCorrespondence() + .WithDueDateTime(DateTimeOffset.UtcNow.AddDays(1)) + .WithConfirmationNeeded(true) + .Build(); + var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", payload); + var correspondenceResponse = await initializeCorrespondenceResponse.Content.ReadFromJsonAsync(_responseSerializerOptions); + Assert.Equal(CorrespondenceStatus.Published, correspondenceResponse?.Correspondences?.FirstOrDefault()?.Status); + var correspondenceId = correspondenceResponse?.Correspondences?.FirstOrDefault()?.CorrespondenceId; + + // Act + var confirmResponse = await _recipientClient.PostAsync($"correspondence/api/v1/correspondence/{correspondenceId}/confirm", null); + Assert.Equal(HttpStatusCode.OK, confirmResponse.StatusCode); + var archiveResponse = await _recipientClient.PostAsync($"correspondence/api/v1/correspondence/{correspondenceId}/archive", null); + + // Assert + Assert.Equal(HttpStatusCode.OK, archiveResponse.StatusCode); + } + [Fact] public async Task Correspondence_with_dataLocationUrl_Reuses_Attachment() { @@ -1059,6 +1134,50 @@ public async Task Delete_Published_Correspondence_SuccessForRecipient_FailsForSe Assert.Equal(overview?.Status, CorrespondenceStatusExt.PurgedByRecipient); } + [Fact] + public async Task Delete_Published_Correspondence_WithoutConfirmation_WhenConfirmationNeeded_ReturnsBadRequest() + { + // Arrange + var payload = new CorrespondenceBuilder() + .CreateCorrespondence() + .WithDueDateTime(DateTimeOffset.UtcNow.AddDays(1)) + .WithConfirmationNeeded(true) + .Build(); + var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", payload); + var correspondenceResponse = await initializeCorrespondenceResponse.Content.ReadFromJsonAsync(_responseSerializerOptions); + Assert.Equal(CorrespondenceStatus.Published, correspondenceResponse?.Correspondences?.FirstOrDefault()?.Status); + var correspondenceId = correspondenceResponse?.Correspondences?.FirstOrDefault()?.CorrespondenceId; + + // Act + var deleteResponse = await _recipientClient.DeleteAsync($"correspondence/api/v1/correspondence/{correspondenceId}/purge"); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, deleteResponse.StatusCode); + } + + [Fact] + public async Task Delete_Published_Correspondence_WithConfirmation_WhenConfirmationNeeded_Gives_OK() + { + // Arrange + var payload = new CorrespondenceBuilder() + .CreateCorrespondence() + .WithDueDateTime(DateTimeOffset.UtcNow.AddDays(1)) + .WithConfirmationNeeded(true) + .Build(); + var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", payload); + var correspondenceResponse = await initializeCorrespondenceResponse.Content.ReadFromJsonAsync(_responseSerializerOptions); + Assert.Equal(CorrespondenceStatus.Published, correspondenceResponse?.Correspondences?.FirstOrDefault()?.Status); + var correspondenceId = correspondenceResponse?.Correspondences?.FirstOrDefault()?.CorrespondenceId; + + // Act + var confirmResponse = await _recipientClient.PostAsync($"correspondence/api/v1/correspondence/{correspondenceId}/confirm", null); + Assert.Equal(HttpStatusCode.OK, confirmResponse.StatusCode); + var deleteResponse = await _recipientClient.DeleteAsync($"correspondence/api/v1/correspondence/{correspondenceId}/purge"); + + // Assert + Assert.Equal(HttpStatusCode.OK, deleteResponse.StatusCode); + } + [Fact] public async Task Delete_Correspondence_Also_deletes_attachment() { @@ -1477,21 +1596,6 @@ public async Task CancelNotificationHandler_SendsSlackNotification_WhenCancellat slackClientMock.Verify(client => client.Post(It.IsAny()), Times.Once); } - [Fact] - public async Task InitializeCorrespondence_With_RequestedPublishTime_Null() - { - // Arrange - var correspondence = new CorrespondenceBuilder() - .CreateCorrespondence() - .WithRequestedPublishTime(null) - .Build(); - - var initializeCorrespondenceResponse = await _senderClient.PostAsJsonAsync("correspondence/api/v1/correspondence", correspondence); - - // Assert - Assert.Equal(HttpStatusCode.OK, initializeCorrespondenceResponse.StatusCode); - } - private MultipartFormDataContent CorrespondenceToFormData(BaseCorrespondenceExt correspondence) { var formData = new MultipartFormDataContent(){ diff --git a/Test/Altinn.Correspondence.Tests/Factories/CorrespondenceBuilder.cs b/Test/Altinn.Correspondence.Tests/Factories/CorrespondenceBuilder.cs index 64e05583..83775b28 100644 --- a/Test/Altinn.Correspondence.Tests/Factories/CorrespondenceBuilder.cs +++ b/Test/Altinn.Correspondence.Tests/Factories/CorrespondenceBuilder.cs @@ -33,7 +33,8 @@ public CorrespondenceBuilder CreateCorrespondence() {"culpa_852", "2"}, {"anim5", "3"} }, - IgnoreReservation = false + IgnoreReservation = false, + IsConfirmationNeeded = false, }, Recipients = new List(){ "0192:991825827", // org number @@ -129,6 +130,11 @@ public CorrespondenceBuilder WithAllowSystemDeleteAfter(DateTimeOffset dueDateTi _correspondence.Correspondence.AllowSystemDeleteAfter = dueDateTime; return this; } + public CorrespondenceBuilder WithConfirmationNeeded(bool confirmationNeeded) + { + _correspondence.Correspondence.IsConfirmationNeeded = confirmationNeeded; + return this; + } public CorrespondenceBuilder WithNotificationTemplate(NotificationTemplateExt notificationTemplate) { _correspondence.Correspondence.Notification ??= new InitializeCorrespondenceNotificationExt() @@ -196,7 +202,7 @@ public static CorrespondenceEntity CorrespondenceEntityWithNotifications() NotificationTemplate = new Core.Models.Enums.NotificationTemplate(), NotificationChannel = new Core.Models.Enums.NotificationChannel(), } - } + }, }; } } diff --git a/Test/Altinn.Correspondence.Tests/Factories/InitializeCorrespondenceFactory.cs b/Test/Altinn.Correspondence.Tests/Factories/InitializeCorrespondenceFactory.cs deleted file mode 100644 index 57faf984..00000000 --- a/Test/Altinn.Correspondence.Tests/Factories/InitializeCorrespondenceFactory.cs +++ /dev/null @@ -1,339 +0,0 @@ -using Altinn.Correspondence.API.Models; -using Altinn.Correspondence.API.Models.Enums; -using Altinn.Correspondence.Core.Models.Entities; - -namespace Altinn.Correspondence.Tests.Factories; -internal static class InitializeCorrespondenceFactory -{ - internal static InitializeCorrespondencesExt BasicCorrespondences(string? url = null) => new InitializeCorrespondencesExt() - { - Correspondence = new BaseCorrespondenceExt() - { - ResourceId = "1", - Sender = "0192:991825827", - SendersReference = "1", - Content = new InitializeCorrespondenceContentExt() - { - Language = "no", - MessageTitle = "test", - MessageSummary = "# test", - MessageBody = "# test body /n __test__ /n **test**/n [test](www.test.no) /n ![test](www.test.no) /n ```test``` /n > test /n - test /n 1. test /n 1. test /n [x] test /n [ ] test /n ## test /n ### test /n #### test /n ##### test /n ###### test /n + test list /n - test list /n * list element", - Attachments = new List() { - new InitializeCorrespondenceAttachmentExt() - { - DataType = "html", - Name = "2", - RestrictionName = "testFile2", - SendersReference = "1234", - FileName = "test-fil2e", - IsEncrypted = false, - } - }, - }, - RequestedPublishTime = DateTimeOffset.UtcNow, - AllowSystemDeleteAfter = DateTimeOffset.UtcNow.AddDays(3), - DueDateTime = DateTimeOffset.UtcNow.AddDays(2), - ExternalReferences = new List(){ - new ExternalReferenceExt() - { - ReferenceValue = "1", - ReferenceType = ReferenceTypeExt.AltinnBrokerFileTransfer - }, - new ExternalReferenceExt() - { - ReferenceValue = "2", - ReferenceType = ReferenceTypeExt.DialogportenProcessId - } - }, - PropertyList = new Dictionary(){ - {"deserunt_12", "1"}, - {"culpa_852", "2"}, - {"anim5", "3"} - }, - ReplyOptions = new List(){ - new CorrespondenceReplyOptionExt() - { - LinkURL = "www.test.no", - LinkText = "test" - }, - new CorrespondenceReplyOptionExt() - { - LinkURL = "test.no", - LinkText = "test" - } - }, - Notification = new InitializeCorrespondenceNotificationExt() - { - NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage, - NotificationChannel = NotificationChannelExt.Email, - SendersReference = "0192:986252932", - RequestedSendTime = DateTimeOffset.UtcNow.AddDays(1), - SendReminder = true, - }, - IgnoreReservation = false - }, - Recipients = new List(){ - "0192:991825827", - "0192:986252932", - "0192:986252933" - }, - ExistingAttachments = new List(), - }; - - internal static InitializeCorrespondencesExt BasicCorrespondenceWithFileAttachment() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.Attachments.Add( - new InitializeCorrespondenceAttachmentExt() - { - DataType = "pdf", - Name = "3", - RestrictionName = "testFile3", - SendersReference = "1234", - FileName = "test-fil3e", - IsEncrypted = false - }); - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithAttachment(List attachments) - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.Attachments = attachments; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithNoMessageBody() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.MessageBody = null; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithoutAttachments() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.Attachments = new List() - { - }; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceAlreadyVisible() - { - var data = BasicCorrespondences(); - data.Correspondence.RequestedPublishTime = DateTimeOffset.UtcNow.AddDays(-1); - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithHtmlInTitle() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.MessageTitle = "

test

"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithMarkdownInTitle() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.MessageTitle = "# test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithHtmlInSummary() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.MessageSummary = "

test

"; - - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithHtmlInBody() - { - var data = BasicCorrespondences(); - data.Correspondence.Content!.MessageBody = "

test

"; - - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithGenericAltinnEmailNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.EmailBody = "test"; - data.Correspondence.Notification!.EmailSubject = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderEmailBody = "test"; - data.Correspondence.Notification!.ReminderEmailSubject = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithGenericAltinnSmsNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.SmsBody = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithEmptyGenericAltinnEmailNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.SendReminder = true; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithEmptyGenericAltinnSmsNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.SendReminder = true; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithPrefferedEmailCustomNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.EmailPreferred; - data.Correspondence.Notification!.EmailBody = "test"; - data.Correspondence.Notification!.EmailSubject = "test"; - data.Correspondence.Notification!.SmsBody = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderEmailBody = "test"; - data.Correspondence.Notification!.ReminderEmailSubject = "test"; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithPrefferedEmailAltinnNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.EmailPreferred; - data.Correspondence.Notification!.SendReminder = true; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithCustomEmailNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.EmailBody = "test"; - data.Correspondence.Notification!.EmailSubject = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderEmailBody = "test"; - data.Correspondence.Notification!.ReminderEmailSubject = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithCustomSmsNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.SmsBody = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithEmptyCustomEmailNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.SendReminder = true; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithEmptyCustomSmsNotification() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.SendReminder = true; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithPrefferedDataWithMissingData() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithPrefferedDataWithMissingReminderData() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.CustomMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.EmailBody = "test"; - data.Correspondence.Notification!.EmailSubject = "test"; - data.Correspondence.Notification!.SendReminder = true; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithEmailNotificationWithSmsReminder() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.ReminderNotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.EmailBody = "test"; - data.Correspondence.Notification!.EmailSubject = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithEmailNotificationWithSmsPrefferedReminder() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.ReminderNotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.EmailBody = "test"; - data.Correspondence.Notification!.EmailSubject = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - data.Correspondence.Notification!.ReminderEmailBody = "test"; - data.Correspondence.Notification!.ReminderEmailSubject = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithSmsNotificationAndEmailReminder() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.ReminderNotificationChannel = NotificationChannelExt.Email; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderEmailBody = "test"; - data.Correspondence.Notification!.ReminderEmailSubject = "test"; - return data; - } - internal static InitializeCorrespondencesExt BasicCorrespondenceWithSmsNotificationAndEmailPrefferedReminder() - { - var data = BasicCorrespondences(); - data.Correspondence.Notification!.NotificationTemplate = NotificationTemplateExt.GenericAltinnMessage; - data.Correspondence.Notification!.NotificationChannel = NotificationChannelExt.Sms; - data.Correspondence.Notification!.ReminderNotificationChannel = NotificationChannelExt.EmailPreferred; - data.Correspondence.Notification!.ReminderSmsBody = "test"; - data.Correspondence.Notification!.SendReminder = true; - data.Correspondence.Notification!.ReminderEmailBody = "test"; - data.Correspondence.Notification!.ReminderEmailSubject = "test"; - return data; - } - internal static CorrespondenceEntity CorrespondenceEntityWithNotifications() - { - return new CorrespondenceEntity() - { - ResourceId = "1", - Sender = "0192:991825827", - Recipient = "0192:991825827", - SendersReference = "1", - RequestedPublishTime = DateTimeOffset.UtcNow, - Statuses = new List(), - Created = DateTimeOffset.UtcNow, - Notifications = new List() - { - new CorrespondenceNotificationEntity() - { - Created = DateTimeOffset.UtcNow, - NotificationOrderId = Guid.NewGuid(), - RequestedSendTime = DateTimeOffset.UtcNow.AddDays(1), - NotificationTemplate = new Core.Models.Enums.NotificationTemplate(), - NotificationChannel = new Core.Models.Enums.NotificationChannel(), - } - } - }; - } -} diff --git a/altinn-correspondence-postman-collection.json b/altinn-correspondence-postman-collection.json index c79cf5f5..2e4b3272 100644 --- a/altinn-correspondence-postman-collection.json +++ b/altinn-correspondence-postman-collection.json @@ -207,7 +207,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"recipient\": \"1234\",\n \"resourceId\": \"1234\",\n \"sender\": \"8536:031145332\",\n \"sendersReference\": \"1234\",\n \"content\": {\n \"language\": \"English\",\n \"messageTitle\": \"test asdf asdf>\",\n \"messageSummary\": \"asdf asdfasdf\",\n \"attachments\": [\n {\n \"dataLocationType\": \"ExisitingExternalStorage\",\n \"dataType\": \"1\",\n \"intendedPresentation\": \"HumanReadable\",\n \"name\": \"file\",\n \"restrictionName\": \"1234\",\n \"sendersReference\": \"1234\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"\",\n \"dataLocationUrl\": \"\"\n },\n {\n \"dataLocationType\": \"ExistingCorrespondenceAttachment\",\n \"dataType\": \"\",\n \"intendedPresentation\": \"MachineReadable\",\n \"name\": \"\",\n \"restrictionName\": \"\",\n \"sendersReference\": \"\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"12345123412341234123412341234123\",\n \"dataLocationUrl\": \"\"\n }\n ]\n },\n \"RequestedPublishTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"allowSystemDeleteAfter\": \"2025-05-29T13:31:28.290518+00:00\",\n \"dueDateTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"externalReferences\": [\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"AltinnBrokerFileTransfer\"\n },\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"DialogPortenDialogID\"\n }\n ],\n \"propertyList\": {\n \"deserunt_12\": \"\",\n \"culpa_852\": \"\",\n \"anim5\": \"\"\n },\n \"replyOptions\": [\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n },\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n }\n ],\n \"notifications\": [\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n },\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n }\n ],\n \"IgnoreReservation\": true\n}", + "raw": "", "options": { "raw": { "headerFamily": "json", @@ -309,7 +309,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"recipient\": \"1234\",\n \"resourceId\": \"1234\",\n \"sender\": \"8536:031145332\",\n \"sendersReference\": \"1234\",\n \"content\": {\n \"language\": \"English\",\n \"messageTitle\": \"test asdf asdf>\",\n \"messageSummary\": \"asdf asdfasdf\",\n \"attachments\": [\n {\n \"dataLocationType\": \"ExisitingExternalStorage\",\n \"dataType\": \"1\",\n \"intendedPresentation\": \"HumanReadable\",\n \"name\": \"file\",\n \"restrictionName\": \"1234\",\n \"sendersReference\": \"1234\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"\",\n \"dataLocationUrl\": \"\"\n },\n {\n \"dataLocationType\": \"ExistingCorrespondenceAttachment\",\n \"dataType\": \"\",\n \"intendedPresentation\": \"MachineReadable\",\n \"name\": \"\",\n \"restrictionName\": \"\",\n \"sendersReference\": \"\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"12345123412341234123412341234123\",\n \"dataLocationUrl\": \"\"\n }\n ]\n },\n \"RequestedPublishTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"allowSystemDeleteAfter\": \"2025-05-29T13:31:28.290518+00:00\",\n \"dueDateTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"externalReferences\": [\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"AltinnBrokerFileTransfer\"\n },\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"DialogPortenDialogID\"\n }\n ],\n \"propertyList\": {\n \"deserunt_12\": \"\",\n \"culpa_852\": \"\",\n \"anim5\": \"\"\n },\n \"replyOptions\": [\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n },\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n }\n ],\n \"notifications\": [\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n },\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n }\n ],\n \"IgnoreReservation\": true\n}", + "raw": "", "options": { "raw": { "headerFamily": "json", @@ -411,7 +411,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"recipient\": \"1234\",\n \"resourceId\": \"1234\",\n \"sender\": \"8536:031145332\",\n \"sendersReference\": \"1234\",\n \"content\": {\n \"language\": \"English\",\n \"messageTitle\": \"test asdf asdf>\",\n \"messageSummary\": \"asdf asdfasdf\",\n \"attachments\": [\n {\n \"dataLocationType\": \"ExisitingExternalStorage\",\n \"dataType\": \"1\",\n \"intendedPresentation\": \"HumanReadable\",\n \"name\": \"file\",\n \"restrictionName\": \"1234\",\n \"sendersReference\": \"1234\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"\",\n \"dataLocationUrl\": \"\"\n },\n {\n \"dataLocationType\": \"ExistingCorrespondenceAttachment\",\n \"dataType\": \"\",\n \"intendedPresentation\": \"MachineReadable\",\n \"name\": \"\",\n \"restrictionName\": \"\",\n \"sendersReference\": \"\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"12345123412341234123412341234123\",\n \"dataLocationUrl\": \"\"\n }\n ]\n },\n \"RequestedPublishTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"allowSystemDeleteAfter\": \"2025-05-29T13:31:28.290518+00:00\",\n \"dueDateTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"externalReferences\": [\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"AltinnBrokerFileTransfer\"\n },\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"DialogPortenDialogID\"\n }\n ],\n \"propertyList\": {\n \"deserunt_12\": \"\",\n \"culpa_852\": \"\",\n \"anim5\": \"\"\n },\n \"replyOptions\": [\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n },\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n }\n ],\n \"notifications\": [\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n },\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n }\n ],\n \"IgnoreReservation\": true\n}", + "raw": "", "options": { "raw": { "headerFamily": "json", @@ -513,7 +513,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"recipient\": \"1234\",\n \"resourceId\": \"1234\",\n \"sender\": \"8536:031145332\",\n \"sendersReference\": \"1234\",\n \"content\": {\n \"language\": \"English\",\n \"messageTitle\": \"test asdf asdf>\",\n \"messageSummary\": \"asdf asdfasdf\",\n \"attachments\": [\n {\n \"dataLocationType\": \"ExisitingExternalStorage\",\n \"dataType\": \"1\",\n \"intendedPresentation\": \"HumanReadable\",\n \"name\": \"file\",\n \"restrictionName\": \"1234\",\n \"sendersReference\": \"1234\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"\",\n \"dataLocationUrl\": \"\"\n },\n {\n \"dataLocationType\": \"ExistingCorrespondenceAttachment\",\n \"dataType\": \"\",\n \"intendedPresentation\": \"MachineReadable\",\n \"name\": \"\",\n \"restrictionName\": \"\",\n \"sendersReference\": \"\",\n \"fileName\": \"\",\n \"isEncrypted\": true,\n \"checksum\": \"12345123412341234123412341234123\",\n \"dataLocationUrl\": \"\"\n }\n ]\n },\n \"RequestedPublishTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"allowSystemDeleteAfter\": \"2025-05-29T13:31:28.290518+00:00\",\n \"dueDateTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"externalReferences\": [\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"AltinnBrokerFileTransfer\"\n },\n {\n \"referenceValue\": \"\",\n \"referenceType\": \"DialogPortenDialogID\"\n }\n ],\n \"propertyList\": {\n \"deserunt_12\": \"\",\n \"culpa_852\": \"\",\n \"anim5\": \"\"\n },\n \"replyOptions\": [\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n },\n {\n \"linkURL\": \"\",\n \"linkText\": \"\"\n }\n ],\n \"notifications\": [\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n },\n {\n \"notificationTemplate\": \"\",\n \"customTextToken\": \"\",\n \"sendersReference\": \"\",\n \"requestedSendTime\": \"2025-05-29T13:31:28.290518+00:00\"\n }\n ],\n \"IgnoreReservation\": true\n}", + "raw": "", "options": { "raw": { "headerFamily": "json", @@ -779,7 +779,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"Correspondence\": {\n \"resourceId\": \"{{resource_id}}\",\n \"sender\": \"0192:{{senderOrgNo}}\",\n \"sendersReference\": \"1\",\n \"content\": {\n \"language\": \"nb\",\n \"messageTitle\": \"Meldingstittel\",\n \"messageSummary\": \"Ett sammendrag for meldingen\",\n \"messageBody\": \"# meldingsteksten. Som kan være plain text eller markdown \",\n \"attachments\": [\n {\n \"dataType\": \"html\",\n \"expirationTime\": \"2024-12-12\",\n \"name\": \"1\",\n \"restrictionName\": \"testFile23\",\n \"sendersReference\": \"1234\",\n \"fileName\": \"test-fil32e\",\n \"isEncrypted\": false,\n \"dataLocationUrl\": \"\"\n }\n ]\n },\n \"RequestedPublishTime\": \"2024-09-28T12:44:28.290518+00:00\",\n \"allowSystemDeleteAfter\": \"2025-08-29T13:31:28.290518+00:00\",\n \"dueDateTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"externalReferences\": [\n {\n \"referenceValue\": \"1\",\n \"referenceType\": \"AltinnBrokerFileTransfer\"\n }\n ],\n \"propertyList\": {\n \"deserunt_12\": \"1\",\n \"culpa_852\": \"2\",\n \"anim5\": \"3\",\n \"Æ*'1??` \": \"asdfgklasjd\"\n },\n \"replyOptions\": [\n {\n \"linkURL\": \"www.test.no\",\n \"linkText\": \"test\"\n },\n {\n \"linkURL\": \"test.no\",\n \"linkText\": \"test\"\n }\n ],\n \"notification\": {\n \"notificationTemplate\": 0,\n \"notificationChannel\": 3,\n \"SendReminder\": true,\n \"EmailBody\": \"Test av varsel\",\n \"EmailSubject\": \"Dette er innholdet i ett varsel\",\n \"SmsBody\": \"Dette er innholdet i ett testvarsel\",\n \"ReminderEmailBody\": \"Dette er test av revarsling \",\n \"ReminderEmailSubject\": \"Test av revarsel\",\n \"ReminderSmsBody\": \"Dette er en test av revarslingl\"\n },\n \"IgnoreReservation\": true\n },\n \"Recipients\": [\n \"0192:{{recipientOrgNo}}\"\n ],\n \"existingAttachments\": []\n}", + "raw": "{\n \"Correspondence\": {\n \"resourceId\": \"{{resource_id}}\",\n \"sender\": \"0192:{{senderOrgNo}}\",\n \"sendersReference\": \"1\",\n \"content\": {\n \"language\": \"nb\",\n \"messageTitle\": \"Meldingstittel\",\n \"messageSummary\": \"Ett sammendrag for meldingen\",\n \"messageBody\": \"# meldingsteksten. Som kan være plain text eller markdown \",\n \"attachments\": []\n },\n \"RequestedPublishTime\": \"2024-09-28T12:44:28.290518+00:00\",\n \"allowSystemDeleteAfter\": \"2025-08-29T13:31:28.290518+00:00\",\n \"dueDateTime\": \"2025-05-29T13:31:28.290518+00:00\",\n \"externalReferences\": [\n {\n \"referenceValue\": \"1\",\n \"referenceType\": \"AltinnBrokerFileTransfer\"\n }\n ],\n \"propertyList\": {\n \"deserunt_12\": \"1\",\n \"culpa_852\": \"2\",\n \"anim5\": \"3\",\n \"Æ*'1??` \": \"asdfgklasjd\"\n },\n \"replyOptions\": [\n {\n \"linkURL\": \"www.test.no\",\n \"linkText\": \"test\"\n },\n {\n \"linkURL\": \"test.no\",\n \"linkText\": \"test\"\n }\n ],\n \"notification\": {\n \"notificationTemplate\": 0,\n \"notificationChannel\": 3,\n \"SendReminder\": true,\n \"EmailBody\": \"Test av varsel\",\n \"EmailSubject\": \"Dette er innholdet i ett varsel\",\n \"SmsBody\": \"Dette er innholdet i ett testvarsel\",\n \"ReminderEmailBody\": \"Dette er test av revarsling \",\n \"ReminderEmailSubject\": \"Test av revarsel\",\n \"ReminderSmsBody\": \"Dette er en test av revarslingl\"\n },\n \"IgnoreReservation\": true,\n \"IsConfirmationNeeded\": false\n },\n \"Recipients\": [\n \"0192:{{recipientOrgNo}}\"\n ],\n \"existingAttachments\": []\n}", "options": { "raw": { "headerFamily": "json", @@ -1084,6 +1084,11 @@ "value": "true", "type": "text" }, + { + "key": "Correspondence.IsConfirmationNeeded", + "value": "false", + "type": "text" + }, { "key": "Attachments", "type": "file", diff --git a/src/Altinn.Correspondence.API/Mappers/CorrespondenceDetailsMapper.cs b/src/Altinn.Correspondence.API/Mappers/CorrespondenceDetailsMapper.cs index d7c45ce7..c3674831 100644 --- a/src/Altinn.Correspondence.API/Mappers/CorrespondenceDetailsMapper.cs +++ b/src/Altinn.Correspondence.API/Mappers/CorrespondenceDetailsMapper.cs @@ -31,7 +31,8 @@ internal static CorrespondenceDetailsExt MapToExternal(GetCorrespondenceDetailsR AllowSystemDeleteAfter = correspondenceDetails.AllowSystemDeleteAfter, DueDateTime = correspondenceDetails.DueDateTime, PropertyList = correspondenceDetails.PropertyList, - Published = correspondenceDetails.Published + Published = correspondenceDetails.Published, + IsConfirmationNeeded = correspondenceDetails.IsConfirmationNeeded, }; return Correspondence; } diff --git a/src/Altinn.Correspondence.API/Mappers/CorrespondenceOverviewMapper.cs b/src/Altinn.Correspondence.API/Mappers/CorrespondenceOverviewMapper.cs index cbb13e38..b1cc5b76 100644 --- a/src/Altinn.Correspondence.API/Mappers/CorrespondenceOverviewMapper.cs +++ b/src/Altinn.Correspondence.API/Mappers/CorrespondenceOverviewMapper.cs @@ -30,7 +30,8 @@ internal static CorrespondenceOverviewExt MapToExternal(GetCorrespondenceOvervie DueDateTime = correspondenceOverview.DueDateTime, PropertyList = correspondenceOverview.PropertyList, IgnoreReservation = correspondenceOverview.IgnoreReservation, - Published = correspondenceOverview.Published + Published = correspondenceOverview.Published, + IsConfirmationNeeded = correspondenceOverview.IsConfirmationNeeded, }; return Correspondence; } diff --git a/src/Altinn.Correspondence.API/Mappers/InitializeCorrespondencesMapper.cs b/src/Altinn.Correspondence.API/Mappers/InitializeCorrespondencesMapper.cs index 97988893..8c8e8e67 100644 --- a/src/Altinn.Correspondence.API/Mappers/InitializeCorrespondencesMapper.cs +++ b/src/Altinn.Correspondence.API/Mappers/InitializeCorrespondencesMapper.cs @@ -34,6 +34,7 @@ internal static InitializeCorrespondencesRequest MapToRequest(BaseCorrespondence attachment => InitializeCorrespondenceAttachmentMapper.MapToEntity(attachment, initializeCorrespondenceExt.ResourceId, initializeCorrespondenceExt.Sender) ).ToList() } : null, + IsConfirmationNeeded = initializeCorrespondenceExt.IsConfirmationNeeded }; return new InitializeCorrespondencesRequest() { diff --git a/src/Altinn.Correspondence.API/Mappers/MigrateCorrespondenceMapper.cs b/src/Altinn.Correspondence.API/Mappers/MigrateCorrespondenceMapper.cs index ceab8b5d..15989805 100644 --- a/src/Altinn.Correspondence.API/Mappers/MigrateCorrespondenceMapper.cs +++ b/src/Altinn.Correspondence.API/Mappers/MigrateCorrespondenceMapper.cs @@ -48,6 +48,7 @@ internal static MigrateCorrespondenceRequest MapToRequest(MigrateCorrespondenceE MessageBody = migrateCorrespondenceExt.CorrespondenceData.Correspondence.Content.MessageBody, Attachments = [] } : null, + IsConfirmationNeeded = migrateCorrespondenceExt.CorrespondenceData.Correspondence.IsConfirmationNeeded, }; return new MigrateCorrespondenceRequest() diff --git a/src/Altinn.Correspondence.API/Models/BaseCorrespondenceExt.cs b/src/Altinn.Correspondence.API/Models/BaseCorrespondenceExt.cs index 4cb79864..b15d895b 100644 --- a/src/Altinn.Correspondence.API/Models/BaseCorrespondenceExt.cs +++ b/src/Altinn.Correspondence.API/Models/BaseCorrespondenceExt.cs @@ -106,6 +106,12 @@ public class BaseCorrespondenceExt /// [JsonPropertyName("Published")] public DateTimeOffset? Published { get; set; } + + /// + /// Specifies whether reading the correspondence needs to be confirmed by the recipient + /// + [JsonPropertyName("IsConfirmationNeeded")] + public bool IsConfirmationNeeded { get; set; } } [AttributeUsage(AttributeTargets.Property)] diff --git a/src/Altinn.Correspondence.Application/CheckNotification/CheckNotificationHandler.cs b/src/Altinn.Correspondence.Application/CheckNotification/CheckNotificationHandler.cs index a1e1efa9..2cf77bdc 100644 --- a/src/Altinn.Correspondence.Application/CheckNotification/CheckNotificationHandler.cs +++ b/src/Altinn.Correspondence.Application/CheckNotification/CheckNotificationHandler.cs @@ -1,3 +1,4 @@ +using Altinn.Correspondence.Application.Helpers; using Altinn.Correspondence.Core.Models.Enums; using Altinn.Correspondence.Core.Repositories; using OneOf; @@ -24,7 +25,7 @@ public async Task> Process(Guid correspo response.SendNotification = false; return response; } - if (correspondence.Statuses.Any(s => s.Status == CorrespondenceStatus.Read)) + if (correspondence.StatusHasBeen(CorrespondenceStatus.Read)) { response.SendNotification = false; } diff --git a/src/Altinn.Correspondence.Application/CorrespondenceDueDate/CorrespondenceDueDateHandler.cs b/src/Altinn.Correspondence.Application/CorrespondenceDueDate/CorrespondenceDueDateHandler.cs index 1fe9c6cc..cb083fc1 100644 --- a/src/Altinn.Correspondence.Application/CorrespondenceDueDate/CorrespondenceDueDateHandler.cs +++ b/src/Altinn.Correspondence.Application/CorrespondenceDueDate/CorrespondenceDueDateHandler.cs @@ -1,3 +1,4 @@ +using Altinn.Correspondence.Application.Helpers; using Altinn.Correspondence.Core.Models.Entities; using Altinn.Correspondence.Core.Models.Enums; using Altinn.Correspondence.Core.Repositories; @@ -35,21 +36,21 @@ public async Task Process(Guid correspondenceId, CancellationToken cancellationT { throw new Exception("Correspondence " + correspondenceId + " not found for exipired due date"); } - else if (correspondence.Content == null || !correspondence.Statuses.Any(s => s.Status == CorrespondenceStatus.Published)) + else if (correspondence.Content == null || !correspondence.StatusHasBeen(CorrespondenceStatus.Published)) { throw new Exception($"Correspondence {correspondenceId} was never published"); } - else if (correspondence.Statuses.Any(s => s.Status == CorrespondenceStatus.Failed)) + else if (correspondence.StatusHasBeen(CorrespondenceStatus.Failed)) { throw new Exception($"Correspondence {correspondenceId} failed to publish"); } - if (!correspondence.Statuses.Any(s => s.Status != CorrespondenceStatus.Read)) + if (!correspondence.StatusHasBeen(CorrespondenceStatus.Read)) { await _eventBus.Publish(AltinnEventType.CorrespondenceReceiverNeverRead, correspondence.ResourceId, correspondence.Id.ToString(), "correspondence", correspondence.Sender, cancellationToken); await _eventBus.Publish(AltinnEventType.CorrespondenceReceiverNeverRead, correspondence.ResourceId, correspondence.Id.ToString(), "correspondence", correspondence.Recipient, cancellationToken); } - if (!correspondence.Statuses.Any(s => s.Status == CorrespondenceStatus.Confirmed)) // TODO: add logic to only check if confirmation is required + if (correspondence.IsConfirmationNeeded && !correspondence.StatusHasBeen(CorrespondenceStatus.Confirmed)) { await _eventBus.Publish(AltinnEventType.CorrespondenceReceiverNeverConfirmed, correspondence.ResourceId, correspondence.Id.ToString(), "correspondence", correspondence.Sender, cancellationToken); await _eventBus.Publish(AltinnEventType.CorrespondenceReceiverNeverConfirmed, correspondence.ResourceId, correspondence.Id.ToString(), "correspondence", correspondence.Recipient, cancellationToken); diff --git a/src/Altinn.Correspondence.Application/Errors.cs b/src/Altinn.Correspondence.Application/Errors.cs index c9356e25..e31f5849 100644 --- a/src/Altinn.Correspondence.Application/Errors.cs +++ b/src/Altinn.Correspondence.Application/Errors.cs @@ -46,4 +46,6 @@ public static class Errors public static Error MissingPrefferedReminderNotificationContent = new Error(38, $"Reminder email body, subject and SMS body must be provided when sending reminder preferred notifications", HttpStatusCode.BadRequest); public static Error AttachmentNotPublished = new Error(39, "Attachment is not published", HttpStatusCode.BadRequest); public static Error LegacyNotAccessToOwner(int partyId) { return new Error(40, $"User does not have access to party with partyId {partyId}", HttpStatusCode.Unauthorized); } + public static Error CorrespondenceNotConfirmed = new Error(41, "Cannot archive or delete a correspondence which has not been confirmed when confirmation is required", HttpStatusCode.BadRequest); + public static Error DueDateRequired = new Error(42, "DueDateTime is required when confirmation is needed", HttpStatusCode.BadRequest); } diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsHandler.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsHandler.cs index f953cc9a..86b53ca4 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsHandler.cs @@ -95,7 +95,8 @@ await _correspondenceStatusRepository.AddCorrespondenceStatus(new Correspondence AllowSystemDeleteAfter = correspondence.AllowSystemDeleteAfter, DueDateTime = correspondence.DueDateTime, PropertyList = correspondence.PropertyList, - Published = correspondence.Published + Published = correspondence.Published, + IsConfirmationNeeded = correspondence.IsConfirmationNeeded, }; return response; } diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsResponse.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsResponse.cs index 98f11b9b..17567eed 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsResponse.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceDetails/GetCorrespondenceDetailsResponse.cs @@ -49,4 +49,6 @@ public class GetCorrespondenceDetailsResponse public Dictionary PropertyList { get; set; } = new Dictionary(); public DateTimeOffset? Published { get; internal set; } + + public bool IsConfirmationNeeded { get; set; } } diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewHandler.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewHandler.cs index 05e11277..9668f4f6 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewHandler.cs @@ -94,7 +94,8 @@ await _correspondenceStatusRepository.AddCorrespondenceStatus(new Correspondence IgnoreReservation = correspondence.IgnoreReservation ?? false, MarkedUnread = correspondence.MarkedUnread, AllowSystemDeleteAfter = correspondence.AllowSystemDeleteAfter, - Published = correspondence.Published + Published = correspondence.Published, + IsConfirmationNeeded = correspondence.IsConfirmationNeeded, }; return response; } diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewResponse.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewResponse.cs index f821dad2..9063f125 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewResponse.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/GetCorrespondenceOverviewResponse.cs @@ -48,6 +48,8 @@ public class GetCorrespondenceOverviewResponse public Dictionary PropertyList { get; set; } = new Dictionary(); public DateTimeOffset? Published { get; set; } + + public bool IsConfirmationNeeded { get; set; } } public class CorrespondenceNotificationOverview { diff --git a/src/Altinn.Correspondence.Application/Helpers/AttachmentExtensions.cs b/src/Altinn.Correspondence.Application/Helpers/AttachmentExtensions.cs index ff336550..c3a0d124 100644 --- a/src/Altinn.Correspondence.Application/Helpers/AttachmentExtensions.cs +++ b/src/Altinn.Correspondence.Application/Helpers/AttachmentExtensions.cs @@ -1,4 +1,5 @@ using Altinn.Correspondence.Core.Models.Entities; +using Altinn.Correspondence.Core.Models.Enums; namespace Altinn.Correspondence.Application.Helpers; public static class AttachmentStatusExtensions { @@ -8,4 +9,8 @@ public static class AttachmentStatusExtensions .OrderByDescending(s => s.StatusChanged).FirstOrDefault(); return statusEntity; } + public static bool StatusHasBeen(this AttachmentEntity attachment, AttachmentStatus status) + { + return attachment.Statuses.Any(s => s.Status == status); + } } \ No newline at end of file diff --git a/src/Altinn.Correspondence.Application/Helpers/CorrespondenceExtensions.cs b/src/Altinn.Correspondence.Application/Helpers/CorrespondenceExtensions.cs index f5a20549..3170fcbb 100644 --- a/src/Altinn.Correspondence.Application/Helpers/CorrespondenceExtensions.cs +++ b/src/Altinn.Correspondence.Application/Helpers/CorrespondenceExtensions.cs @@ -45,5 +45,8 @@ public static bool IsPurgeableForSender(this CorrespondenceStatus correspondence ]; return validStatuses.Contains(correspondenceStatus); } - + public static bool StatusHasBeen(this CorrespondenceEntity correspondence, CorrespondenceStatus status) + { + return correspondence.Statuses.Any(s => s.Status == status); + } } \ No newline at end of file diff --git a/src/Altinn.Correspondence.Application/Helpers/InitializeCorrespondenceHelper.cs b/src/Altinn.Correspondence.Application/Helpers/InitializeCorrespondenceHelper.cs index 37271d86..07d7c2f8 100644 --- a/src/Altinn.Correspondence.Application/Helpers/InitializeCorrespondenceHelper.cs +++ b/src/Altinn.Correspondence.Application/Helpers/InitializeCorrespondenceHelper.cs @@ -136,7 +136,7 @@ public async Task> GetExistingAttachments(List atta public CorrespondenceStatus GetInitializeCorrespondenceStatus(CorrespondenceEntity correspondence) { var status = CorrespondenceStatus.Initialized; - if (correspondence.Content != null && correspondence.Content.Attachments.All(c => c.Attachment?.Statuses != null && c.Attachment.Statuses.Any(s => s.Status == AttachmentStatus.Published))) + if (correspondence.Content != null && correspondence.Content.Attachments.All(c => c.Attachment?.Statuses != null && c.Attachment.StatusHasBeen(AttachmentStatus.Published))) { if (_hostEnvironment.IsDevelopment() && correspondence.RequestedPublishTime < DateTimeOffset.UtcNow) status = CorrespondenceStatus.Published; // used to test on published correspondences in development else status = CorrespondenceStatus.ReadyForPublish; diff --git a/src/Altinn.Correspondence.Application/InitializeCorrespondences/InitializeCorrespondencesHandler.cs b/src/Altinn.Correspondence.Application/InitializeCorrespondences/InitializeCorrespondencesHandler.cs index 1c275eb1..897525e2 100644 --- a/src/Altinn.Correspondence.Application/InitializeCorrespondences/InitializeCorrespondencesHandler.cs +++ b/src/Altinn.Correspondence.Application/InitializeCorrespondences/InitializeCorrespondencesHandler.cs @@ -63,6 +63,10 @@ public async Task> Process(Initi { return Errors.DuplicateRecipients; } + if (request.Correspondence.IsConfirmationNeeded && request.Correspondence.DueDateTime is null) + { + return Errors.DueDateRequired; + } var dateError = _initializeCorrespondenceHelper.ValidateDateConstraints(request.Correspondence); if (dateError != null) { @@ -185,6 +189,7 @@ public async Task> Process(Initi Created = request.Correspondence.Created, ExternalReferences = request.Correspondence.ExternalReferences, Published = status == CorrespondenceStatus.Published ? DateTimeOffset.UtcNow : null, + IsConfirmationNeeded = request.Correspondence.IsConfirmationNeeded, }; correspondences.Add(correspondence); } diff --git a/src/Altinn.Correspondence.Application/MigrateCorrespondenceAttachment/MigrateUploadAttachmentHandler.cs b/src/Altinn.Correspondence.Application/MigrateCorrespondenceAttachment/MigrateUploadAttachmentHandler.cs index b5358013..ecb52c58 100644 --- a/src/Altinn.Correspondence.Application/MigrateCorrespondenceAttachment/MigrateUploadAttachmentHandler.cs +++ b/src/Altinn.Correspondence.Application/MigrateCorrespondenceAttachment/MigrateUploadAttachmentHandler.cs @@ -32,7 +32,7 @@ public async Task> Process(UploadAttachme { return Errors.InvalidFileSize; } - if (attachment.Statuses.Any(status => status.Status == AttachmentStatus.UploadProcessing)) + if (attachment.StatusHasBeen(AttachmentStatus.UploadProcessing)) { return Errors.InvalidUploadAttachmentStatus; } diff --git a/src/Altinn.Correspondence.Application/PurgeAttachment/PurgeAttachmentHandler.cs b/src/Altinn.Correspondence.Application/PurgeAttachment/PurgeAttachmentHandler.cs index 78260c85..1d2ce6fa 100644 --- a/src/Altinn.Correspondence.Application/PurgeAttachment/PurgeAttachmentHandler.cs +++ b/src/Altinn.Correspondence.Application/PurgeAttachment/PurgeAttachmentHandler.cs @@ -30,7 +30,7 @@ public async Task> Process(Guid attachmentId, CancellationTok { return Errors.NoAccessToResource; } - if (attachment.Statuses.Any(status => status.Status == AttachmentStatus.Purged)) + if (attachment.StatusHasBeen(AttachmentStatus.Purged)) { return Errors.InvalidPurgeAttachmentStatus; } diff --git a/src/Altinn.Correspondence.Application/PurgeCorrespondence/PurgeCorrespondenceHandler.cs b/src/Altinn.Correspondence.Application/PurgeCorrespondence/PurgeCorrespondenceHandler.cs index ee354fa2..54341ffd 100644 --- a/src/Altinn.Correspondence.Application/PurgeCorrespondence/PurgeCorrespondenceHandler.cs +++ b/src/Altinn.Correspondence.Application/PurgeCorrespondence/PurgeCorrespondenceHandler.cs @@ -87,6 +87,10 @@ public async Task> Process(Guid correspondenceId, Cancellatio { return Errors.CorrespondenceNotFound; } + if (correspondence.IsConfirmationNeeded && !correspondence.StatusHasBeen(CorrespondenceStatus.Confirmed)) + { + return Errors.CorrespondenceNotConfirmed; + } newStatus = new CorrespondenceStatusEntity() { CorrespondenceId = correspondenceId, @@ -110,7 +114,7 @@ public async Task CheckAndPurgeAttachments(Guid correspondenceId, CancellationTo foreach (var attachment in attachments) { var canBeDeleted = await _attachmentRepository.CanAttachmentBeDeleted(attachment.Id, cancellationToken); - if (!canBeDeleted || attachment.Statuses.Any(status => status.Status == AttachmentStatus.Purged)) + if (!canBeDeleted || attachment.StatusHasBeen(AttachmentStatus.Purged)) { continue; } diff --git a/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/UpdateCorrespondenceStatusHandler.cs b/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/UpdateCorrespondenceStatusHandler.cs index 260dee75..b5233fca 100644 --- a/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/UpdateCorrespondenceStatusHandler.cs +++ b/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/UpdateCorrespondenceStatusHandler.cs @@ -53,7 +53,7 @@ public async Task> Process(UpdateCorrespondenceStatusRequest { return Errors.LatestStatusIsNull; } - if ((request.Status == CorrespondenceStatus.Confirmed || request.Status == CorrespondenceStatus.Read) && !currentStatus!.Status.IsAvailableForRecipient()) + if (!currentStatus.Status.IsAvailableForRecipient()) { return Errors.CorrespondenceNotFound; } @@ -69,6 +69,10 @@ public async Task> Process(UpdateCorrespondenceStatusRequest { return request.CorrespondenceId; } + if (request.Status == CorrespondenceStatus.Archived && correspondence.IsConfirmationNeeded && !correspondence.StatusHasBeen(CorrespondenceStatus.Confirmed)) + { + return Errors.CorrespondenceNotConfirmed; + } await _correspondenceStatusRepository.AddCorrespondenceStatus(new CorrespondenceStatusEntity { diff --git a/src/Altinn.Correspondence.Application/UpdateMarkUnread/UpdateMarkAsUnreadHandler.cs b/src/Altinn.Correspondence.Application/UpdateMarkUnread/UpdateMarkAsUnreadHandler.cs index 1400e080..41b87956 100644 --- a/src/Altinn.Correspondence.Application/UpdateMarkUnread/UpdateMarkAsUnreadHandler.cs +++ b/src/Altinn.Correspondence.Application/UpdateMarkUnread/UpdateMarkAsUnreadHandler.cs @@ -34,7 +34,7 @@ public async Task> Process(Guid correspondenceId, Cancellatio } var currentStatus = correspondence.GetLatestStatus(); - if (!correspondence.Statuses.Any(s => s.Status == CorrespondenceStatus.Read)) + if (!correspondence.StatusHasBeen(CorrespondenceStatus.Read)) { return Errors.CorrespondenceHasNotBeenRead; } diff --git a/src/Altinn.Correspondence.Application/UploadAttachment/UploadAttachmentHandler.cs b/src/Altinn.Correspondence.Application/UploadAttachment/UploadAttachmentHandler.cs index 1138f584..a20a3623 100644 --- a/src/Altinn.Correspondence.Application/UploadAttachment/UploadAttachmentHandler.cs +++ b/src/Altinn.Correspondence.Application/UploadAttachment/UploadAttachmentHandler.cs @@ -31,7 +31,7 @@ public async Task> Process(UploadAttachme { return Errors.InvalidFileSize; } - if (attachment.Statuses.Any(status => status.Status == AttachmentStatus.UploadProcessing)) + if (attachment.StatusHasBeen(AttachmentStatus.UploadProcessing)) { return Errors.InvalidUploadAttachmentStatus; } diff --git a/src/Altinn.Correspondence.Core/Models/Entities/CorrespondenceEntity.cs b/src/Altinn.Correspondence.Core/Models/Entities/CorrespondenceEntity.cs index ccecd4de..da7010b3 100644 --- a/src/Altinn.Correspondence.Core/Models/Entities/CorrespondenceEntity.cs +++ b/src/Altinn.Correspondence.Core/Models/Entities/CorrespondenceEntity.cs @@ -55,5 +55,7 @@ public class CorrespondenceEntity public int? Altinn2CorrespondenceId { get; set; } public DateTimeOffset? Published { get; set; } + + public bool IsConfirmationNeeded { get; set; } } } \ No newline at end of file diff --git a/src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.Designer.cs b/src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.Designer.cs new file mode 100644 index 00000000..a9e374d2 --- /dev/null +++ b/src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.Designer.cs @@ -0,0 +1,510 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Altinn.Correspondence.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20241024103535_AddedIsConfirmationNeeded")] + partial class AddedIsConfirmationNeeded + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("correspondence") + .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.AttachmentEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Checksum") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("DataLocationType") + .HasColumnType("integer"); + + b.Property("DataLocationUrl") + .HasColumnType("text"); + + b.Property("DataType") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsEncrypted") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RestrictionName") + .HasColumnType("text"); + + b.Property("Sender") + .IsRequired() + .HasColumnType("text"); + + b.Property("SendersReference") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)"); + + b.HasKey("Id"); + + b.ToTable("Attachments", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.AttachmentStatusEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttachmentId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("StatusChanged") + .HasColumnType("timestamp with time zone"); + + b.Property("StatusText") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AttachmentId"); + + b.ToTable("AttachmentStatuses", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceAttachmentEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttachmentId") + .HasColumnType("uuid"); + + b.Property("CorrespondenceContentId") + .HasColumnType("uuid"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpirationTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AttachmentId"); + + b.HasIndex("CorrespondenceContentId"); + + b.ToTable("CorrespondenceAttachments", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceContentEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CorrespondenceId") + .HasColumnType("uuid"); + + b.Property("Language") + .IsRequired() + .HasColumnType("text"); + + b.Property("MessageBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("MessageSummary") + .IsRequired() + .HasColumnType("text"); + + b.Property("MessageTitle") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CorrespondenceId") + .IsUnique(); + + b.ToTable("CorrespondenceContents", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowSystemDeleteAfter") + .HasColumnType("timestamp with time zone"); + + b.Property("Altinn2CorrespondenceId") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("DueDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IgnoreReservation") + .HasColumnType("boolean"); + + b.Property("IsConfirmationNeeded") + .HasColumnType("boolean"); + + b.Property("MarkedUnread") + .HasColumnType("boolean"); + + b.Property("MessageSender") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property>("PropertyList") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("hstore"); + + b.Property("Published") + .HasColumnType("timestamp with time zone"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequestedPublishTime") + .HasColumnType("timestamp with time zone"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Sender") + .IsRequired() + .HasColumnType("text"); + + b.Property("SendersReference") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)"); + + b.HasKey("Id"); + + b.ToTable("Correspondences", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceNotificationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Altinn2NotificationId") + .HasColumnType("integer"); + + b.Property("CorrespondenceId") + .HasColumnType("uuid"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("IsReminder") + .HasColumnType("boolean"); + + b.Property("NotificationAddress") + .HasColumnType("text"); + + b.Property("NotificationChannel") + .HasColumnType("integer"); + + b.Property("NotificationOrderId") + .HasColumnType("uuid"); + + b.Property("NotificationSent") + .HasColumnType("timestamp with time zone"); + + b.Property("NotificationTemplate") + .HasColumnType("integer"); + + b.Property("RequestedSendTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CorrespondenceId"); + + b.ToTable("CorrespondenceNotifications", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceReplyOptionEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CorrespondenceId") + .HasColumnType("uuid"); + + b.Property("LinkText") + .HasColumnType("text"); + + b.Property("LinkURL") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CorrespondenceId"); + + b.ToTable("CorrespondenceReplyOptions", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceStatusEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CorrespondenceId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("StatusChanged") + .HasColumnType("timestamp with time zone"); + + b.Property("StatusText") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CorrespondenceId"); + + b.ToTable("CorrespondenceStatuses", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.ExternalReferenceEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CorrespondenceId") + .HasColumnType("uuid"); + + b.Property("ReferenceType") + .HasColumnType("integer"); + + b.Property("ReferenceValue") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CorrespondenceId"); + + b.ToTable("ExternalReferences", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.NotificationTemplateEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EmailBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("EmailSubject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Language") + .HasColumnType("text"); + + b.Property("RecipientType") + .HasColumnType("integer"); + + b.Property("ReminderEmailBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReminderEmailSubject") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReminderSmsBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("SmsBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("Template") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("NotificationTemplates", "correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.AttachmentStatusEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.AttachmentEntity", "Attachment") + .WithMany("Statuses") + .HasForeignKey("AttachmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Attachment"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceAttachmentEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.AttachmentEntity", "Attachment") + .WithMany("CorrespondenceAttachments") + .HasForeignKey("AttachmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Altinn.Correspondence.Core.Models.Entities.CorrespondenceContentEntity", "CorrespondenceContent") + .WithMany("Attachments") + .HasForeignKey("CorrespondenceContentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Attachment"); + + b.Navigation("CorrespondenceContent"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceContentEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", "Correspondence") + .WithOne("Content") + .HasForeignKey("Altinn.Correspondence.Core.Models.Entities.CorrespondenceContentEntity", "CorrespondenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceNotificationEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", "Correspondence") + .WithMany("Notifications") + .HasForeignKey("CorrespondenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceReplyOptionEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", "Correspondence") + .WithMany("ReplyOptions") + .HasForeignKey("CorrespondenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceStatusEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", "Correspondence") + .WithMany("Statuses") + .HasForeignKey("CorrespondenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.ExternalReferenceEntity", b => + { + b.HasOne("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", "Correspondence") + .WithMany("ExternalReferences") + .HasForeignKey("CorrespondenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Correspondence"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.AttachmentEntity", b => + { + b.Navigation("CorrespondenceAttachments"); + + b.Navigation("Statuses"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceContentEntity", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Altinn.Correspondence.Core.Models.Entities.CorrespondenceEntity", b => + { + b.Navigation("Content"); + + b.Navigation("ExternalReferences"); + + b.Navigation("Notifications"); + + b.Navigation("ReplyOptions"); + + b.Navigation("Statuses"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.cs b/src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.cs new file mode 100644 index 00000000..d7eb0f1f --- /dev/null +++ b/src/Altinn.Correspondence.Persistence/Migrations/20241024103535_AddedIsConfirmationNeeded.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Altinn.Correspondence.Persistence.Migrations +{ + /// + public partial class AddedIsConfirmationNeeded : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsConfirmationNeeded", + schema: "correspondence", + table: "Correspondences", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsConfirmationNeeded", + schema: "correspondence", + table: "Correspondences"); + } + } +} diff --git a/src/Altinn.Correspondence.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Altinn.Correspondence.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs index 5041cb1e..d5c59840 100644 --- a/src/Altinn.Correspondence.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Altinn.Correspondence.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs @@ -187,6 +187,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("IgnoreReservation") .HasColumnType("boolean"); + b.Property("IsConfirmationNeeded") + .HasColumnType("boolean"); + b.Property("MarkedUnread") .HasColumnType("boolean");