From 56c204167f461ec145c1da17e2882da8a02d5640 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Thu, 6 Mar 2025 15:39:28 +0100 Subject: [PATCH 1/7] OZG-4097 send-attachment: Fix sending attachments --- .../nachrichten/postfach/osiv2/model/FileChunkInfo.java | 6 ++++++ .../nachrichten/postfach/osiv2/model/Osi2Attachment.java | 2 +- .../postfach/osiv2/transfer/Osi2ResponseMapper.java | 2 +- src/main/resources/application-stage.yml | 2 +- .../osiv2/extension/AttachmentExampleUploadUtil.java | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/FileChunkInfo.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/FileChunkInfo.java index a119cba..f63abe3 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/FileChunkInfo.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/FileChunkInfo.java @@ -16,6 +16,12 @@ public record FileChunkInfo( ) { public AbstractResource createUploadResource(InputStream fileInputStream) { return new AbstractResource() { + + @Override + public String getFilename() { + return upload.file().getName(); + } + @Override public String getDescription() { return "File chunk " + chunkIndex + " of " + upload.getLoggableString(); diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Attachment.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Attachment.java index dc41ec7..a948a1a 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Attachment.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Attachment.java @@ -10,7 +10,7 @@ public record Osi2Attachment( String guid, OzgCloudFile file ) { - public static final long CHUNK_SIZE = 100L * (2L << 10); + public static final long CHUNK_SIZE = (2L << 14); public static Osi2Attachment from(OzgCloudFile file) { return Osi2Attachment.builder() diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java index 74a34e0..1dda33f 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java @@ -113,7 +113,7 @@ public interface Osi2ResponseMapper { } default void checkChunkUploadSuccess(QuarantineFileResult quarantineFileResult) { - if (!Boolean.TRUE.equals(quarantineFileResult.getSuccess())) { + if (!Optional.ofNullable(quarantineFileResult.getError()).map(String::isBlank).orElse(true)) { throw new Osi2RuntimeException( "Chunk-Upload of file %s failed: %s".formatted(quarantineFileResult.getFileUid(), quarantineFileResult.getError()), null); } diff --git a/src/main/resources/application-stage.yml b/src/main/resources/application-stage.yml index 2618fc5..e69cb9d 100644 --- a/src/main/resources/application-stage.yml +++ b/src/main/resources/application-stage.yml @@ -2,7 +2,7 @@ ozgcloud: osiv2: enabled: false auth: - client-id: 'OZG-Kopfstelle' + client-id: 'OZG-Kopfstelle-SH' client-secret: 'changeme' scope: default, access_urn:dataport:osi:sh:stage:ozgkopfstelle token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/AttachmentExampleUploadUtil.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/AttachmentExampleUploadUtil.java index 8aa5491..97cc84d 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/AttachmentExampleUploadUtil.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/AttachmentExampleUploadUtil.java @@ -12,7 +12,7 @@ import lombok.extern.log4j.Log4j2; @Log4j2 public class AttachmentExampleUploadUtil { - public static final byte[] EXAMPLE_TEXT_DATA = LoremIpsum.getInstance().getParagraphs(5,100).getBytes(); + public static final byte[] EXAMPLE_TEXT_DATA = LoremIpsum.getInstance().getParagraphs(5,10).getBytes(); public static String uploadTextFile(Osi2AttachmentFileService remoteService) { -- GitLab From 8e31650225e6fbba34d6ddbb5bac1cf2ddbd9895 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Thu, 6 Mar 2025 15:40:08 +0100 Subject: [PATCH 2/7] OZG-4097 readme: Add sequence diagrams for send and receive --- README.md | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e2d81a..e985ee9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,105 @@ # OSIv2-Postfach-Anbindung für OZG-Cloud-Nachrichten -Anbindung des OSIv2-Postfachs für die OZG-Cloud. +Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 (OPF). +## Senden einer Postfach-Nachricht +```mermaid +%% Senden einer Nachricht + sequenceDiagram + participant N as nachrichten-manager + participant A as file-manager + participant B as Client + participant C as OPF + activate A + activate C + activate B + activate N + N->>B: OsiPostfachRemoteService::sendMessage + Note left of B: (1) Hochladen der Anhänge + B->>A: GRPC findBinaryFilesMetaData + A-->>B: {Liste an Anhang-Metadaten} + loop Für jeden Anhang + B->>A: GRPC GetBinaryFileContent + loop Für jeden Daten-Chunk + B->>C: POST /Quarantine/v1/Upload/Chunked (chunk) + C-->>B: + end + A-->>B: + B->>C: POST /Quarantine/v1/Upload/Chunked (empty chunk) + C-->>B: + end + deactivate A + Note left of B: (2) Warten auf Prüfung der hochgeladenen Anhänge + loop Regelmäßiges Polling bis alle Anhänge geprüft sind + loop Für alle Anhänge + B->>C: GET /Quarantine/v1/Upload/{guid} + C-->>B: + end + end + Note left of B: (3) Nachricht senden + B->>C: POST /MessageExchange/v1/Send/{mailboxId} + C-->>B: + deactivate C + B-->>N: + deactivate B + deactivate N +``` + +## Empfangen von Postfach-Nachrichten + +```mermaid +%% Empfangen einer Nachricht + sequenceDiagram + participant N as nachrichten-manager + participant A as file-manager + participant B as Client + participant C as OPF + activate A + activate C + activate B + activate N + N->>B: OsiPostfachRemoteService::receiveMessages + B->>C: GET /MessageExchange/v1/Receive + C-->>B: {Liste an Nachrichten-Kennungen (max 100)} + loop Für jede Nachrichten-Kennung (messageId) + Note left of B: (1) Nachricht abrufen + B->>C: GET /MessageExchange/v1/Receive/{messageId} + C-->>B: {Nachricht mit Anhang-Metadaten} + Note left of B: (2) Herunterladen der Anhänge + loop Für jeden Anhang + B->>C: GET /MessageExchange/v1/Receive/{messageId}/Attachment/{attachmentId} + B->>A: GRPC UploadBinaryFileAsStream + A-->>B: + C-->>B: + end + end + deactivate A + deactivate C + B->>N: {Stream an Postfach-Nachrichten} + deactivate B + deactivate N +``` + +Der nachrichten-manager erhält von osiv2-postfach einen Stream von Postfach-Nachrichten. Nach der erfolgreichen Verarbeitung einer Nachricht sollte er `OsiPostfachRemoteService::deleteMessage` aufrufen: + +```mermaid +%% Empfangen einer Nachricht + sequenceDiagram + participant N as nachrichten-manager + participant B as Client + participant C as OPF + activate C + activate B + activate N + N->>B: OsiPostfachRemoteService::deleteMessage + B->>C: GET /MessageExchange/v1/Delete/{messageId} + C->>B: + deactivate C + B-->>N: + deactivate B + deactivate N +``` ## Client-Authentifizierung beim Servicekonto -- GitLab From deeb21cb869d1cfc83600551cd9d2c836eff752c Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 7 Mar 2025 13:12:04 +0100 Subject: [PATCH 3/7] OZG-4097 send: Lookup mailboxId by nameId --- spec/postfach-api-facade.yaml | 1 + .../osiv2/config/ApiClientConfiguration.java | 6 + .../osiv2/exception/Osi2ExceptionHandler.java | 4 +- .../Osi2MailboxNotFoundException.java | 7 + .../postfach/osiv2/model/Osi2Message.java | 3 +- .../osiv2/transfer/Osi2MessageMapper.java | 67 ++++- .../osiv2/transfer/Osi2PostfachService.java | 9 +- .../osiv2/transfer/Osi2RequestMapper.java | 54 +--- .../osiv2/transfer/Osi2ResponseMapper.java | 53 ++-- .../transfer/PostfachApiFacadeService.java | 17 +- .../osiv2/OsiPostfachRemoteServiceITCase.java | 20 ++ .../Osi2PersistAttachmentServiceTest.java | 1 - .../exception/Osi2ExceptionHandlerTest.java | 17 ++ .../factory/Osi2AttachmentTestFactory.java | 21 ++ .../osiv2/factory/Osi2MessageTestFactory.java | 10 +- .../factory/PostfachAddressTestFactory.java | 4 +- .../factory/PostfachNachrichtTestFactory.java | 9 +- ...esMailboxDirectoryResponseTestFactory.java | 56 ++++ .../osiv2/transfer/Osi2MessageMapperTest.java | 241 +++++++++++++++++- .../transfer/Osi2PostfachServiceTest.java | 92 ++++++- .../osiv2/transfer/Osi2RequestMapperTest.java | 101 ++------ .../transfer/Osi2ResponseMapperTest.java | 70 ++++- .../PostfachApiFacadeServiceTest.java | 104 ++++++-- 23 files changed, 766 insertions(+), 201 deletions(-) create mode 100644 src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2MailboxNotFoundException.java create mode 100644 src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2AttachmentTestFactory.java create mode 100644 src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/ResponsesMailboxDirectoryResponseTestFactory.java diff --git a/spec/postfach-api-facade.yaml b/spec/postfach-api-facade.yaml index 9a67d1c..d494dbb 100644 --- a/spec/postfach-api-facade.yaml +++ b/spec/postfach-api-facade.yaml @@ -756,6 +756,7 @@ paths: detail: Der Dienst ist zurzeit nicht verfügbar. /MailboxDirectory/v1/Lookup: post: + operationId: lookupMailboxIds tags: - MailboxDirectory summary: Liefert eine Liste der zu NameIdentifiern gehörenden OSI-Postfächer diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index 6b28b57..50496ca 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; import de.ozgcloud.nachrichten.postfach.osiv2.gen.ApiClient; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MailboxDirectoryApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.QuarantineApi; import lombok.RequiredArgsConstructor; @@ -57,6 +58,11 @@ public class ApiClientConfiguration { return new QuarantineApi(apiClient); } + @Bean + MailboxDirectoryApi mailboxDirectoryApi(ApiClient apiClient) { + return new MailboxDirectoryApi(apiClient); + } + @Bean @SneakyThrows ApiClient apiClient() { diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java index 395f427..f7e42d6 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java @@ -19,6 +19,9 @@ public class Osi2ExceptionHandler { if (exception instanceof ResourceAccessException) { return PostfachMessageCode.SERVER_CONNECTION_FAILED_MESSAGE_CODE; } + if (exception instanceof Osi2MailboxNotFoundException) { + return PostfachMessageCode.SEND_FAILED_UNKNOWN_POSTFACH_ID_MESSAGE_CODE; + } return PostfachMessageCode.PROCESS_FAILED_MESSAGE_CODE; } @@ -33,5 +36,4 @@ public class Osi2ExceptionHandler { return restClientResponseException.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(404)); } - } diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2MailboxNotFoundException.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2MailboxNotFoundException.java new file mode 100644 index 0000000..5a44f27 --- /dev/null +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2MailboxNotFoundException.java @@ -0,0 +1,7 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.exception; + +public class Osi2MailboxNotFoundException extends Osi2RuntimeException { + public Osi2MailboxNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Message.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Message.java index f527fce..ecda0e2 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Message.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/model/Osi2Message.java @@ -3,14 +3,13 @@ package de.ozgcloud.nachrichten.postfach.osiv2.model; import java.time.ZonedDateTime; import java.util.List; -import de.ozgcloud.nachrichten.postfach.PostfachAddress; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import lombok.Builder; @Builder public record Osi2Message( String vorgangId, - PostfachAddress postfachAddress, + String mailboxId, String messageId, ZonedDateTime createdAt, String subject, diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapper.java index 7d81f6f..006fe52 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapper.java @@ -1,16 +1,31 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.Named; import org.mapstruct.ReportingPolicy; +import de.ozgcloud.nachrichten.postfach.PostfachAddress; +import de.ozgcloud.nachrichten.postfach.PostfachAddressIdentifier; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.StringBasedIdentifier; +import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachRemoteService; +import de.ozgcloud.nachrichten.postfach.osiv2.model.AttachmentInfo; +import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; @Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR) public interface Osi2MessageMapper { + String POSTFACH_ADDRESS_VERSION = "2.0"; + int POSTFACH_ADDRESS_TYPE = 2; + @Mapping(target = "id", ignore = true) @Mapping(target = "referencedNachricht", ignore = true) @@ -20,7 +35,57 @@ public interface Osi2MessageMapper { @Mapping(target = "sentSuccessful", ignore = true) @Mapping(target = "messageCode", ignore = true) + @Mapping(target = "postfachAddress", source = "osi2Message.mailboxId", qualifiedByName = "createPostfachAddressByMailboxId") @Mapping(target = "attachments", source = "attachmentIds") @Mapping(target = "direction", constant = "IN") - PostfachNachricht toPostfachNachricht(Osi2Message osi2Message, List<String> attachmentIds); + PostfachNachricht mapPostfachNachricht(Osi2Message osi2Message, List<String> attachmentIds); + + @Named("createPostfachAddressByMailboxId") + default PostfachAddress createPostfachAddressByMailboxId(String mailBoxId) { + return PostfachAddress.builder() + .type(POSTFACH_ADDRESS_TYPE) + .version(POSTFACH_ADDRESS_VERSION) + .identifier(StringBasedIdentifier.builder() + // Note: this should be a nameIdentifier for sending but is a mailboxGuid/messageBox. + // Thus, the PostfachAddress in this mapped response can not be used for sending + .postfachId(mailBoxId) + .build()) + .serviceKontoType(OsiPostfachRemoteService.POSTFACH_TYPE_OSI) + .build(); + + } + + default String getNameIdentifier(PostfachNachricht nachricht) { + return Optional.ofNullable(nachricht.getPostfachAddress()) + .map(PostfachAddress::getIdentifier) + .map(PostfachAddressIdentifier::getStringRepresentation) + .orElseThrow(() -> new IllegalArgumentException("Missing nameIdentifier!")); + } + + @Mapping(target = "mailboxId", source = "mailboxId") + @Mapping(target = "attachments", expression = "java( mapAttachmentInfosInOriginalOrder(nachricht, uploadAttachments) )") + Osi2Message mapOsi2Message(PostfachNachricht nachricht, String mailboxId, List<Osi2Attachment> uploadAttachments); + + default List<AttachmentInfo> mapAttachmentInfosInOriginalOrder(PostfachNachricht nachricht, List<Osi2Attachment> files) { + var filesById = associateUploadWithAttachmentId(files); + return nachricht.getAttachments() + .stream() + .map(fileId -> Objects.requireNonNull( + filesById.get(fileId), + "Expect all attachmentIds are uploaded!" + )) + .map(this::mapAttachmentInfo) + .toList(); + } + + @Mapping(target = "contentType", source = "file.contentType") + @Mapping(target = "name", source = "file.name") + @Mapping(target = "size", source = "file.size") + AttachmentInfo mapAttachmentInfo(Osi2Attachment file); + + default Map<String, Osi2Attachment> associateUploadWithAttachmentId(List<Osi2Attachment> uploads) { + return uploads.stream() + .filter(upload -> upload.file() != null && upload.file().getId() != null) + .collect(Collectors.toMap(upload -> upload.file().getId().toString(), Function.identity())); + } } diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachService.java index 754a945..dc08ac2 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachService.java @@ -19,8 +19,11 @@ public class Osi2PostfachService { public void sendMessage(PostfachNachricht nachricht) { postfachApiFacadeService.sendMessage( - nachricht, - quarantineService.uploadAttachments(nachricht.getAttachments()) + messageMapper.mapOsi2Message( + nachricht, + postfachApiFacadeService.lookupMailboxId(messageMapper.getNameIdentifier(nachricht)), + quarantineService.uploadAttachments(nachricht.getAttachments()) + ) ); } @@ -32,7 +35,7 @@ public class Osi2PostfachService { PostfachNachricht fetchPostfachNachricht(String messageGuid) { var message = postfachApiFacadeService.fetchMessageById(messageGuid); - return messageMapper.toPostfachNachricht( + return messageMapper.mapPostfachNachricht( message, persistAttachmentService.persistAttachments(message) ); diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java index 86aa86d..de83be9 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java @@ -2,67 +2,43 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.Named; import org.mapstruct.ReportingPolicy; -import de.ozgcloud.nachrichten.postfach.PostfachAddress; -import de.ozgcloud.nachrichten.postfach.PostfachAddressIdentifier; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.DomainChunkMetaData; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeFiles; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.OutSendMessageRequestV2; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1References; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; +import de.ozgcloud.nachrichten.postfach.osiv2.model.AttachmentInfo; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; -import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; +import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; @Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR) public interface Osi2RequestMapper { int MAX_NUMBER_RECEIVED_MESSAGES = 100; - @Mapping(target = "sequencenumber", source = "nachricht.vorgangId") - @Mapping(target = "body", source = "nachricht.mailBody") + @Mapping(target = "sequencenumber", source = "vorgangId") + @Mapping(target = "body", source = "mailBody") @Mapping(target = "displayName", ignore = true) @Mapping(target = "originSender", ignore = true) - @Mapping(target = "replyAction", source = "nachricht.replyOption") + @Mapping(target = "replyAction", source = "replyOption") @Mapping(target = "eidasLevel", constant = "LOW") @Mapping(target = "isObligatory", expression = "java( false )") @Mapping(target = "isHtml", expression = "java( false )") - @Mapping(target = "files", expression = "java( mapMessageExchangeFiles(nachricht, files) )") + @Mapping(target = "files", source = "attachments", qualifiedByName = "mapMessageExchangeFile") @Mapping(target = "references", expression = "java( mapReferences() )") - OutSendMessageRequestV2 mapOutSendMessageRequestV2(PostfachNachricht nachricht, List<Osi2Attachment> files); + OutSendMessageRequestV2 mapOutSendMessageRequestV2(Osi2Message message); - default List<MessageExchangeFiles> mapMessageExchangeFiles(PostfachNachricht nachricht, List<Osi2Attachment> files) { - var filesById = associateUploadWithAttachmentId(files); - return nachricht.getAttachments() - .stream() - .map(fileId -> Objects.requireNonNull( - filesById.get(fileId), - "Expect all attachmentIds are uploaded!" - )) - .map(this::mapMessageExchangeFile) - .toList(); - } - - default Map<String, Osi2Attachment> associateUploadWithAttachmentId(List<Osi2Attachment> uploads) { - return uploads.stream() - .filter(upload -> upload.file() != null && upload.file().getId() != null) - .collect(Collectors.toMap(upload -> upload.file().getId().toString(), Function.identity())); - } - - @Mapping(target = "mimeType", source = "file.contentType") - @Mapping(target = "name", source = "file.name") - @Mapping(target = "size", source = "file.size") + @Mapping(target = "mimeType", source = "contentType") @Mapping(target = "isOriginalMessage", expression = "java( false )") - MessageExchangeFiles mapMessageExchangeFile(Osi2Attachment fileUpload); + @Named("mapMessageExchangeFile") + MessageExchangeFiles mapMessageExchangeFile(AttachmentInfo fileUpload); default List<V1References> mapReferences() { return Collections.emptyList(); @@ -83,12 +59,4 @@ public interface Osi2RequestMapper { @Mapping(target = "totalChunks", expression = "java( (int) fileChunkInfo.upload().numberOfChunks() )") @Mapping(target = "totalFileSize", source = "upload.file.size") DomainChunkMetaData mapDomainChunkMetaData(FileChunkInfo fileChunkInfo); - - default String mapMailboxId(PostfachNachricht nachricht) { - return Optional.ofNullable(nachricht.getPostfachAddress()) - .map(PostfachAddress::getIdentifier) - .map(PostfachAddressIdentifier::getStringRepresentation) - .orElseThrow(() -> new IllegalArgumentException("Missing MailboxId!")); - } - } diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java index 1dda33f..a1ab4aa 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java @@ -7,23 +7,26 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; +import java.util.stream.Stream; + +import jakarta.validation.constraints.NotNull; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Named; import org.mapstruct.ReportingPolicy; -import de.ozgcloud.nachrichten.postfach.PostfachAddress; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; -import de.ozgcloud.nachrichten.postfach.StringBasedIdentifier; -import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachRemoteService; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2MailboxNotFoundException; import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2UploadException; -import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveAttachment; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.DTOMailboxScopeData; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MddiMailboxIndexData; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineFileResult; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.ResponsesMailboxDirectoryResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyFiles; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; @@ -33,11 +36,8 @@ import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; @Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR, imports = { Osi2HtmlDocument.class }) public interface Osi2ResponseMapper { - String POSTFACH_ADDRESS_VERSION = "2.0"; - int POSTFACH_ADDRESS_TYPE = 2; - @Mapping(target = "vorgangId", source = "sequencenumber") - @Mapping(target = "postfachAddress", source = "messageBox") + @Mapping(target = "mailboxId", source = "messageBox") @Mapping(target = "messageId", source = "guid") @Mapping(target = "createdAt", source = "responseTime", qualifiedByName = "mapOffsetDateTimeToZoned") @Mapping(target = "subject", source = "subject") @@ -66,20 +66,6 @@ public interface Osi2ResponseMapper { : body; } - default PostfachAddress buildPostfachAddressByPostfachId(UUID messageBox) { - return messageBox == null - ? null - : PostfachAddress.builder() - .type(POSTFACH_ADDRESS_TYPE) - .version(POSTFACH_ADDRESS_VERSION) - .identifier(StringBasedIdentifier.builder() - .postfachId(messageBox.toString()) - .build()) - .serviceKontoType(OsiPostfachRemoteService.POSTFACH_TYPE_OSI) - .build(); - - } - default PostfachNachricht.ReplyOption mapReplyAction(V1ReplyBehavior replyOption) { return replyOption == null ? PostfachNachricht.ReplyOption.FORBIDDEN @@ -119,12 +105,23 @@ public interface Osi2ResponseMapper { } } - @Named("mapMessageExchangeReceiveAttachment") - default String mapMessageExchangeReceiveAttachment(MessageExchangeReceiveAttachment attachment) { - return Optional.ofNullable(attachment) - .map(MessageExchangeReceiveAttachment::getGuid) - .map(UUID::toString) - .orElse(null); + default Optional<String> extractMailboxIdByTenantOrFirst(@NotNull List<MddiMailboxIndexData> mailBoxes, String tenant) { + return mailBoxes.stream() + .filter(mailbox -> tenant.equals(mailbox.getTenant())) + .findFirst() + .or(() -> mailBoxes.stream().findFirst()) + .map(MddiMailboxIndexData::getMailboxguid) + .map(UUID::toString); } + default String getMailboxIdByTenantOrFirst(ResponsesMailboxDirectoryResponse responsesMailboxDirectoryResponse, String tenant) { + return Optional.ofNullable(responsesMailboxDirectoryResponse) + .map(ResponsesMailboxDirectoryResponse::getMailBoxIndex) + .map(Collection::stream) + .flatMap(Stream::findFirst) + .map(DTOMailboxScopeData::getMemberscope) + .flatMap(mailBoxes -> extractMailboxIdByTenantOrFirst(mailBoxes, tenant)) + .orElseThrow(() -> new Osi2MailboxNotFoundException("Empty mailbox lookup response! %s".formatted( + responsesMailboxDirectoryResponse != null ? responsesMailboxDirectoryResponse.toString() : "(response null)"))); + } } diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index 989ae00..65010e5 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -8,14 +8,13 @@ import java.util.UUID; import org.springframework.core.io.AbstractResource; import org.springframework.core.io.Resource; -import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.ServiceIfOsi2Enabled; import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2UploadException; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MailboxDirectoryApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.QuarantineApi; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; -import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -27,14 +26,15 @@ public class PostfachApiFacadeService { private final MessageExchangeApi messageExchangeApi; private final QuarantineApi quarantineApi; + private final MailboxDirectoryApi mailboxDirectoryApi; private final Osi2RequestMapper requestMapper; private final Osi2ResponseMapper responseMapper; private final Osi2PostfachProperties.ApiConfiguration apiConfiguration; - public void sendMessage(PostfachNachricht nachricht, List<Osi2Attachment> attachments) { + public void sendMessage(Osi2Message message) { messageExchangeApi.sendMessage( - requestMapper.mapMailboxId(nachricht), - requestMapper.mapOutSendMessageRequestV2(nachricht, attachments) + message.mailboxId(), + requestMapper.mapOutSendMessageRequestV2(message) ); } @@ -75,4 +75,11 @@ public class PostfachApiFacadeService { public Resource downloadAttachment(String messageGuid, String attachmentGuid) { return messageExchangeApi.getMessageAttachment(UUID.fromString(messageGuid), UUID.fromString(attachmentGuid)); } + + public String lookupMailboxId(String nameIdentifier) { + return responseMapper.getMailboxIdByTenantOrFirst( + mailboxDirectoryApi.lookupMailboxIds(List.of(UUID.fromString(nameIdentifier))), + apiConfiguration.getTenant() + ); + } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index 550d15b..51dd44b 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -35,6 +35,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.factory.JsonUtil; import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeSendMessageResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.ResponsesMailboxDirectoryResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyFilesTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineFileResult; @@ -83,6 +84,7 @@ class OsiPostfachRemoteServiceITCase { @SneakyThrows void shouldSendRequestWithJwt() { var postfachNachricht = PostfachNachrichtTestFactory.create(); + mockLookupResponse(); mockSendResponse(); osiPostfachRemoteService.sendMessage(postfachNachricht); @@ -110,6 +112,7 @@ class OsiPostfachRemoteServiceITCase { var postfachNachrichtWithAttachment = PostfachNachrichtTestFactory.createBuilder() .attachments(List.of(textFileId)) .build(); + mockLookupResponse(); mockSendResponse(); osiPostfachRemoteService.sendMessage(postfachNachrichtWithAttachment); @@ -130,6 +133,10 @@ class OsiPostfachRemoteServiceITCase { exactly(1), postRequestedFor(urlPathTemplate("/MessageExchange/v1/Send/{mailboxId}")) ); + postfachFacadeMockServer.verify( + exactly(1), + postRequestedFor(urlPathTemplate("/MailboxDirectory/v1/Lookup")) + ); } @DisplayName("should throw postfach exception with connection error code") @@ -173,6 +180,7 @@ class OsiPostfachRemoteServiceITCase { var postfachNachrichtWithAttachment = PostfachNachrichtTestFactory.createBuilder() .attachments(List.of(textFileId)) .build(); + mockLookupResponse(); try { osiPostfachRemoteService.sendMessage(postfachNachrichtWithAttachment); @@ -204,6 +212,7 @@ class OsiPostfachRemoteServiceITCase { var postfachNachrichtWithAttachment = PostfachNachrichtTestFactory.createBuilder() .attachments(List.of(textFileId)) .build(); + mockLookupResponse(); try { osiPostfachRemoteService.sendMessage(postfachNachrichtWithAttachment); @@ -217,6 +226,17 @@ class OsiPostfachRemoteServiceITCase { ); } + private void mockLookupResponse() { + // Stub mailboxids lookup response (MessageExchangeApi::lookupMailboxIds) + postfachFacadeMockServer.stubFor(post(urlPathTemplate("/MailboxDirectory/v1/Lookup")) + .willReturn( + okJsonObj( + ResponsesMailboxDirectoryResponseTestFactory.create() + ) + ) + ); + } + private void mockSendResponse() { // Stub message send response (MessageExchangeApi::sendMessage) postfachFacadeMockServer.stubFor(post(urlPathTemplate("/MessageExchange/v1/Send/{mailboxId}")) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/attachment/Osi2PersistAttachmentServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/attachment/Osi2PersistAttachmentServiceTest.java index 2fcf400..92b590f 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/attachment/Osi2PersistAttachmentServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/attachment/Osi2PersistAttachmentServiceTest.java @@ -3,7 +3,6 @@ package de.ozgcloud.nachrichten.postfach.osiv2.attachment; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.GrpcOzgFileTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory.*; -import static de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java index df51704..986571b 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java @@ -11,6 +11,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.springframework.http.HttpStatusCode; +import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestClientResponseException; class Osi2ExceptionHandlerTest { @@ -36,6 +37,22 @@ class Osi2ExceptionHandlerTest { assertThat(result).isEqualTo(SERVER_CONNECTION_FAILED_MESSAGE_CODE); } + @DisplayName("should return connection failed message code") + @Test + void shouldReturnConnectionFailedMessageCode() { + var result = handler.deriveMessageCode(new ResourceAccessException("")); + + assertThat(result).isEqualTo(SERVER_CONNECTION_FAILED_MESSAGE_CODE); + } + + @DisplayName("should return unknown postfach id message code") + @Test + void shouldReturnUnknownPostfachIdMessageCode() { + var result = handler.deriveMessageCode(new Osi2MailboxNotFoundException("")); + + assertThat(result).isEqualTo(SEND_FAILED_UNKNOWN_POSTFACH_ID_MESSAGE_CODE); + } + @DisplayName("should return processed failed error code by default") @Test void shouldReturnProcessedFailedErrorCodeByDefault() { diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2AttachmentTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2AttachmentTestFactory.java new file mode 100644 index 0000000..662d3d3 --- /dev/null +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2AttachmentTestFactory.java @@ -0,0 +1,21 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.factory; + +import java.util.UUID; + +import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; + +public class Osi2AttachmentTestFactory { + public static final String ATTACHMENT_GUID = UUID.randomUUID().toString(); + public static final String ATTACHMENT_GUID_2 = UUID.randomUUID().toString(); + + public static Osi2Attachment create() { + return createBuilder().build(); + } + + public static Osi2Attachment.Osi2AttachmentBuilder createBuilder() { + return Osi2Attachment.builder() + .guid(ATTACHMENT_GUID) + .file(OzgCloudFileTestFactory.create()); + } +} diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2MessageTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2MessageTestFactory.java index 8d40f11..b609152 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2MessageTestFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/Osi2MessageTestFactory.java @@ -1,29 +1,31 @@ package de.ozgcloud.nachrichten.postfach.osiv2.factory; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory.*; -import static de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory.*; import java.time.ZonedDateTime; import java.util.List; +import java.util.UUID; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; public class Osi2MessageTestFactory { + public static final String MAILBOX_ID = UUID.randomUUID().toString(); + public static Osi2Message create() { return createBuilder().build(); } public static Osi2Message.Osi2MessageBuilder createBuilder() { return Osi2Message.builder() + .vorgangId(VORGANG_ID) + .mailboxId(MAILBOX_ID) .messageId(MESSAGE_ID) .mailBody(MAIL_BODY) .subject(MAIL_SUBJECT) .replyOption(PostfachNachricht.ReplyOption.FORBIDDEN) .createdAt(ZonedDateTime.now()) - .vorgangId(VORGANG_ID) - .attachments(List.of()) - .postfachAddress(PostfachAddressTestFactory.create()); + .attachments(List.of()); } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java index de986e0..415054d 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java @@ -7,7 +7,7 @@ import de.ozgcloud.nachrichten.postfach.StringBasedIdentifier; public class PostfachAddressTestFactory { - public static final String MAILBOX_ID = UUID.randomUUID().toString(); + public static final String NAME_IDENTIFIER = UUID.randomUUID().toString(); public static final String SERVICE_KONTO_TYPE = "TYPE1"; public static PostfachAddress create() { @@ -19,7 +19,7 @@ public class PostfachAddressTestFactory { .type(1) .serviceKontoType(SERVICE_KONTO_TYPE) .identifier(StringBasedIdentifier.builder() - .postfachId(MAILBOX_ID) + .postfachId(NAME_IDENTIFIER) .build()); } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachNachrichtTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachNachrichtTestFactory.java index aaf929e..3424251 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachNachrichtTestFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachNachrichtTestFactory.java @@ -12,7 +12,9 @@ public class PostfachNachrichtTestFactory { public static final String MAIL_SUBJECT = "AW: " + LoremIpsum.getInstance().getTitle(2, 6); public static final String VORGANG_ID = "test-vorgang-id"; public static final String USER_ID = "test-user-id"; - + public static final String MESSAGE_ID = UUID.randomUUID().toString(); + public static final ZonedDateTime CREATED_AT = ZonedDateTime.now(); + public static final PostfachNachricht.ReplyOption REPLY_OPTION = PostfachNachricht.ReplyOption.FORBIDDEN; public static PostfachNachricht create() { return createBuilder().build(); @@ -22,8 +24,9 @@ public class PostfachNachrichtTestFactory { return PostfachNachricht.builder() .mailBody(MAIL_BODY) .subject(MAIL_SUBJECT) - .replyOption(PostfachNachricht.ReplyOption.FORBIDDEN) - .createdAt(ZonedDateTime.now()) + .messageId(MESSAGE_ID) + .replyOption(REPLY_OPTION) + .createdAt(CREATED_AT) .createdBy(USER_ID) .vorgangId(VORGANG_ID) .postfachAddress(PostfachAddressTestFactory.create()); diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/ResponsesMailboxDirectoryResponseTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/ResponsesMailboxDirectoryResponseTestFactory.java new file mode 100644 index 0000000..9681f8d --- /dev/null +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/ResponsesMailboxDirectoryResponseTestFactory.java @@ -0,0 +1,56 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.factory; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.DTOMailboxScopeData; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MddiMailboxIndexData; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MddiMailboxType; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.ResponsesMailboxDirectoryResponse; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1Meta; + +public class ResponsesMailboxDirectoryResponseTestFactory { + + public static final String NAME_ID = UUID.randomUUID().toString(); + public static final String MAILBOX_GUID_SH = UUID.randomUUID().toString(); + public static final String MAILBOX_GUID_HH = UUID.randomUUID().toString(); + public static final String TENANT_SH = "SH"; + public static final String TENANT_HH = "HH"; + + public static ResponsesMailboxDirectoryResponse create() { + return createBuilder( + buildMailboxWithSHTenant().build(), + buildMailboxWithHHTenant().build() + ).build(); + } + + public static ResponsesMailboxDirectoryResponse.Builder createBuilder(MddiMailboxIndexData... mailBoxes) { + return ResponsesMailboxDirectoryResponse.builder() + .mailBoxIndex(List.of(createScopeData(mailBoxes))) + .meta(V1Meta.builder().build()); + } + + public static MddiMailboxIndexData.Builder buildMailboxWithSHTenant() { + return MddiMailboxIndexData.builder() + .mailboxguid(UUID.fromString(MAILBOX_GUID_SH)) + .tenant(TENANT_SH) + .mailboxname("") + .mailboxdescription("") + .mailboxtype(MddiMailboxType.PERSONAL); + } + + public static MddiMailboxIndexData.Builder buildMailboxWithHHTenant() { + return MddiMailboxIndexData.builder() + .mailboxguid(UUID.fromString(MAILBOX_GUID_HH)) + .tenant(TENANT_HH) + .mailboxtype(MddiMailboxType.PERSONAL); + } + + private static DTOMailboxScopeData createScopeData(MddiMailboxIndexData... mailBoxes) { + return DTOMailboxScopeData.builder() + .membershipcontext(UUID.fromString(NAME_ID)) + .memberscope(Arrays.asList(mailBoxes)) + .build(); + } +} diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapperTest.java index 89d64ba..31584b2 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2MessageMapperTest.java @@ -1,27 +1,45 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; +import static de.ozgcloud.apilib.file.OzgCloudFileTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2AttachmentTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory.*; -import static java.util.Collections.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.transfer.Osi2MessageMapper.*; import static org.assertj.core.api.Assertions.*; import java.util.List; +import java.util.UUID; +import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mapstruct.factory.Mappers; +import de.ozgcloud.apilib.file.OzgCloudFileId; +import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; +import de.ozgcloud.nachrichten.postfach.PostfachAddress; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachRemoteService; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2AttachmentTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.model.AttachmentInfo; +import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; class Osi2MessageMapperTest { private final Osi2MessageMapper mapper = Mappers.getMapper(Osi2MessageMapper.class); - @DisplayName("to PostfachNachricht") + @DisplayName("map PostfachNachricht") @Nested - class TestToPostfachNachricht { + class TestMapPostfachNachricht { private final Osi2Message osi2Message = Osi2MessageTestFactory.create(); private final String attachmentId1 = "attachmentId1"; private final String attachmentId2 = "attachmentId2"; @@ -71,7 +89,9 @@ class Osi2MessageMapperTest { void shouldMapPostfachAddress() { var result = doMapping(); - assertThat(result.getPostfachAddress()).isEqualTo(osi2Message.postfachAddress()); + assertThat(result.getPostfachAddress()).usingRecursiveComparison().isEqualTo( + mapper.createPostfachAddressByMailboxId(osi2Message.mailboxId()) + ); } @DisplayName("should map direction") @@ -91,7 +111,218 @@ class Osi2MessageMapperTest { } private PostfachNachricht doMapping() { - return mapper.toPostfachNachricht(osi2Message, List.of(attachmentId1, attachmentId2)); + return mapper.mapPostfachNachricht(osi2Message, List.of(attachmentId1, attachmentId2)); + } + } + + @DisplayName("create postfach address by mailboxId") + @Nested + class TestCreatePostfachAddressByMailboxId { + + @DisplayName("should map postfach address type") + @Test + void shouldMapPostfachAddressType() { + var result = doMapping(); + + assertThat(result.getType()).isEqualTo(POSTFACH_ADDRESS_TYPE); + } + + @DisplayName("should map version") + @Test + void shouldMapVersion() { + var result = doMapping(); + + assertThat(result.getVersion()).isEqualTo(POSTFACH_ADDRESS_VERSION); + } + + @DisplayName("should map postfachId") + @Test + void shouldMapPostfachId() { + var result = doMapping(); + + assertThat(result.getIdentifier().getStringRepresentation()).isEqualTo(MAILBOX_ID); + } + + @DisplayName("should map servicekontotype") + @Test + void shouldMapServicekontotype() { + var result = doMapping(); + + assertThat(result.getServiceKontoType()).isEqualTo(OsiPostfachRemoteService.POSTFACH_TYPE_OSI); + } + + private PostfachAddress doMapping() { + return mapper.createPostfachAddressByMailboxId(MAILBOX_ID); + } + } + + @DisplayName("map osi2 message") + @Nested + class TestMapOsi2Message { + + private static final String FILE_ID2 = UUID.randomUUID().toString(); + private final Osi2Attachment attachment1 = Osi2AttachmentTestFactory.createBuilder() + .build(); + private final Osi2Attachment attachment2 = Osi2AttachmentTestFactory.createBuilder() + .guid(ATTACHMENT_GUID_2) + .file(OzgCloudFileTestFactory.createBuilder() + .id(OzgCloudFileId.from(FILE_ID2)) + .build()) + .build(); + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.createBuilder() + .attachments(List.of(ID_STR, FILE_ID2)) + .build(); + + @DisplayName("should map vorgangId") + @Test + void shouldMapVorgangId() { + var result = doMapping(); + + assertThat(result.vorgangId()).isEqualTo(VORGANG_ID); + } + + @DisplayName("should map mailboxId") + @Test + void shouldMapMailboxId() { + var result = doMapping(); + + assertThat(result.mailboxId()).isEqualTo(MAILBOX_ID); + } + + @DisplayName("should map messsageId") + @Test + void shouldMapMesssageId() { + var result = doMapping(); + + assertThat(result.messageId()).isEqualTo(MESSAGE_ID); + } + + @DisplayName("should map createdAt") + @Test + void shouldMapCreatedAt() { + var result = doMapping(); + + assertThat(result.createdAt()).isEqualTo(CREATED_AT); + } + + @DisplayName("should map subject") + @Test + void shouldMapSubject() { + var result = doMapping(); + + assertThat(result.subject()).isEqualTo(MAIL_SUBJECT); + } + + @DisplayName("should map mailBody") + @Test + void shouldMapMailBody() { + var result = doMapping(); + + assertThat(result.mailBody()).isEqualTo(MAIL_BODY); + } + + @DisplayName("should map replyOption") + @Test + void shouldMapReplyOption() { + var result = doMapping(); + + assertThat(result.replyOption()).isEqualTo(REPLY_OPTION); + } + + @DisplayName("should map attachments") + @Test + void shouldMapAttachments() { + var result = doMapping(); + + assertThat(result.attachments()).containsExactly( + mapper.mapAttachmentInfo(attachment1), + mapper.mapAttachmentInfo(attachment2) + ); + } + + private Osi2Message doMapping() { + return mapper.mapOsi2Message( + nachricht, + MAILBOX_ID, + List.of(attachment2, attachment1) + ); + } + } + + @DisplayName("map attachment info") + @Nested + class TestMapAttachmentInfo { + + private final Osi2Attachment attachment = Osi2AttachmentTestFactory.create(); + + @DisplayName("should map guid") + @Test + void shouldMapGuid() { + var result = doMapping(); + + assertThat(result.guid()).isEqualTo(ATTACHMENT_GUID); + } + + @DisplayName("should map name") + @Test + void shouldMapName() { + var result = doMapping(); + + assertThat(result.name()).isEqualTo(OzgCloudFileTestFactory.NAME); + } + + @DisplayName("should map contentType") + @Test + void shouldMapContentType() { + var result = doMapping(); + + assertThat(result.contentType()).isEqualTo(OzgCloudFileTestFactory.CONTENT_TYPE); + } + + @DisplayName("should map size") + @Test + void shouldMapSize() { + var result = doMapping(); + + assertThat(result.size()).isEqualTo(OzgCloudFileTestFactory.SIZE); + } + + private AttachmentInfo doMapping() { + return mapper.mapAttachmentInfo(attachment); + } + } + + @DisplayName("get nameIdentifier") + @Nested + class TestGetNameIdentifier { + + @DisplayName("should map postfach address to nameIdentifier") + @Test + void shouldMapPostfachAddressToNameIdentifier() { + var result = mapper.getNameIdentifier(PostfachNachrichtTestFactory.create()); + + assertThat(result).isEqualTo(NAME_IDENTIFIER); + } + + @DisplayName("should throw on missing postfach address") + @ParameterizedTest + @MethodSource("badPostfachAddresses") + void shouldThrowOnMissingPostfachAddress(PostfachAddress badPostfachAddress) { + var nachrichtWithBadPostfachAddress = PostfachNachrichtTestFactory.createBuilder() + .postfachAddress(badPostfachAddress) + .build(); + + assertThatThrownBy(() -> mapper.getNameIdentifier(nachrichtWithBadPostfachAddress)) + .isInstanceOf(IllegalArgumentException.class); + } + + static Stream<Arguments> badPostfachAddresses() { + return Stream.of( + null, + Arguments.of(PostfachAddressTestFactory.createBuilder() + .identifier(null) + .build()) + ); } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachServiceTest.java index 7077d02..8f19f2c 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2PostfachServiceTest.java @@ -1,6 +1,10 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; +import static de.ozgcloud.apilib.file.OzgCloudFileTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -16,9 +20,12 @@ import org.mockito.Mock; import org.mockito.Spy; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.attachment.Osi2PersistAttachmentService; import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; +import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; class Osi2PostfachServiceTest { @@ -30,33 +37,65 @@ class Osi2PostfachServiceTest { private PostfachApiFacadeService postfachApiFacadeService; @Mock private Osi2QuarantineService quarantineService; + @Mock + private Osi2PersistAttachmentService persistAttachmentService; + @Mock + private Osi2MessageMapper messageMapper; @DisplayName("send message") @Nested class TestSendOsi2Message { private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + private final Osi2Message osi2Message = Osi2MessageTestFactory.create(); private final List<Osi2Attachment> uploadFiles = List.of(Osi2FileUploadTestFactory.create()); @BeforeEach void mock() { + when(messageMapper.getNameIdentifier(any())).thenReturn(NAME_IDENTIFIER); + when(messageMapper.mapOsi2Message(any(), any(), any())).thenReturn(osi2Message); when(quarantineService.uploadAttachments(any())).thenReturn(uploadFiles); + when(postfachApiFacadeService.lookupMailboxId(any())).thenReturn(MAILBOX_ID); + } + + @DisplayName("should call getNameIdentifier") + @Test + void shouldCallGetNameIdentifier() { + service.sendMessage(nachricht); + + verify(messageMapper).getNameIdentifier(nachricht); + } + + @DisplayName("should call lookupMailboxId") + @Test + void shouldCallLookupMailboxId() { + service.sendMessage(nachricht); + + verify(postfachApiFacadeService).lookupMailboxId(NAME_IDENTIFIER); } - @DisplayName("should send message") + @DisplayName("should call mapOsi2Message") @Test - void shouldSendMessage() { + void shouldCallMapOsi2Message() { service.sendMessage(nachricht); - verify(postfachApiFacadeService).sendMessage(nachricht, uploadFiles); + verify(messageMapper).mapOsi2Message(nachricht, MAILBOX_ID, uploadFiles); } - @DisplayName("should upload attachments of nachricht") + @DisplayName("should call uploadAttachments") @Test - void shouldUploadAttachmentsOfNachricht() { + void shouldCallUploadAttachments() { service.sendMessage(nachricht); verify(quarantineService).uploadAttachments(nachricht.getAttachments()); } + + @DisplayName("should call sendMessage") + @Test + void shouldCallSendMessage() { + service.sendMessage(nachricht); + + verify(postfachApiFacadeService).sendMessage(osi2Message); + } } @DisplayName("receive messages") @@ -93,4 +132,47 @@ class Osi2PostfachServiceTest { } } + @DisplayName("fetch PostfachNachricht") + @Nested + class TestFetchPostfachNachricht { + + private final Osi2Message message = Osi2MessageTestFactory.create(); + private final PostfachNachricht postfachNachricht = PostfachNachrichtTestFactory.create(); + + @BeforeEach + void mock() { + when(postfachApiFacadeService.fetchMessageById(any())).thenReturn(message); + when(messageMapper.mapPostfachNachricht(any(), any())).thenReturn(postfachNachricht); + when(persistAttachmentService.persistAttachments(any())).thenReturn(List.of(ID_STR)); + } + + @DisplayName("should call fetchMessageById") + @Test + void shouldCallFetchMessageById() { + fetchPostfachNachricht(); + + verify(postfachApiFacadeService).fetchMessageById(MESSAGE_ID); + } + + @DisplayName("should call mapPostfachNachricht") + @Test + void shouldCallMapPostfachNachricht() { + fetchPostfachNachricht(); + + verify(messageMapper).mapPostfachNachricht(message, List.of(ID_STR)); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var result = fetchPostfachNachricht(); + + assertThat(result).isEqualTo(postfachNachricht); + } + + private PostfachNachricht fetchPostfachNachricht() { + return service.fetchPostfachNachricht(MESSAGE_ID); + } + } + } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java index bdf27c7..b6cda51 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java @@ -1,80 +1,46 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory.*; -import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory.*; -import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import java.util.List; import java.util.UUID; -import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import org.mapstruct.factory.Mappers; -import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; -import de.ozgcloud.nachrichten.postfach.PostfachAddress; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.AttachmentInfoTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.FileChunkInfoTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.DomainChunkMetaData; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeFiles; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.OutSendMessageRequestV2; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1EidasLevel; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1FilestorageTarget; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; +import de.ozgcloud.nachrichten.postfach.osiv2.model.AttachmentInfo; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; +import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; class Osi2RequestMapperTest { private final Osi2RequestMapper mapper = Mappers.getMapper(Osi2RequestMapper.class); - @DisplayName("map mailbox id") - @Nested - class TestMapMailboxId { - - @DisplayName("should map postfach address to mailbox id") - @Test - void shouldMapPostfachAddressToMailboxId() { - var result = mapper.mapMailboxId(PostfachNachrichtTestFactory.create()); - - assertThat(result).isEqualTo(MAILBOX_ID); - } - - @DisplayName("should throw on missing postfach address") - @ParameterizedTest - @MethodSource("badPostfachAddresses") - void shouldThrowOnMissingPostfachAddress(PostfachAddress badPostfachAddress) { - var nachrichtWithBadPostfachAddress = PostfachNachrichtTestFactory.createBuilder() - .postfachAddress(badPostfachAddress) - .build(); - - assertThatThrownBy(() -> mapper.mapMailboxId(nachrichtWithBadPostfachAddress)) - .isInstanceOf(IllegalArgumentException.class); - } - - static Stream<Arguments> badPostfachAddresses() { - return Stream.of( - null, - Arguments.of(PostfachAddressTestFactory.createBuilder() - .identifier(null) - .build()) - ); - } - } - @DisplayName("map OutSendMessageRequestV2") @Nested class TestMapOutSendOsi2MessageRequestV2 { + private final Osi2Message osi2Message = Osi2MessageTestFactory.create(); + + private final AttachmentInfo attachment1 = AttachmentInfoTestFactory.create(); + private final AttachmentInfo attachment2 = AttachmentInfoTestFactory.createBuilder() + .guid(UPLOAD_GUID2) + .build(); + @DisplayName("should map sequence number") @Test void shouldMapSequenceNumber() { @@ -118,11 +84,11 @@ class Osi2RequestMapperTest { @DisplayName("should map possible reply action") @Test void shouldMapPossibleReplyAction() { - var nachricht = PostfachNachrichtTestFactory.createBuilder() + var message = Osi2MessageTestFactory.createBuilder() .replyOption(PostfachNachricht.ReplyOption.POSSIBLE) .build(); - var result = mapper.mapOutSendMessageRequestV2(nachricht, emptyList()); + var result = mapper.mapOutSendMessageRequestV2(message); assertThat(result.getReplyAction()).isEqualTo(V1ReplyBehavior.REPLYPOSSIBLE); } @@ -130,11 +96,11 @@ class Osi2RequestMapperTest { @DisplayName("should map mandatory reply action") @Test void shouldMapMandatoryReplyAction() { - var nachricht = PostfachNachrichtTestFactory.createBuilder() + var message = Osi2MessageTestFactory.createBuilder() .replyOption(PostfachNachricht.ReplyOption.MANDATORY) .build(); - var result = mapper.mapOutSendMessageRequestV2(nachricht, emptyList()); + var result = mapper.mapOutSendMessageRequestV2(message); assertThat(result.getReplyAction()).isEqualTo(V1ReplyBehavior.REPLYMANDATORY); } @@ -171,36 +137,19 @@ class Osi2RequestMapperTest { assertThat(result.getFiles()).isEmpty(); } - @DisplayName("should map two files") + @DisplayName("should map files") @Test - void shouldMapTwoFiles() { - var files = List.of( - Osi2FileUploadTestFactory.create(), - Osi2FileUploadTestFactory.createBuilder() - .file(OzgCloudFileTestFactory.create()) - .guid(UPLOAD_GUID2) - .build() - ); - var nachricht = PostfachNachrichtTestFactory.createBuilder() - .attachments(List.of(UPLOAD_FILE_ID, OzgCloudFileTestFactory.ID_STR)) + void shouldMapFiles() { + var message = Osi2MessageTestFactory.createBuilder() + .attachments(List.of(attachment1, attachment2)) .build(); - var result = mapper.mapOutSendMessageRequestV2(nachricht, files); + var result = mapper.mapOutSendMessageRequestV2(message); - assertThat(result.getFiles()) - .usingRecursiveComparison() - .isEqualTo(files.stream().map(mapper::mapMessageExchangeFile).toList()); - } - - @DisplayName("should map files") - @Test - void shouldMapFiles() { - var result = mapper.mapOutSendMessageRequestV2( - PostfachNachrichtTestFactory.create(), - List.of(Osi2FileUploadTestFactory.create()) + assertThat(result.getFiles()).containsExactly( + mapper.mapMessageExchangeFile(attachment1), + mapper.mapMessageExchangeFile(attachment2) ); - - assertThat(result.getFiles()).isEmpty(); } @DisplayName("should map references") @@ -212,7 +161,7 @@ class Osi2RequestMapperTest { } private OutSendMessageRequestV2 doMapping() { - return mapper.mapOutSendMessageRequestV2(PostfachNachrichtTestFactory.create(), emptyList()); + return mapper.mapOutSendMessageRequestV2(osi2Message); } } @@ -252,7 +201,7 @@ class Osi2RequestMapperTest { } private MessageExchangeFiles mapFile() { - return mapper.mapMessageExchangeFile(Osi2FileUploadTestFactory.create()); + return mapper.mapMessageExchangeFile(AttachmentInfoTestFactory.create()); } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java index ff5a336..154bf87 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java @@ -5,6 +5,7 @@ import static de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyFilesTestFac import static de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory.*; import static org.assertj.core.api.Assertions.*; +import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; @@ -18,13 +19,16 @@ import org.mapstruct.factory.Mappers; import org.mockito.InjectMocks; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2MailboxNotFoundException; import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2UploadException; import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.QuarantineFileResultTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.ResponsesMailboxDirectoryResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyFilesTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.ResponsesMailboxDirectoryResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyFiles; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; @@ -53,8 +57,7 @@ class Osi2ResponseMapperTest { void shouldMapPostfachAddress() { var result = doMapping(); - assertThat(result.postfachAddress().getIdentifier()) - .hasToString(MESSAGE_BOX_ID); + assertThat(result.mailboxId()).isEqualTo(MESSAGE_BOX_ID); } @Test @@ -295,4 +298,67 @@ class Osi2ResponseMapperTest { .hasMessageContaining(Osi2FileUploadTestFactory.UPLOAD_GUID); } } + + @DisplayName("get mailboxId by tenant or first") + @Nested + class TestGetMailboxIdByTenantOrFirst { + + private final ResponsesMailboxDirectoryResponse response = ResponsesMailboxDirectoryResponseTestFactory.create(); + + @DisplayName("should throw with null response") + @Test + void shouldThrowWithNullResponse() { + + assertThatThrownBy(() -> mapper.getMailboxIdByTenantOrFirst(null, "")) + .isInstanceOf(Osi2MailboxNotFoundException.class); + } + + @DisplayName("should throw with missing index") + @Test + void shouldThrowWithMissingIndex() { + var responseWithoutMailboxIds = ResponsesMailboxDirectoryResponseTestFactory.createBuilder() + .mailBoxIndex(List.of()) + .build(); + + assertThatThrownBy( + () -> mapper.getMailboxIdByTenantOrFirst(responseWithoutMailboxIds, ResponsesMailboxDirectoryResponseTestFactory.TENANT_SH)) + .isInstanceOf(Osi2MailboxNotFoundException.class); + } + + @DisplayName("should throw with missing mailboxes") + @Test + void shouldThrowWithMissingMailboxes() { + var responseWithoutMailboxIds = ResponsesMailboxDirectoryResponseTestFactory.createBuilder() + .build(); + + assertThatThrownBy( + () -> mapper.getMailboxIdByTenantOrFirst(responseWithoutMailboxIds, ResponsesMailboxDirectoryResponseTestFactory.TENANT_SH)) + .isInstanceOf(Osi2MailboxNotFoundException.class); + } + + @DisplayName("should return mailboxId for SH") + @Test + void shouldReturnMailboxIdForSH() { + var result = mapper.getMailboxIdByTenantOrFirst(response, ResponsesMailboxDirectoryResponseTestFactory.TENANT_SH); + + assertThat(result).isEqualTo(ResponsesMailboxDirectoryResponseTestFactory.MAILBOX_GUID_SH); + } + + @DisplayName("should return mailboxId for HH") + @Test + void shouldReturnMailboxIdForHh() { + var result = mapper.getMailboxIdByTenantOrFirst(response, ResponsesMailboxDirectoryResponseTestFactory.TENANT_HH); + + assertThat(result).isEqualTo(ResponsesMailboxDirectoryResponseTestFactory.MAILBOX_GUID_HH); + } + + @DisplayName("should return first mailboxId for unknown tenant") + @Test + void shouldReturnFirstMailboxIdForUnknownTenant() { + var result = mapper.getMailboxIdByTenantOrFirst(response, "unknown"); + + assertThat(result).isEqualTo(ResponsesMailboxDirectoryResponseTestFactory.MAILBOX_GUID_SH); + } + + } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java index 0e6e97f..eafc3e2 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java @@ -1,7 +1,10 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.ResponsesMailboxDirectoryResponseTestFactory.*; import static de.ozgcloud.nachrichten.postfach.osiv2.transfer.Osi2RequestMapper.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -18,14 +21,13 @@ import org.mockito.Mock; import org.mockito.Spy; import org.springframework.core.io.AbstractResource; -import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; import de.ozgcloud.nachrichten.postfach.osiv2.factory.FileChunkInfoTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2FileUploadTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.Osi2MessageTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.ResponsesMailboxDirectoryResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MailboxDirectoryApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.QuarantineApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.DomainChunkMetaData; @@ -34,9 +36,9 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMe import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeSendMessageResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.OutSendMessageRequestV2; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.ResponsesMailboxDirectoryResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; -import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Attachment; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2Message; import lombok.SneakyThrows; @@ -52,6 +54,9 @@ class PostfachApiFacadeServiceTest { @Mock QuarantineApi quarantineApi; + @Mock + MailboxDirectoryApi mailboxDirectoryApi; + @Mock Osi2RequestMapper osi2RequestMapper; @@ -71,37 +76,26 @@ class PostfachApiFacadeServiceTest { @Mock MessageExchangeSendMessageResponse messageExchangeSendMessageResponse; - private final List<Osi2Attachment> files = List.of(Osi2FileUploadTestFactory.create()); - - private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + private final Osi2Message message = Osi2MessageTestFactory.create(); @BeforeEach void mock() { - when(osi2RequestMapper.mapMailboxId(any())).thenReturn(MAILBOX_ID); - when(osi2RequestMapper.mapOutSendMessageRequestV2(any(), any())).thenReturn(outSendMessageRequestV2); + when(osi2RequestMapper.mapOutSendMessageRequestV2(any())).thenReturn(outSendMessageRequestV2); when(messageExchangeApi.sendMessage(any(), any())).thenReturn(messageExchangeSendMessageResponse); } - @DisplayName("should call mapMailboxId") - @Test - void shouldCallMapMailboxId() { - service.sendMessage(nachricht, files); - - verify(osi2RequestMapper).mapMailboxId(nachricht); - } - @DisplayName("should call mapOutSendMessageRequestV2") @Test void shouldCallMapOutSendMessageRequestV2() { - service.sendMessage(nachricht, files); + service.sendMessage(message); - verify(osi2RequestMapper).mapOutSendMessageRequestV2(nachricht, files); + verify(osi2RequestMapper).mapOutSendMessageRequestV2(message); } @DisplayName("should call sendMessage") @Test void shouldCallSendMessage() { - service.sendMessage(nachricht, files); + service.sendMessage(message); verify(messageExchangeApi).sendMessage(MAILBOX_ID, outSendMessageRequestV2); } @@ -323,4 +317,74 @@ class PostfachApiFacadeServiceTest { } } + @DisplayName("download attachment") + @Nested + class TestDownloadAttachment { + @Mock + AbstractResource resource; + + @BeforeEach + void mock() { + when(messageExchangeApi.getMessageAttachment(any(), any())).thenReturn(resource); + } + + @DisplayName("should call getMessageAttachment") + @Test + void shouldCallGetMessageAttachment() { + service.downloadAttachment(MESSAGE_ID_1, UPLOAD_GUID); + + verify(messageExchangeApi).getMessageAttachment(UUID.fromString(MESSAGE_ID_1), UUID.fromString(UPLOAD_GUID)); + } + + @DisplayName("should return resource") + @Test + void shouldReturnResource() { + var result = service.downloadAttachment(MESSAGE_ID_1, UPLOAD_GUID); + + assertThat(result).isEqualTo(resource); + } + } + + @DisplayName("lookup mailboxId") + @Nested + class TestLookupMailboxId { + + private final ResponsesMailboxDirectoryResponse response = ResponsesMailboxDirectoryResponseTestFactory.create(); + + @BeforeEach + void mock() { + when(osi2ResponseMapper.getMailboxIdByTenantOrFirst(any(), any())).thenReturn(MAILBOX_ID); + when(mailboxDirectoryApi.lookupMailboxIds(any())).thenReturn(response); + when(apiConfiguration.getTenant()).thenReturn(TENANT_SH); + } + + @DisplayName("should call lookupMailboxIds") + @Test + void shouldCallLookupMailboxIds() { + lookupMailboxId(); + + verify(mailboxDirectoryApi).lookupMailboxIds(List.of(UUID.fromString(NAME_IDENTIFIER))); + } + + @DisplayName("should call getMailBoxIdByTenantOrFirst") + @Test + void shouldCallGetMailBoxIdByTenantOrFirst() { + lookupMailboxId(); + + verify(osi2ResponseMapper).getMailboxIdByTenantOrFirst(response, TENANT_SH); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var result = lookupMailboxId(); + + assertThat(result).isEqualTo(MAILBOX_ID); + } + + private String lookupMailboxId() { + return service.lookupMailboxId(NAME_IDENTIFIER); + } + } + } \ No newline at end of file -- GitLab From 977a14238a039e050f6afce6768358388eb94d10 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 7 Mar 2025 13:42:38 +0100 Subject: [PATCH 4/7] OZG-4097 readme: Update sequence diagrams --- README.md | 56 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e985ee9..cba21e6 100644 --- a/README.md +++ b/README.md @@ -11,34 +11,47 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 participant A as file-manager participant B as Client participant C as OPF - activate A - activate C - activate B activate N N->>B: OsiPostfachRemoteService::sendMessage - Note left of B: (1) Hochladen der Anhänge + activate B + Note left of B: (1) Nachschlagen einer Empfänger-Postfach-Adresse + B->>C: POST /MailboxDirectory/v1/Lookup + activate C + C-->>B: {mailboxId} + deactivate C + Note left of B: (2) Hochladen der Anhänge B->>A: GRPC findBinaryFilesMetaData + activate A A-->>B: {Liste an Anhang-Metadaten} + deactivate A loop Für jeden Anhang B->>A: GRPC GetBinaryFileContent + activate A loop Für jeden Daten-Chunk - B->>C: POST /Quarantine/v1/Upload/Chunked (chunk) + B->>C: POST /Quarantine/v1/Upload/Chunked (chunk) + activate C C-->>B: + deactivate C end A-->>B: + deactivate A B->>C: POST /Quarantine/v1/Upload/Chunked (empty chunk) + activate C C-->>B: + deactivate C end - deactivate A - Note left of B: (2) Warten auf Prüfung der hochgeladenen Anhänge + Note left of B: (3) Warten auf Prüfung der hochgeladenen Anhänge loop Regelmäßiges Polling bis alle Anhänge geprüft sind - loop Für alle Anhänge + loop Für jeden Anhang B->>C: GET /Quarantine/v1/Upload/{guid} - C-->>B: + activate C + C-->>B: + deactivate C end end - Note left of B: (3) Nachricht senden + Note left of B: (4) Nachricht senden B->>C: POST /MessageExchange/v1/Send/{mailboxId} + activate C C-->>B: deactivate C B-->>N: @@ -55,33 +68,37 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 participant A as file-manager participant B as Client participant C as OPF - activate A - activate C - activate B activate N N->>B: OsiPostfachRemoteService::receiveMessages + activate B B->>C: GET /MessageExchange/v1/Receive + activate C C-->>B: {Liste an Nachrichten-Kennungen (max 100)} + deactivate C loop Für jede Nachrichten-Kennung (messageId) Note left of B: (1) Nachricht abrufen B->>C: GET /MessageExchange/v1/Receive/{messageId} + activate C C-->>B: {Nachricht mit Anhang-Metadaten} + deactivate C Note left of B: (2) Herunterladen der Anhänge loop Für jeden Anhang B->>C: GET /MessageExchange/v1/Receive/{messageId}/Attachment/{attachmentId} + activate C B->>A: GRPC UploadBinaryFileAsStream + activate A A-->>B: + deactivate A C-->>B: + deactivate C end end - deactivate A - deactivate C - B->>N: {Stream an Postfach-Nachrichten} + B-->>N: {Stream an Postfach-Nachrichten} deactivate B deactivate N ``` -Der nachrichten-manager erhält von osiv2-postfach einen Stream von Postfach-Nachrichten. Nach der erfolgreichen Verarbeitung einer Nachricht sollte er `OsiPostfachRemoteService::deleteMessage` aufrufen: +Der nachrichten-manager erhält beim Aufruf von `receiveMessages` einen Stream von Postfach-Nachrichten. Nach der erfolgreichen Verarbeitung einer Nachricht sollte er `deleteMessage` aufrufen: ```mermaid %% Empfangen einer Nachricht @@ -89,11 +106,12 @@ Der nachrichten-manager erhält von osiv2-postfach einen Stream von Postfach-Nac participant N as nachrichten-manager participant B as Client participant C as OPF - activate C - activate B + activate N N->>B: OsiPostfachRemoteService::deleteMessage + activate B B->>C: GET /MessageExchange/v1/Delete/{messageId} + activate C C->>B: deactivate C B-->>N: -- GitLab From e2dc15e145ec48544fb58346310a7b961acf6825 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 10 Mar 2025 11:31:15 +0100 Subject: [PATCH 5/7] Readme: Explain configuration --- README.md | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cba21e6..522dba4 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,38 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 (OPF). +Das Maven-Artefakt `osiv2-postach` kann in ein Spring-Boot eingebunden werden. +Die Spring-Bean `osiPostfachRemoteService` mit dem Interface +`PostfachRemoteService` kann mit `ozgcloud.osiv2.enabled: true` aktiviert werden. + +## Konfiguration +Um auf die Postfach-Facade zugreifen zu können muss der Client sich beim Servicekonto anmelden. +Hierzu wird `ozgcloud.osiv2.auth` konfiguriert, wie bspw. hier für Stage-Schleswig-Holstein: +```yaml +client-id: 'OZG-Kopfstelle-SH' +client-secret: 'changeme' +scope: default, access_urn:dataport:osi:sh:stage:ozgkopfstelle +token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' +resource: 'urn:dataport:osi:postfach:rz2:stage:sh' +``` +Für die Postfach-Facade muss zudem die URL, der Tenant, und der SAML-Name-Identifier konfiguriert werden. +Beim Nachschlagen des Postfachs der Antragsteller*in wird ein Postfach mit übereinstimmenden Tenant präferiert. +Zudem werden Tenant und SAML-Name-Identifier beim Upload von Anhängen angegeben. + +Hierzu wird `ozgcloud.osiv2.api` konfiguriert: +```yaml +url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0' +tenant: 'SH' +name-identifier: 'ozgkopfstelle' +``` +<small>(Der Wert von `name-identifier` wird momentan nicht von der Postfach-Facade geprüft.)</small> + ## Senden einer Postfach-Nachricht +Der Aufruf `sendMessage(PostfachNachricht)` sendet eine Nachricht an die Antragsteller*in. Jede Nachricht ist stets in Bezug zu einem Vorgang. +1. Mit dem SAML-Name-Identifier der Antragsteller*in wird ein Postfach nachgeschlagen, welches die Nachricht empfangen soll. +2. Vor dem Senden der Nachricht werden alle Anhänge in die Quarantäne hochgeladen und auf Viren geprüft. +3. Nach dem erfolgreichen Hochladen der Anhänge wird die Nachricht an das Postfach gesendet. ```mermaid %% Senden einer Nachricht sequenceDiagram @@ -40,7 +70,6 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 C-->>B: deactivate C end - Note left of B: (3) Warten auf Prüfung der hochgeladenen Anhänge loop Regelmäßiges Polling bis alle Anhänge geprüft sind loop Für jeden Anhang B->>C: GET /Quarantine/v1/Upload/{guid} @@ -49,7 +78,7 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 deactivate C end end - Note left of B: (4) Nachricht senden + Note left of B: (3) Nachricht senden B->>C: POST /MessageExchange/v1/Send/{mailboxId} activate C C-->>B: @@ -60,9 +89,13 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 ``` ## Empfangen von Postfach-Nachrichten +Der Aufruf `receiveMessages()` holt alle Nachrichten, die an das OZG-Cloud-Postfach gerichtet sind ab. +1. Es wird eine Liste an Nachrichten-Kennungen abgerufen. +2. Für jede Nachricht wird die Nachricht abgerufen und die Anhänge heruntergeladen. +3. Ein Stream an Nachrichten wird zurückgegeben. Anhand der Vorgangs-Kennung lässt sich jede Nachricht stets einem Vorgang zugordnen. ```mermaid -%% Empfangen einer Nachricht +%% Empfangen von Nachrichten sequenceDiagram participant N as nachrichten-manager participant A as file-manager @@ -92,8 +125,9 @@ Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 C-->>B: deactivate C end + Note left of B: (3) Bereitstellung der Postfach-Nachricht + B-->>N: {Postfach-Nachricht als Stream-Element} end - B-->>N: {Stream an Postfach-Nachrichten} deactivate B deactivate N ``` @@ -132,7 +166,7 @@ Der Resource-Server liest die Resource-URI aus dem `aud`-Claim (siehe [RFC 9068, curl -v --output auth_response.json \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ - --data-urlencode "client_id=OZG-Kopfstelle" \ + --data-urlencode "client_id=OZG-Kopfstelle-SH" \ --data-urlencode "client_secret=${SH_STAGE_CLIENT_SECRET}" \ --data-urlencode "scope=default access_urn:dataport:osi:sh:stage:ozgkopfstelle" \ --data-urlencode "resource=urn:dataport:osi:postfach:rz2:stage:sh" \ -- GitLab From 977e71c43d09249484473c31b6a09634c348205d Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 10 Mar 2025 11:36:32 +0100 Subject: [PATCH 6/7] OZG-4097 Readme: Explain configuration --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 522dba4..7f75018 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Die Spring-Bean `osiPostfachRemoteService` mit dem Interface `PostfachRemoteService` kann mit `ozgcloud.osiv2.enabled: true` aktiviert werden. ## Konfiguration -Um auf die Postfach-Facade zugreifen zu können muss der Client sich beim Servicekonto anmelden. +Um auf die Postfach-Facade zugreifen zu können, muss der Client sich beim Servicekonto anmelden. Hierzu wird `ozgcloud.osiv2.auth` konfiguriert, wie bspw. hier für Stage-Schleswig-Holstein: ```yaml client-id: 'OZG-Kopfstelle-SH' -- GitLab From 970e727a38ed9e05b320639809f491c551ebd6b3 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 10 Mar 2025 11:36:32 +0100 Subject: [PATCH 7/7] OZG-4097 Readme: Explain configuration --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7f75018..16fe92f 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Der Aufruf `sendMessage(PostfachNachricht)` sendet eine Nachricht an die Antrags ``` ## Empfangen von Postfach-Nachrichten -Der Aufruf `receiveMessages()` holt alle Nachrichten, die an das OZG-Cloud-Postfach gerichtet sind ab. +Der Aufruf `getAllMessages()` holt alle Nachrichten, die an das OZG-Cloud-Postfach gerichtet sind ab. 1. Es wird eine Liste an Nachrichten-Kennungen abgerufen. 2. Für jede Nachricht wird die Nachricht abgerufen und die Anhänge heruntergeladen. @@ -102,7 +102,7 @@ Der Aufruf `receiveMessages()` holt alle Nachrichten, die an das OZG-Cloud-Postf participant B as Client participant C as OPF activate N - N->>B: OsiPostfachRemoteService::receiveMessages + N->>B: OsiPostfachRemoteService::getAllMessages activate B B->>C: GET /MessageExchange/v1/Receive activate C @@ -132,7 +132,7 @@ Der Aufruf `receiveMessages()` holt alle Nachrichten, die an das OZG-Cloud-Postf deactivate N ``` -Der nachrichten-manager erhält beim Aufruf von `receiveMessages` einen Stream von Postfach-Nachrichten. Nach der erfolgreichen Verarbeitung einer Nachricht sollte er `deleteMessage` aufrufen: +Der nachrichten-manager erhält beim Aufruf von `getAllMessages` einen Stream von Postfach-Nachrichten. Nach der erfolgreichen Verarbeitung einer Nachricht sollte er `deleteMessage` aufrufen: ```mermaid %% Empfangen einer Nachricht -- GitLab