diff --git a/.gitignore b/.gitignore index 3fc1d884b983db7cd48581b4198239e70ebc5119..174f39620a3a67eaad565eae9eaff3b03614809e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ target/ .idea *.iml *.orig +.vscode/ diff --git a/lombok.config b/lombok.config index d07dd9b0e2b0281fbf514a968b9451cb6af62f93..a06fa130e8af26b659f2d3a0cb1114cd966a9b0e 100644 --- a/lombok.config +++ b/lombok.config @@ -27,4 +27,5 @@ lombok.log.slf4j.flagUsage = ERROR lombok.log.log4j.flagUsage = ERROR lombok.data.flagUsage = ERROR lombok.nonNull.exceptionType = IllegalArgumentException -lombok.addLombokGeneratedAnnotation = true \ No newline at end of file +lombok.addLombokGeneratedAnnotation = true +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier \ No newline at end of file diff --git a/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto b/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto index 34504138fbe034e800a6d2d02eeb90b78bac9f6f..ada0e22babb0fa9f35fb2f5c0980a7cb4cfd3719 100644 --- a/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto +++ b/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto @@ -62,9 +62,9 @@ message GrpcRueckfrage { string status = 7; string trustLevel = 8; bool accessible = 9; - + string text = 10; - + repeated string attachmentFileId = 11; repeated GrpcRueckfrageAnswer answers = 12; } @@ -92,4 +92,30 @@ message GrpcGetRueckfrageRequest { message GrpcGetRueckfrageResponse { GrpcRueckfrage rueckfrage = 1; +} + +message GrpcGetAttachmentContentRequest { + string samlToken = 1; + string nachrichtId = 2; + string fileId = 3; +} + +message GrpcGetAttachmentContentResponse { + bytes fileContent = 1; +} + +message GrpcGetAttachmentMetadataRequest { + string samlToken = 1; + string nachrichtId = 2; + string fileId = 3; +} + +message GrpcGetAttachmentMetadataResponse { + GrpcFileMetadata fileMetadata = 1; +} + +message GrpcFileMetadata { + string name = 1; + int64 size = 2; + string contentType = 3; } \ No newline at end of file diff --git a/nachrichten-manager-interface/src/main/protobuf/antragraum.proto b/nachrichten-manager-interface/src/main/protobuf/antragraum.proto index e22f3bb0fa2226094b2551d8748c1095f1ded8f5..b82fb2711176118e1bc07819205dd9d7e5b63586 100644 --- a/nachrichten-manager-interface/src/main/protobuf/antragraum.proto +++ b/nachrichten-manager-interface/src/main/protobuf/antragraum.proto @@ -26,7 +26,6 @@ syntax = "proto3"; package de.ozgcloud.nachrichten.antragraum; import "antragraum.model.proto"; -import "command.model.proto"; option java_multiple_files = true; option java_package = "de.ozgcloud.nachrichten.antragraum"; @@ -38,7 +37,14 @@ service AntragraumService { rpc SendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest) returns (GrpcSendRueckfrageAnswerResponse) { } - + rpc GetRueckfrage(GrpcGetRueckfrageRequest) returns (GrpcGetRueckfrageResponse){ } + + rpc GetAttachmentContent (GrpcGetAttachmentContentRequest) returns (stream GrpcGetAttachmentContentResponse){ + } + + rpc GetAttachmentMetadata (GrpcGetAttachmentMetadataRequest) returns (GrpcGetAttachmentMetadataResponse){ + } + } \ No newline at end of file diff --git a/nachrichten-manager-server/pom.xml b/nachrichten-manager-server/pom.xml index daca1893bc2bb66e7e61a5398486ac054084c5a3..28fe26cba3bca3d69eafc29654f923ce7e366430 100644 --- a/nachrichten-manager-server/pom.xml +++ b/nachrichten-manager-server/pom.xml @@ -24,7 +24,8 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> @@ -47,7 +48,8 @@ <bayernid-proxy-interface.version>0.7.0</bayernid-proxy-interface.version> <vorgang-manager.version>2.17.0-SNAPSHOT</vorgang-manager.version> <muk-postfach.version>0.1.0-SNAPSHOT</muk-postfach.version> - <ozgcloud-starter.version>0.13.0-SNAPSHOT</ozgcloud-starter.version> + <api-lib.version>0.13.0-SNAPSHOT</api-lib.version> + <ozgcloud-common.version>4.5.0-SNAPSHOT</ozgcloud-common.version> </properties> <dependencies> @@ -86,12 +88,6 @@ <artifactId>muk-postfach</artifactId> <version>${muk-postfach.version}</version> </dependency> - - <dependency> - <groupId>de.ozgcloud.api-lib</groupId> - <artifactId>ozg-cloud-spring-boot-starter</artifactId> - <version>${ozgcloud-starter.version}</version> - </dependency> <dependency> <groupId>de.ozgcloud.info</groupId> @@ -99,6 +95,18 @@ <version>${ozg-info-manager-interface.version}</version> </dependency> + <dependency> + <groupId>de.ozgcloud.api-lib</groupId> + <artifactId>api-lib-core</artifactId> + <version>${api-lib.version}</version> + </dependency> + + <dependency> + <groupId>de.ozgcloud.common</groupId> + <artifactId>ozgcloud-common-lib</artifactId> + <version>${ozgcloud-common.version}</version> + </dependency> + <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> @@ -221,6 +229,13 @@ <type>test-jar</type> <scope>test</scope> </dependency> + <dependency> + <groupId>de.ozgcloud.api-lib</groupId> + <artifactId>api-lib-core</artifactId> + <version>${api-lib.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -334,4 +349,4 @@ </snapshots> </repository> </repositories> -</project> +</project> \ No newline at end of file diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java index 26f1ff18efd89ac60df5af212f5f410cbb3a1732..7f8d749fcc4f46c569fdc72071ebf779a13282d2 100644 --- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java @@ -6,6 +6,11 @@ import org.springframework.context.annotation.Configuration; import de.ozgcloud.apilib.common.command.OzgCloudCommandService; import de.ozgcloud.apilib.common.command.grpc.CommandMapper; import de.ozgcloud.apilib.common.command.grpc.GrpcOzgCloudCommandService; +import de.ozgcloud.apilib.file.OzgCloudFileService; +import de.ozgcloud.apilib.file.grpc.GrpcOzgCloudFileService; +import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; +import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub; import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc; import net.devh.boot.grpc.client.inject.GrpcClient; @@ -13,19 +18,33 @@ import net.devh.boot.grpc.client.inject.GrpcClient; public class NachrichtenManagerConfiguration { public static final String OZG_CLOUD_COMMAND_SERVICE_NAME = "nachrichten_OzgCloudCommandService"; + public static final String OZG_CLOUD_FILE_SERVICE_NAME = "nachrichten_OzgCloudFileService"; public static final String NACHRICHTEN_VORGANG_SERVICE = "nachrichten_vorgangService"; public static final String NACHRICHTEN_VORGANG_REMOTE_SERVICE = "nachrichten_vorgangRemoteService"; + public static final String NACHRICHTEN_ATTACHED_ITEM_SERVICE = "nachrichten_attachedItemService"; + public static final String NACHRICHTEN_OZG_CLOUD_FILE_MAPPER = "nachrichten_OzgCloudFileMapperImpl"; public static final String GRPC_VORGANG_MANAGER_NAME = "vorgang-manager"; public static final String GRPC_COMMAND_MANAGER_NAME = "command-manager"; + public static final String GRPC_FILE_MANAGER_NAME = "file-manager"; @GrpcClient(GRPC_COMMAND_MANAGER_NAME) private CommandServiceGrpc.CommandServiceBlockingStub commandServiceStub; + @GrpcClient(GRPC_FILE_MANAGER_NAME) + private BinaryFileServiceBlockingStub fileServiceBlockingStub; + @GrpcClient(GRPC_FILE_MANAGER_NAME) + private BinaryFileServiceStub fileServiceAsyncServiceStub; + @Bean(OZG_CLOUD_COMMAND_SERVICE_NAME) OzgCloudCommandService grpcOzgCloudCommandService(CommandMapper commandMapper, NachrichtenManagerCallContextProvider contextProvider) { return new GrpcOzgCloudCommandService(commandServiceStub, commandMapper, contextProvider, GrpcOzgCloudCommandService.DEFAULT_COMMAND_REQUEST_THRESHOLD_MILLIS); } + + @Bean(OZG_CLOUD_FILE_SERVICE_NAME) + OzgCloudFileService grpcOzgCloudFileService(NachrichtenManagerCallContextProvider contextProvider, OzgCloudFileMapper mapper) { + return new GrpcOzgCloudFileService(fileServiceBlockingStub, fileServiceAsyncServiceStub, contextProvider, mapper); + } } \ No newline at end of file diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java index 60fb62d6bfa8384eb093780e82411474bec22373..3c1918cca9831e57400a8ed37c9b8374956505e7 100644 --- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java @@ -28,11 +28,19 @@ import java.util.List; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.core.task.TaskExecutor; +import com.google.protobuf.ByteString; + +import de.ozgcloud.apilib.file.OzgCloudFile; +import de.ozgcloud.common.binaryfile.GrpcBinaryFileServerDownloader; import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration; import de.ozgcloud.nachrichten.common.vorgang.VorgangService; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import io.grpc.stub.CallStreamObserver; import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.server.service.GrpcService; @@ -41,9 +49,16 @@ import net.devh.boot.grpc.server.service.GrpcService; @RequiredArgsConstructor @ConditionalOnProperty(AntragraumProperties.PROPERTY_ANTRAGSRAUM_URL) class AntragraumGrpcService extends AntragraumServiceGrpc.AntragraumServiceImplBase { + + static final int CHUNK_SIZE = 256 * 1024; + private final AntragraumService service; private final AntragraumNachrichtMapper mapper; private final RueckfrageMapper rueckfrageMapper; + private final AttachmentFileRequestMapper attachmentFileRequestMapper; + @Qualifier(NachrichtenManagerConfiguration.NACHRICHTEN_OZG_CLOUD_FILE_MAPPER) + private final OzgCloudFileMapper ozgCloudFileMapper; + private final TaskExecutor taskExecutor; private final VorgangService vorgangService; @@ -113,4 +128,38 @@ class AntragraumGrpcService extends AntragraumServiceGrpc.AntragraumServiceImplB GrpcGetRueckfrageResponse buildGetRueckfrageResponse(GrpcRueckfrage rueckfrage) { return GrpcGetRueckfrageResponse.newBuilder().setRueckfrage(rueckfrage).build(); } + + @Override + public void getAttachmentContent(GrpcGetAttachmentContentRequest request, StreamObserver<GrpcGetAttachmentContentResponse> responseObserver) { + buildAttachmentDownloader(attachmentFileRequestMapper.fromContentRequest(request), responseObserver).start(); + } + + GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> buildAttachmentDownloader(AttachmentFileRequest request, + StreamObserver<GrpcGetAttachmentContentResponse> responseObserver) { + return GrpcBinaryFileServerDownloader.<GrpcGetAttachmentContentResponse>builder() + .callObserver((CallStreamObserver<GrpcGetAttachmentContentResponse>) responseObserver) + .taskExecutor(taskExecutor) + .downloadConsumer(outputStream -> service.getAttachmentContent(request, outputStream)) + .chunkBuilder(this::buildAttachmentChunkResponse) + .build(); + } + + GrpcGetAttachmentContentResponse buildAttachmentChunkResponse(ByteString chunk) { + return GrpcGetAttachmentContentResponse.newBuilder().setFileContent(chunk).build(); + } + + @Override + public void getAttachmentMetadata(GrpcGetAttachmentMetadataRequest request, StreamObserver<GrpcGetAttachmentMetadataResponse> responseObserver) { + var attachment = service.getAttachmentMetadata(attachmentFileRequestMapper.fromMetadataRequest(request)); + + responseObserver.onNext(buildAttachmentMetadataResponse(attachment)); + + responseObserver.onCompleted(); + } + + private GrpcGetAttachmentMetadataResponse buildAttachmentMetadataResponse(OzgCloudFile attachment) { + return GrpcGetAttachmentMetadataResponse.newBuilder() + .setFileMetadata(ozgCloudFileMapper.toMetadata(attachment)) + .build(); + } } diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java index bbb328c92b80034e5edd6897b3b4f9f49c03fab7..315c455b75691aa841ccf8dec547d776ca800d73 100644 --- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java @@ -25,6 +25,7 @@ package de.ozgcloud.nachrichten.antragraum; import static java.util.Objects.*; +import java.io.OutputStream; import java.time.ZonedDateTime; import java.util.Comparator; import java.util.Optional; @@ -41,10 +42,14 @@ import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.datatypes.GenericId; import de.ozgcloud.apilib.common.errorhandling.NotFoundException; +import de.ozgcloud.apilib.file.OzgCloudFile; +import de.ozgcloud.apilib.file.OzgCloudFileId; +import de.ozgcloud.apilib.file.OzgCloudFileService; import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration; import de.ozgcloud.nachrichten.NachrichtenManagerProperties; import de.ozgcloud.nachrichten.common.vorgang.Vorgang; import de.ozgcloud.nachrichten.common.vorgang.VorgangService; +import de.ozgcloud.nachrichten.postfach.AttachedItemService; import de.ozgcloud.nachrichten.postfach.PersistPostfachNachrichtService; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachNachrichtMapper; @@ -57,6 +62,8 @@ import lombok.extern.log4j.Log4j2; @ConditionalOnProperty(AntragraumProperties.PROPERTY_ANTRAGSRAUM_URL) public class AntragraumService { + private static final String POSTFACH_NACHRICHT = "PostfachNachricht"; + static final String BAYERN_ID_SERVICE_KONTO_TYPE = "BAYERN_ID"; static final String USER_NOTIFICATION_TEMPLATE = """ @@ -77,9 +84,15 @@ public class AntragraumService { private final AntragraumProperties properties; private final NachrichtenManagerProperties nachrichtenManagerProperties; - private final RueckfrageMapper rueckfrageMapper; + @Qualifier(NachrichtenManagerConfiguration.NACHRICHTEN_VORGANG_SERVICE) private final VorgangService vorgangService; + @Qualifier(NachrichtenManagerConfiguration.OZG_CLOUD_FILE_SERVICE_NAME) + private final OzgCloudFileService ozgCloudFileService; + @Qualifier(NachrichtenManagerConfiguration.NACHRICHTEN_ATTACHED_ITEM_SERVICE) + private final AttachedItemService attachedItemService; + + private final RueckfrageMapper rueckfrageMapper; private final PostfachNachrichtMapper nachrichtMapper; @PostConstruct @@ -94,14 +107,14 @@ public class AntragraumService { LOG.info("Starting Antragraum Service"); } - public String getAntragsraumUrl() { - return properties.getUrl(); - } - public String getUserNotificationText() { return USER_NOTIFICATION_TEMPLATE.formatted(getAntragsraumUrl()); } + public String getAntragsraumUrl() { + return properties.getUrl(); + } + public Stream<RueckfrageHead> findRueckfragen(String samlToken) { verifyToken(samlToken); @@ -139,7 +152,7 @@ public class AntragraumService { public String sendRueckfrageAnswer(String samlToken, String rueckfrageId, PostfachNachricht nachricht) { verifyToken(samlToken); - verifyPostfachId(samlToken, nachricht); + verifyAccessToPostfach(samlToken, nachricht); return postfachNachrichtService.persistAnswer(rueckfrageId, nachricht); } @@ -150,20 +163,33 @@ public class AntragraumService { return postfachNachrichtService.findAnswers(BAYERN_ID_SERVICE_KONTO_TYPE, getPostfachId(samlToken), rueckfrageId); } - String getPostfachId(String samlToken) { - return decrypter.decryptPostfachId(parser.parse(samlToken)); - } - public PostfachNachricht getRueckfrage(String samlToken, String id) { verifyToken(samlToken); var nachricht = nachrichtMapper.fromMapToPostfachMail(postfachNachrichtService.getById(id)); - verifyPostfachId(samlToken, nachricht); + verifyAccessToPostfach(samlToken, nachricht); return nachricht; } + public void getAttachmentContent(AttachmentFileRequest request, OutputStream outputStream) { + verifyAccessToFile(request); + ozgCloudFileService.writeFileDataToStream(OzgCloudFileId.from(request.getFileId()), outputStream); + } + + public OzgCloudFile getAttachmentMetadata(AttachmentFileRequest request) { + verifyAccessToFile(request); + return ozgCloudFileService.getFile(OzgCloudFileId.from(request.getFileId())); + } + + void verifyAccessToFile(AttachmentFileRequest request) { + verifyToken(request.getSamlToken()); + var nachricht = attachedItemService.getPostfachNachricht(request.getNachrichtId()); + verifyAccessToPostfach(request.getSamlToken(), nachricht); + verifyFileId(request.getFileId(), nachricht); + } + void verifyToken(String token) { var errors = verifier.verify(token); if (CollectionUtils.isNotEmpty(errors)) { @@ -171,12 +197,25 @@ public class AntragraumService { } } - void verifyPostfachId(String samlToken, PostfachNachricht nachricht) { + void verifyAccessToPostfach(String token, PostfachNachricht nachricht) { var vorgang = vorgangService.getVorgang(nachricht.getVorgangId()); + verifyPostfachId(token, nachricht, vorgang); + verifyTrustLevel(token, nachricht, vorgang); + } + void verifyPostfachId(String samlToken, PostfachNachricht nachricht, Vorgang vorgang) { if (!StringUtils.equals(vorgang.getPostfachId(), getPostfachId(samlToken))) { - LOG.info("PostfachId in token is not matching postfachId in vorgang."); - throw new NotFoundException(GenericId.from(nachricht.getId()), "PostfachNachricht"); + throw new NotFoundException(GenericId.from(nachricht.getId()), POSTFACH_NACHRICHT); + } + } + + String getPostfachId(String samlToken) { + return decrypter.decryptPostfachId(parser.parse(samlToken)); + } + + void verifyTrustLevel(String token, PostfachNachricht nachricht, Vorgang vorgang) { + if (!isAccessible(token, vorgang.getTrustLevel())) { + throw new NotFoundException(GenericId.from(nachricht.getId()), POSTFACH_NACHRICHT); } } @@ -191,4 +230,10 @@ public class AntragraumService { Response parseSamlToken(String samlToken) { return parser.parse(samlToken); } + + void verifyFileId(String fileId, PostfachNachricht nachricht) { + if (!nachricht.getAttachments().contains(fileId)) { + throw new NotFoundException(GenericId.from(nachricht.getId()), POSTFACH_NACHRICHT); + } + } } \ No newline at end of file diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequest.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..51d0c97c956d666c088f8ede9772fcac4cc4356c --- /dev/null +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024. Das Land Schleswig-Holstein + * vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.nachrichten.antragraum; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Builder +@Getter +@EqualsAndHashCode +public class AttachmentFileRequest { + + private String samlToken; + private String nachrichtId; + private String fileId; + +} diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapper.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..fc6bfb55868ba8e319f194c5bfa724e8fc8a49c9 --- /dev/null +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapper.java @@ -0,0 +1,13 @@ +package de.ozgcloud.nachrichten.antragraum; + +import org.mapstruct.Mapper; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.ReportingPolicy; + +@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.WARN) +interface AttachmentFileRequestMapper { + + AttachmentFileRequest fromContentRequest(GrpcGetAttachmentContentRequest request); + + AttachmentFileRequest fromMetadataRequest(GrpcGetAttachmentMetadataRequest request); +} diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapper.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..43ccf9a3988595c9b10b027473f3fc178688c4fd --- /dev/null +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapper.java @@ -0,0 +1,27 @@ +package de.ozgcloud.nachrichten.antragraum; + +import org.mapstruct.AnnotateWith; +import org.mapstruct.AnnotateWith.Element; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.ReportingPolicy; +import org.springframework.stereotype.Component; + +import de.ozgcloud.apilib.file.OzgCloudFile; +import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration; + +@AnnotateWith(value = Component.class, elements = @Element(strings = NachrichtenManagerConfiguration.NACHRICHTEN_OZG_CLOUD_FILE_MAPPER)) +@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.WARN) +interface OzgCloudFileMapper { + + @Mapping(target = "mergeFrom", ignore = true) + @Mapping(target = "clearField", ignore = true) + @Mapping(target = "clearOneof", ignore = true) + @Mapping(target = "mergeUnknownFields", ignore = true) + @Mapping(target = "contentTypeBytes", ignore = true) + @Mapping(target = "nameBytes", ignore = true) + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "allFields", ignore = true) + GrpcFileMetadata toMetadata(OzgCloudFile file); +} diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java index d854927466082238e4b4e09f111c53ff5cc0c453..d7607de3d693db332191ce174d6553d30a9fba32 100644 --- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java @@ -35,6 +35,7 @@ import de.ozgcloud.nachrichten.common.grpc.NachrichtenCallContextAttachingInterc import de.ozgcloud.vorgang.common.GrpcProperty; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemRequest; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem; +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest; import de.ozgcloud.vorgang.vorgangAttachedItem.VorgangAttachedItemServiceGrpc.VorgangAttachedItemServiceBlockingStub; import net.devh.boot.grpc.client.inject.GrpcClient; @@ -70,10 +71,6 @@ class AttachedItemRemoteService { return response.getVorgangAttachedItemsList().stream().map(postfachNachrichtMapper::fromAttachedItem); } - VorgangAttachedItemServiceBlockingStub getVorgangAttachedItemServiceStub() { - return vorgangAttachedItemServiceStub.withInterceptors(new NachrichtenCallContextAttachingInterceptor()); - } - GrpcFindVorgangAttachedItemRequest buildFindRequest(String vorgangId) { return GrpcFindVorgangAttachedItemRequest.newBuilder() .setVorgangId(vorgangId) @@ -81,4 +78,19 @@ class AttachedItemRemoteService { .setItemName(ITEM_NAME) .build(); } + + public PostfachNachricht getPostfachNachrichtById(String postfachNachrichtId) { + var response = getVorgangAttachedItemServiceStub().getById(buildGetByIdRequest(postfachNachrichtId)); + return postfachNachrichtMapper.fromAttachedItem(response.getVorgangAttachedItem()); + } + + VorgangAttachedItemServiceBlockingStub getVorgangAttachedItemServiceStub() { + return vorgangAttachedItemServiceStub.withInterceptors(new NachrichtenCallContextAttachingInterceptor()); + } + + GrpcVorgangAttachedItemRequest buildGetByIdRequest(String postfachNachrichtId) { + return GrpcVorgangAttachedItemRequest.newBuilder() + .setId(postfachNachrichtId) + .build(); + } } diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemService.java new file mode 100644 index 0000000000000000000000000000000000000000..ffceed84d137e6293d94f8ded9ca5a1d3b7fe646 --- /dev/null +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemService.java @@ -0,0 +1,17 @@ +package de.ozgcloud.nachrichten.postfach; + +import org.springframework.stereotype.Service; + +import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration; +import lombok.RequiredArgsConstructor; + +@Service(NachrichtenManagerConfiguration.NACHRICHTEN_ATTACHED_ITEM_SERVICE) +@RequiredArgsConstructor +public class AttachedItemService { + + private final AttachedItemRemoteService remoteService; + + public PostfachNachricht getPostfachNachricht(String id) { + return remoteService.getPostfachNachrichtById(id); + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java index a3815062085899da5db72cba9430d03f317a8c93..cde69a9d74df8dc17d6fa5aedf4859282c59e717 100644 --- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java @@ -24,13 +24,17 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.io.OutputStream; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -39,8 +43,16 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.Spy; +import org.springframework.core.task.TaskExecutor; +import com.google.protobuf.ByteString; +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.apilib.file.OzgCloudFile; +import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; +import de.ozgcloud.common.binaryfile.GrpcBinaryFileServerDownloader; import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.nachrichten.common.vorgang.GrpcServiceKontoTestFactory; import de.ozgcloud.nachrichten.common.vorgang.Vorgang; @@ -49,6 +61,7 @@ import de.ozgcloud.nachrichten.common.vorgang.VorgangTestFactory; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory; import de.ozgcloud.nachrichten.postfach.osi.MessageTestFactory; +import io.grpc.stub.CallStreamObserver; import io.grpc.stub.StreamObserver; class AntragraumGrpcServiceTest { @@ -62,9 +75,14 @@ class AntragraumGrpcServiceTest { private AntragraumNachrichtMapper nachrichtMapper; @Mock private RueckfrageMapper rueckfrageMapper; - + @Mock + private AttachmentFileRequestMapper attachmentFileRequestMapper; @Mock private VorgangService vorgangService; + @Mock + private OzgCloudFileMapper ozgCloudFileMapper; + @Mock + private TaskExecutor taskExecutor; @DisplayName("Find rueckfragen") @Nested @@ -448,4 +466,202 @@ class AntragraumGrpcServiceTest { assertThat(rueckfrageResponse.getRueckfrage()).isEqualTo(grpcRueckfrage); } } + + @Nested + class TestGetAttachmentContent { + + @Mock + private StreamObserver<GrpcGetAttachmentContentResponse> responseObserver; + @Mock + private GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> downloader; + + private final GrpcGetAttachmentContentRequest grpcRequest = GrpcGetAttachmentContentRequestTestFactory.create(); + private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create(); + + @BeforeEach + void mock() { + when(attachmentFileRequestMapper.fromContentRequest(grpcRequest)).thenReturn(request); + doReturn(downloader).when(grpcService).buildAttachmentDownloader(request, responseObserver); + } + + @Test + void shouldMapRequest() { + callGetAttachmentContent(); + + verify(attachmentFileRequestMapper).fromContentRequest(grpcRequest); + } + + @Test + void shouldCallBuildAttachmentDownloader() { + callGetAttachmentContent(); + + verify(grpcService).buildAttachmentDownloader(request, responseObserver); + } + + @Test + void shouldStartDownloader() { + callGetAttachmentContent(); + + verify(downloader).start(); + } + + private void callGetAttachmentContent() { + grpcService.getAttachmentContent(grpcRequest, responseObserver); + } + } + + @Nested + class TestBuildAttachmentDownloader { + @Mock + private CallStreamObserver<GrpcGetAttachmentContentResponse> responseObserver; + @Mock + private OutputStream outputStream; + + private MockedConstruction<GrpcBinaryFileServerDownloader> downloaderMockedConstruction; + private GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> downloader; + private StreamObserver<GrpcGetAttachmentContentResponse> setResponseObserver; + private TaskExecutor setTaskExecutor; + private Consumer<OutputStream> setDownloadConsumer; + private Function<ByteString, GrpcGetAttachmentContentResponse> setChunkBuilder; + + private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create(); + private final ByteString chunk = ByteString.copyFromUtf8(LoremIpsum.getInstance().getWords(5)); + + @SuppressWarnings("unchecked") + @BeforeEach + void mock() { + downloaderMockedConstruction = mockConstruction(GrpcBinaryFileServerDownloader.class, (downloader, context) -> { + setResponseObserver = (StreamObserver<GrpcGetAttachmentContentResponse>) context.arguments().get(0); + setChunkBuilder = (Function<ByteString, GrpcGetAttachmentContentResponse>) context.arguments().get(1); + setDownloadConsumer = (Consumer<OutputStream>) context.arguments().get(2); + setTaskExecutor = (TaskExecutor) context.arguments().get(3); + this.downloader = downloader; + }); + } + + @AfterEach + void closeMock() { + downloaderMockedConstruction.close(); + } + + @Test + void shouldSetResponseObserver() { + callBuildAttachmentDownloader(); + + assertThat(setResponseObserver).isEqualTo(responseObserver); + } + + @Test + void shouldSetTaskExecutor() { + callBuildAttachmentDownloader(); + + assertThat(setTaskExecutor).isEqualTo(taskExecutor); + } + + @Test + void shouldSetDownloadConsumer() { + callBuildAttachmentDownloader(); + + setDownloadConsumer.accept(outputStream); + + verify(service).getAttachmentContent(request, outputStream); + } + + @Test + void shouldSetChunkBuilder() { + var response = GrpcGetAttachmentContentResponse.newBuilder().setFileContent(chunk).build(); + doReturn(response).when(grpcService).buildAttachmentChunkResponse(chunk); + callBuildAttachmentDownloader(); + + var result = setChunkBuilder.apply(chunk); + + assertThat(result).isEqualTo(response); + } + + @Test + void shouldReturnDownloader() { + var returnedDownloader = callBuildAttachmentDownloader(); + + assertThat(returnedDownloader).isEqualTo(downloader); + } + + private GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> callBuildAttachmentDownloader() { + return grpcService.buildAttachmentDownloader(request, responseObserver); + } + } + + @Nested + class TestBuildAttachmentChunkResponse { + + private final ByteString chunk = ByteString.copyFromUtf8(LoremIpsum.getInstance().getWords(5)); + + @Test + void shouldReturnResponse() { + var expectedResponse = GrpcGetAttachmentContentResponse.newBuilder().setFileContent(chunk).build(); + + var result = grpcService.buildAttachmentChunkResponse(chunk); + + assertThat(result).isEqualTo(expectedResponse); + + } + } + + @Nested + class TestGetAttachmentMetadata { + + @Mock + private StreamObserver<GrpcGetAttachmentMetadataResponse> responseObserver; + + private final GrpcGetAttachmentMetadataRequest grpcRequest = GrpcGetAttachmentMetadataRequestTestFactory.create(); + private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create(); + private final OzgCloudFile attachment = OzgCloudFileTestFactory.create(); + private final GrpcFileMetadata metadata = GrpcFileMetadataTestFactory.create(); + + @BeforeEach + void mock() { + when(attachmentFileRequestMapper.fromMetadataRequest(grpcRequest)).thenReturn(request); + when(service.getAttachmentMetadata(request)).thenReturn(attachment); + when(ozgCloudFileMapper.toMetadata(attachment)).thenReturn(metadata); + } + + @Test + void shouldMapRequest() { + callGetAttachmentMetadata(); + + verify(attachmentFileRequestMapper).fromMetadataRequest(grpcRequest); + } + + @Test + void shouldCallServiceToGetMetadata() { + callGetAttachmentMetadata(); + + verify(service).getAttachmentMetadata(request); + } + + @Test + void shouldMapMetadata() { + callGetAttachmentMetadata(); + + verify(ozgCloudFileMapper).toMetadata(attachment); + } + + @Test + void shouldSendMetadata() { + callGetAttachmentMetadata(); + + verify(responseObserver).onNext(argThat((response) -> response.getFileMetadata().equals(metadata))); + } + + @Test + void shouldCallOnCompleted() { + callGetAttachmentMetadata(); + + verify(responseObserver).onCompleted(); + } + + private void callGetAttachmentMetadata() { + grpcService.getAttachmentMetadata(grpcRequest, responseObserver); + } + } + } \ No newline at end of file diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java index f5220ab82ed6c6dfa41fb8aba83a080aa1785837..ffda45abc90ea43778a91908668c572f9f671ca3 100644 --- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.io.OutputStream; import java.time.ZonedDateTime; import java.util.List; import java.util.Map; @@ -22,17 +23,23 @@ import org.mockito.Spy; import org.opensaml.saml.saml2.core.Response; import de.ozgcloud.apilib.common.errorhandling.NotFoundException; +import de.ozgcloud.apilib.file.OzgCloudFile; +import de.ozgcloud.apilib.file.OzgCloudFileId; +import de.ozgcloud.apilib.file.OzgCloudFileService; +import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; import de.ozgcloud.nachrichten.NachrichtenManagerProperties; import de.ozgcloud.nachrichten.common.vorgang.GrpcPostfachAddressTestFactory; import de.ozgcloud.nachrichten.common.vorgang.GrpcServiceKontoTestFactory; import de.ozgcloud.nachrichten.common.vorgang.Vorgang; import de.ozgcloud.nachrichten.common.vorgang.VorgangService; import de.ozgcloud.nachrichten.common.vorgang.VorgangTestFactory; +import de.ozgcloud.nachrichten.postfach.AttachedItemService; import de.ozgcloud.nachrichten.postfach.PersistPostfachNachrichtService; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachNachrichtMapper; import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory; import de.ozgcloud.nachrichten.postfach.osi.MessageTestFactory; +import lombok.SneakyThrows; class AntragraumServiceTest { @@ -58,6 +65,10 @@ class AntragraumServiceTest { private VorgangService vorgangService; @Mock private PostfachNachrichtMapper nachrichtMapper; + @Mock + private AttachedItemService attachedItemService; + @Mock + private OzgCloudFileService ozgCloudFileService; @Nested class TestGetAntragsraumUrl { @@ -297,7 +308,7 @@ class AntragraumServiceTest { @DisplayName("Send rueckfragen answers") @Nested - class TestSendRueckfragenAnswers { + class TestSendRueckfrageAnswer { static final String SAML_TOKEN = "TOKEN"; static final String RUECKFRAGE_ID = UUID.randomUUID().toString(); static final PostfachNachricht NACHRICHT = PostfachNachrichtTestFactory.create(); @@ -305,7 +316,7 @@ class AntragraumServiceTest { @BeforeEach void mock() { doNothing().when(service).verifyToken(any()); - doNothing().when(service).verifyPostfachId(any(), any()); + doNothing().when(service).verifyAccessToPostfach(any(), any()); } @Test @@ -323,10 +334,10 @@ class AntragraumServiceTest { } @Test - void shouldVerifyPostfachId() { + void shouldVerifyAccessToPostfach() { service.sendRueckfrageAnswer(SAML_TOKEN, RUECKFRAGE_ID, NACHRICHT); - verify(service).verifyPostfachId(SAML_TOKEN, NACHRICHT); + verify(service).verifyAccessToPostfach(SAML_TOKEN, NACHRICHT); } } @@ -402,7 +413,7 @@ class AntragraumServiceTest { when(nachrichtMapper.fromMapToPostfachMail(any())).thenReturn(nachricht); doNothing().when(service).verifyToken(any()); - doNothing().when(service).verifyPostfachId(any(), any()); + doNothing().when(service).verifyAccessToPostfach(any(), any()); } @Test @@ -434,10 +445,10 @@ class AntragraumServiceTest { } @Test - void shouldCallVerifyPostfachId() { + void shouldCallVerifyAccessToPostfach() { getRueckfrage(); - verify(service).verifyPostfachId(samlToken, nachricht); + verify(service).verifyAccessToPostfach(samlToken, nachricht); } private PostfachNachricht getRueckfrage() { @@ -445,32 +456,18 @@ class AntragraumServiceTest { } } - @DisplayName("Verify postfachId") @Nested class TestVerifyPostfachId { - private static final String SAML_TOKEN = "TOKEN"; - private static final PostfachNachricht POSTFACH_NACHRICHT = PostfachNachrichtTestFactory.create(); - - @BeforeEach - void mock() { - when(vorgangService.getVorgang(any())).thenReturn(VorgangTestFactory.create()); - } - - @Test - void shouldCallVorgangService() { - doReturn(GrpcPostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE).when(service).getPostfachId(any()); - - service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT); - - verify(vorgangService).getVorgang(MessageTestFactory.VORGANG_ID); - } + private final String SAML_TOKEN = "TOKEN"; + private final PostfachNachricht POSTFACH_NACHRICHT = PostfachNachrichtTestFactory.create(); + private final Vorgang vorgang = VorgangTestFactory.create(); @Test void shouldGetPostfachIdFromToken() { doReturn(GrpcPostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE).when(service).getPostfachId(any()); - service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT); + service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT, vorgang); verify(service).getPostfachId(SAML_TOKEN); } @@ -479,7 +476,7 @@ class AntragraumServiceTest { void shouldThrowExceptionOnMismatchPostfachId() { doReturn("not-matching-postfach-id").when(service).getPostfachId(any()); - assertThatThrownBy(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT)) + assertThatThrownBy(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT, vorgang)) .isInstanceOf(NotFoundException.class) .hasMessageContaining("PostfachNachricht") .hasMessageContaining(PostfachNachrichtTestFactory.ID); @@ -489,7 +486,7 @@ class AntragraumServiceTest { void shouldNotThrowExceptionOnMatchingPostfachId() { doReturn(GrpcPostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE).when(service).getPostfachId(any()); - assertDoesNotThrow(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT)); + assertDoesNotThrow(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT, vorgang)); } } @@ -587,4 +584,217 @@ class AntragraumServiceTest { assertThat(parseResponse).isEqualTo(response); } } + + @Nested + class TestGetAttachmentContent { + + @Mock + private OutputStream outputStream; + + private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create(); + + @BeforeEach + void mock() { + doNothing().when(service).verifyAccessToFile(request); + } + + @Test + void shouldCallVerifyAccessToFile() { + callGetAttachmentContent(); + + verify(service).verifyAccessToFile(request); + } + + @Test + void shouldCallOzgCloudFileServiceToWriteData() { + callGetAttachmentContent(); + + verify(ozgCloudFileService).writeFileDataToStream(OzgCloudFileId.from(AttachmentFileRequestTestFactory.FILE_ID), outputStream); + } + + @SneakyThrows + private void callGetAttachmentContent() { + service.getAttachmentContent(request, outputStream); + } + } + + @Nested + class TestGetAttachmentMetadata { + + private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create(); + + @BeforeEach + void mock() { + doNothing().when(service).verifyAccessToFile(request); + } + + @Test + void shouldCallVerifyAccessToFile() { + callGetAttachmentMetadata(); + + verify(service).verifyAccessToFile(request); + } + + @Test + void shouldCallOzgCloudFileServiceToGetFile() { + callGetAttachmentMetadata(); + + verify(ozgCloudFileService).getFile(OzgCloudFileId.from(AttachmentFileRequestTestFactory.FILE_ID)); + } + + @Test + void shouldReturnOzgCloudFile() { + var ozgCloudFile = OzgCloudFileTestFactory.create(); + when(ozgCloudFileService.getFile(OzgCloudFileId.from(AttachmentFileRequestTestFactory.FILE_ID))).thenReturn(ozgCloudFile); + + var result = callGetAttachmentMetadata(); + + assertThat(result).isEqualTo(ozgCloudFile); + } + + private OzgCloudFile callGetAttachmentMetadata() { + return service.getAttachmentMetadata(request); + } + } + + @Nested + class TestVerifyAccessToFile { + + private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create(); + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + + @BeforeEach + void mock() { + when(attachedItemService.getPostfachNachricht(AttachmentFileRequestTestFactory.NACHRICHT_ID)).thenReturn(nachricht); + doNothing().when(service).verifyAccessToPostfach(AttachmentFileRequestTestFactory.TOKEN, nachricht); + doNothing().when(service).verifyFileId(AttachmentFileRequestTestFactory.FILE_ID, nachricht); + } + + @Test + void shouldVerifySamlToken() { + callVerifyAccessToFile(); + + verify(service).verifyToken(AttachmentFileRequestTestFactory.TOKEN); + } + + @Test + void shouldCallAttachedItemServiceToGetPostfachNachricht() { + callVerifyAccessToFile(); + + verify(attachedItemService).getPostfachNachricht(AttachmentFileRequestTestFactory.NACHRICHT_ID); + } + + @Test + void shouldCallVerifyAccessToPostfach() { + callVerifyAccessToFile(); + + verify(service).verifyAccessToPostfach(AttachmentFileRequestTestFactory.TOKEN, nachricht); + } + + @Test + void shouldVerifyFileId() { + callVerifyAccessToFile(); + + verify(service).verifyFileId(AttachmentFileRequestTestFactory.FILE_ID, nachricht); + } + + private void callVerifyAccessToFile() { + service.verifyAccessToFile(request); + } + + } + + @Nested + class TestVerifyAccessToPostfach { + + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + private final Vorgang vorgang = VorgangTestFactory.create(); + + @BeforeEach + void mock() { + when(vorgangService.getVorgang(MessageTestFactory.VORGANG_ID)).thenReturn(vorgang); + doNothing().when(service).verifyPostfachId(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang); + doNothing().when(service).verifyTrustLevel(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang); + } + + @Test + void shouldCallVorgangService() { + verifyAccessToPostfach(); + + verify(vorgangService).getVorgang(MessageTestFactory.VORGANG_ID); + } + + @Test + void shouldCallVerifyPostfachId() { + verifyAccessToPostfach(); + + verify(service).verifyPostfachId(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang); + } + + @Test + void shouldVerifyTrustLevel() { + verifyAccessToPostfach(); + + verify(service).verifyTrustLevel(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang); + } + + private void verifyAccessToPostfach() { + service.verifyAccessToPostfach(AttachmentFileRequestTestFactory.TOKEN, nachricht); + } + } + + @Nested + class TestVerifyTrustLevel { + + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + private final Vorgang vorgang = VorgangTestFactory.create(); + + @Test + void shouldCallIsAccessible() { + doReturn(true).when(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL); + + callVerifyTrustLevel(); + + verify(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL); + } + + @Test + void shouldThrowExceptionOnNotAccessible() { + doReturn(false).when(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL); + + assertThatThrownBy(() -> callVerifyTrustLevel()) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("PostfachNachricht") + .hasMessageContaining(PostfachNachrichtTestFactory.ID); + } + + @Test + void shouldNotThrowExceptionOnAccessible() { + doReturn(true).when(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL); + + assertDoesNotThrow(() -> callVerifyTrustLevel()); + } + + private void callVerifyTrustLevel() { + service.verifyTrustLevel(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang); + } + } + + @Nested + class TestVerifyFileId { + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + + @Test + void shouldThrowExceptionOnNotMatchingFileId() { + assertThatThrownBy(() -> service.verifyFileId(PostfachNachrichtTestFactory.ATTACHMENT_FILE_ID + "wrong", nachricht)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("PostfachNachricht") + .hasMessageContaining(PostfachNachrichtTestFactory.ID); + } + + @Test + void shouldNotThrowExceptionOnMatchingFileId() { + assertDoesNotThrow(() -> service.verifyFileId(PostfachNachrichtTestFactory.ATTACHMENT_FILE_ID, nachricht)); + } + } } \ No newline at end of file diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapperTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f76b44c73d7bce9d9cc5ac1ec877f6cdfdfb8d94 --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapperTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024. Das Land Schleswig-Holstein + * vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.nachrichten.antragraum; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +class AttachmentFileRequestMapperTest { + + private final AttachmentFileRequestMapper mapper = Mappers.getMapper(AttachmentFileRequestMapper.class); + + @Nested + class TestFromContentRequest { + + @Test + void shouldMapToRueckfrageAttachmentFileRequest() { + var request = mapper.fromContentRequest(GrpcGetAttachmentContentRequestTestFactory.create()); + + assertThat(request).isEqualTo(AttachmentFileRequestTestFactory.create()); + } + } + + @Nested + class TestFromMetadataRequest { + + @Test + void shouldMapToRueckfrageAttachmentFileRequest() { + var request = mapper.fromMetadataRequest(GrpcGetAttachmentMetadataRequestTestFactory.create()); + + assertThat(request).isEqualTo(AttachmentFileRequestTestFactory.create()); + } + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..5697bb2a54e2c74d72868c78ef8a36654c8aa6fa --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestTestFactory.java @@ -0,0 +1,27 @@ +package de.ozgcloud.nachrichten.antragraum; + +import java.util.UUID; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.nachrichten.antragraum.AttachmentFileRequest.AttachmentFileRequestBuilder; +import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory; + +public class AttachmentFileRequestTestFactory { + + public static final String TOKEN = LoremIpsum.getInstance().getWords(1); + public static final String FILE_ID = UUID.randomUUID().toString(); + public static final String NACHRICHT_ID = PostfachNachrichtTestFactory.ID; + + public static AttachmentFileRequest create() { + return createBuilder() + .build(); + } + + public static AttachmentFileRequestBuilder createBuilder() { + return AttachmentFileRequest.builder() + .samlToken(TOKEN) + .fileId(FILE_ID) + .nachrichtId(NACHRICHT_ID); + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcFileMetadataTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcFileMetadataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..41b231bf773e24e74b3e2800a4c39eaaa2c66c67 --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcFileMetadataTestFactory.java @@ -0,0 +1,23 @@ +package de.ozgcloud.nachrichten.antragraum; + +import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; +import de.ozgcloud.nachrichten.antragraum.GrpcFileMetadata.Builder; + +public class GrpcFileMetadataTestFactory { + + public static final long SIZE = OzgCloudFileTestFactory.SIZE; + public static final String NAME = OzgCloudFileTestFactory.NAME; + public static final String CONTENT_TYPE = OzgCloudFileTestFactory.CONTENT_TYPE; + + public static GrpcFileMetadata create() { + return createBuilder().build(); + + } + + public static Builder createBuilder() { + return GrpcFileMetadata.newBuilder() + .setContentType(CONTENT_TYPE) + .setName(NAME) + .setSize(SIZE); + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentContentRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentContentRequestTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..51ac2d5f80248b21f2158161070aa9822fdf6f1b --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentContentRequestTestFactory.java @@ -0,0 +1,19 @@ +package de.ozgcloud.nachrichten.antragraum; + +public class GrpcGetAttachmentContentRequestTestFactory { + + public static final String TOKEN = AttachmentFileRequestTestFactory.TOKEN; + public static final String FILE_ID = AttachmentFileRequestTestFactory.FILE_ID; + public static final String NACHRICHT_ID = AttachmentFileRequestTestFactory.NACHRICHT_ID; + + public static GrpcGetAttachmentContentRequest create() { + return createBuilder().build(); + } + + public static GrpcGetAttachmentContentRequest.Builder createBuilder() { + return GrpcGetAttachmentContentRequest.newBuilder() + .setSamlToken(TOKEN) + .setNachrichtId(NACHRICHT_ID) + .setFileId(FILE_ID); + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentMetadataRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentMetadataRequestTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..bbd7acd1af4a4c27cf6cfb9c6698c2760241ab27 --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentMetadataRequestTestFactory.java @@ -0,0 +1,19 @@ +package de.ozgcloud.nachrichten.antragraum; + +public class GrpcGetAttachmentMetadataRequestTestFactory { + + public static final String TOKEN = AttachmentFileRequestTestFactory.TOKEN; + public static final String FILE_ID = AttachmentFileRequestTestFactory.FILE_ID; + public static final String NACHRICHT_ID = AttachmentFileRequestTestFactory.NACHRICHT_ID; + + public static GrpcGetAttachmentMetadataRequest create() { + return createBuilder().build(); + } + + public static GrpcGetAttachmentMetadataRequest.Builder createBuilder() { + return GrpcGetAttachmentMetadataRequest.newBuilder() + .setSamlToken(TOKEN) + .setNachrichtId(NACHRICHT_ID) + .setFileId(FILE_ID); + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapperTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cd64a2b0fa4ecd0817594a179598d6d2a4805b07 --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapperTest.java @@ -0,0 +1,25 @@ +package de.ozgcloud.nachrichten.antragraum; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; + +class OzgCloudFileMapperTest { + + private final OzgCloudFileMapper mapper = Mappers.getMapper(OzgCloudFileMapper.class); + + @Nested + class TestToMetadata { + + @Test + void shouldMapToMetadata() { + var metadata = mapper.toMetadata(OzgCloudFileTestFactory.create()); + + assertThat(metadata).isEqualTo(GrpcFileMetadataTestFactory.create()); + } + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java index 0c879370f9fc9d636ca233686e98a63d69f816d5..62969f468a20003d0446dd1d345f32f6c39d625a 100644 --- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java @@ -46,6 +46,8 @@ import de.ozgcloud.vorgang.common.GrpcProperty; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemRequest; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemResponse; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem; +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest; +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemResponse; import de.ozgcloud.vorgang.vorgangAttachedItem.VorgangAttachedItemServiceGrpc.VorgangAttachedItemServiceBlockingStub; class AttachedItemRemoteServiceTest { @@ -264,4 +266,75 @@ class AttachedItemRemoteServiceTest { assertThat(postfachNachrichten).containsExactly(postfachNachricht); } } + + @Nested + class TestGetPostfachNachrichtById { + + @Mock + private VorgangAttachedItemServiceBlockingStub stubWithInterceptor; + + private final GrpcVorgangAttachedItemRequest request = GrpcVorgangAttachedItemRequestTestFactory.create(); + private final GrpcVorgangAttachedItemResponse response = GrpcVorgangAttachedItemResponseTestFactory.create(); + + @BeforeEach + void mock() { + doReturn(stubWithInterceptor).when(service).getVorgangAttachedItemServiceStub(); + doReturn(request).when(service).buildGetByIdRequest(PostfachNachrichtTestFactory.ID); + when(stubWithInterceptor.getById(request)).thenReturn(response); + } + + @Test + void shouldCallGetVorgangAttachedItemServiceStub() { + callGetPostfachNachrichtById(); + + verify(service).getVorgangAttachedItemServiceStub(); + } + + @Test + void shouldCallBuildGetByIdRequest() { + callGetPostfachNachrichtById(); + + verify(service).buildGetByIdRequest(PostfachNachrichtTestFactory.ID); + } + + @Test + void shouldCallServiceStubWithInterceptor() { + callGetPostfachNachrichtById(); + + verify(stubWithInterceptor).getById(request); + } + + @Test + void shouldMapToPostfachNachricht() { + callGetPostfachNachrichtById(); + + verify(postfachNachrichtMapper).fromAttachedItem(GrpcVorgangAttachedItemResponseTestFactory.ATTACHED_ITEM); + } + + @Test + void shouldReturnMappedPostfachNachricht() { + var mappedPostfachNachricht = PostfachNachrichtTestFactory.create(); + when(postfachNachrichtMapper.fromAttachedItem(GrpcVorgangAttachedItemResponseTestFactory.ATTACHED_ITEM)) + .thenReturn(mappedPostfachNachricht); + + var postfachNachricht = callGetPostfachNachrichtById(); + + assertThat(postfachNachricht).isEqualTo(mappedPostfachNachricht); + } + + private PostfachNachricht callGetPostfachNachrichtById() { + return service.getPostfachNachrichtById(PostfachNachrichtTestFactory.ID); + } + } + + @Nested + class TestBuildGetByIdRequest { + + @Test + void shouldReturnGrpcRequest() { + var request = service.buildGetByIdRequest(PostfachNachrichtTestFactory.ID); + + assertThat(request).isEqualTo(GrpcVorgangAttachedItemRequestTestFactory.create()); + } + } } \ No newline at end of file diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6c513319ac59889f9c3478bcf05d1dbfe7f70b2a --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemServiceTest.java @@ -0,0 +1,45 @@ +package de.ozgcloud.nachrichten.postfach; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +class AttachedItemServiceTest { + + @InjectMocks + private AttachedItemService service; + + @Mock + private AttachedItemRemoteService remoteService; + + @Nested + class TestGetPostfachNachricht { + + private final PostfachNachricht postfachNachricht = PostfachNachrichtTestFactory.create(); + + @Test + void shouldCallRemoteService() { + callGetPostfachNachricht(); + + verify(remoteService).getPostfachNachrichtById(PostfachNachrichtTestFactory.ID); + } + + @Test + void shouldReturnPostfachNachricht() { + when(remoteService.getPostfachNachrichtById(PostfachNachrichtTestFactory.ID)).thenReturn(postfachNachricht); + + var result = callGetPostfachNachricht(); + + assertThat(result).isEqualTo(postfachNachricht); + } + + private PostfachNachricht callGetPostfachNachricht() { + return service.getPostfachNachricht(PostfachNachrichtTestFactory.ID); + } + } + +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemRequestTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..2f371dd485369072b0e7b36aafa917c2eb469966 --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemRequestTestFactory.java @@ -0,0 +1,16 @@ +package de.ozgcloud.nachrichten.postfach; + +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest; +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest.Builder; + +public class GrpcVorgangAttachedItemRequestTestFactory { + + public static GrpcVorgangAttachedItemRequest create() { + return createBuilder().build(); + } + + public static Builder createBuilder() { + return GrpcVorgangAttachedItemRequest.newBuilder() + .setId(PostfachNachrichtTestFactory.ID); + } +} diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemResponseTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemResponseTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..ad87b1859ce2cd0e2bd47a7b468a31aae735983e --- /dev/null +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemResponseTestFactory.java @@ -0,0 +1,19 @@ +package de.ozgcloud.nachrichten.postfach; + +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem; +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemResponse; +import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemResponse.Builder; + +public class GrpcVorgangAttachedItemResponseTestFactory { + + public static final GrpcVorgangAttachedItem ATTACHED_ITEM = GrpcVorgangAttachedItemTestFactory.create(); + + public static GrpcVorgangAttachedItemResponse create() { + return createBuilder().build(); + } + + public static Builder createBuilder() { + return GrpcVorgangAttachedItemResponse.newBuilder() + .setVorgangAttachedItem(ATTACHED_ITEM); + } +}