diff --git a/archive-manager-server/pom.xml b/archive-manager-server/pom.xml index 641a7f94ebb7cf631dbab8db17351aaf83618d30..e7f316f838c54dfa2a53500d7fd3d0eefe93daac 100644 --- a/archive-manager-server/pom.xml +++ b/archive-manager-server/pom.xml @@ -4,7 +4,6 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - <parent> <groupId>de.ozgcloud.archive</groupId> <artifactId>archive-manager</artifactId> @@ -46,6 +45,10 @@ <artifactId>archive-manager-interface</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>de.ozgcloud.command</groupId> + <artifactId>command-manager</artifactId> + </dependency> <dependency> <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-interface</artifactId> @@ -66,12 +69,35 @@ <groupId>de.ozgcloud.document</groupId> <artifactId>document-manager-interface</artifactId> </dependency> + + <!-- Spring --> <dependency> - <groupId>de.ozgcloud.api-lib</groupId> - <artifactId>api-lib-core</artifactId> - <type>test-jar</type> - <scope>test</scope> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-core</artifactId> </dependency> + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + </dependency> + + <!-- gRPC --> + <dependency> + <groupId>net.devh</groupId> + <artifactId>grpc-server-spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>net.devh</groupId> + <artifactId>grpc-client-spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-inprocess</artifactId> + </dependency> + <!-- Tools --> <dependency> <groupId>jakarta.xml.bind</groupId> @@ -89,7 +115,27 @@ <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> </dependency> + <!-- Test --> + <dependency> + <groupId>de.ozgcloud.api-lib</groupId> + <artifactId>api-lib-core</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>de.ozgcloud.command</groupId> + <artifactId>command-manager</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>de.ozgcloud.vorgang</groupId> + <artifactId>vorgang-manager-base</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java index e33bfda9dbf7058f86be261ba0fb333c664355a6..247277431b87bdb7fa32e063f090e427db734f6a 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java @@ -1,14 +1,41 @@ package de.ozgcloud.archive; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import de.ozgcloud.apilib.client_attribute.OzgCloudClientAttributeService; +import de.ozgcloud.apilib.client_attribute.grpc.OzgCloudClientAttributeGrpcService; +import de.ozgcloud.apilib.client_attribute.grpc.OzgCloudClientAttributeMapper; +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.apilib.user.GrpcOzgCloudUserProfileService; +import de.ozgcloud.apilib.user.OzgCloudUserProfileService; +import de.ozgcloud.apilib.user.UserProfileMapper; +import de.ozgcloud.archive.common.callcontext.CallContextProvider; +import de.ozgcloud.user.grpc.userprofile.UserProfileServiceGrpc.UserProfileServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub; +import de.ozgcloud.vorgang.grpc.clientAttribute.ClientAttributeServiceGrpc.ClientAttributeServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc.CommandServiceBlockingStub; +import lombok.RequiredArgsConstructor; +import net.devh.boot.grpc.client.inject.GrpcClient; + @Configuration -public class ArchiveManagerConfiguration { // NOSONAR +@RequiredArgsConstructor +public class ArchiveManagerConfiguration { + public static final String VORGANG_SERVICE_NAME = "archive_VorgangService"; public static final String VORGANG_REMOTE_MANAGER_SERVICE_NAME = "archive_VorgangRemoteService"; public static final String VORGANG_WITH_EINGANG_MAPPER_NAME = "archive_VorgangWithEingangMapper"; + public static final String CURRENT_USER_SERVICE_NAME = "archive_CurrentUserService"; public static final String DOCUMENT_MAPPER_NAME = "archive_DocumentMapper"; + public static final String DOCUMENT_REMOTE_SERVICE_NAME = "archive_DocumentRemoteService"; public static final String USER_SERVICE_NAME = "archive_UserService"; public static final String USER_PROFILE_MAPPER_NAME = "archive_UserProfileMapper"; @@ -17,6 +44,7 @@ public class ArchiveManagerConfiguration { // NOSONAR public static final String COMMAND_SERVICE_NAME = "archive_CommandService"; public static final String COMMAND_REMOTE_SERVICE_NAME = "archive_CommandRemoteService"; public static final String COMMAND_MAPPER_NAME = "archive_CommandMapper"; + public static final String OZGCLOUD_COMMAND_SERVICE_NAME = "archive_OzgCloudCommandService"; public static final String BINARY_FILE_SERVICE_NAME = "archive_BinaryFileService"; public static final String BINARY_FILE_REMOTE_SERVICE_NAME = "archive_BinaryFileRemoteService"; @@ -27,6 +55,59 @@ public class ArchiveManagerConfiguration { // NOSONAR public static final String BESCHEID_REMOTE_SERVICE_NAME = "archive_BescheidRemoteService"; public static final String BESCHEID_MAPPER_NAME = "archive_BescheidMapper"; - public static final String OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME = "archive_CallContextProvider"; + public static final String CALL_CONTEXT_PROVIDER_NAME = "archive_CallContextProvider"; + public static final String CALL_CONTEXT_MAPPER_NAME = "archive_CallContextMapper"; + + public static final String CLIENT_ATTRIBUTE_SERVICE_NAME = "archive_ClientAttributeService"; + public static final String OZGCLOUD_CLIENT_ATTRIBUTE_SERVICE_NAME = "archive_OzgCloudClientAttributeService"; + + public static final String KOMMENTAR_SERVICE_NAME = "archive_KommentarService"; + public static final String KOMMENTAR_REMOTE_SERVICE_NAME = "archive_KommentarRemoteService"; + + public static final String CALL_CONTEXT_SERVER_INTERCEPTOR_NAME = "archive_CallContextGrpcServerInterceptor"; + + public static final String GRPC_VORGANG_MANAGER_CLIENT_NAME = "vorgang-manager"; + public static final String GRPC_COMMAND_MANAGER_CLIENT_NAME = "command-manager"; + public static final String GRPC_FILE_MANAGER_CLIENT_NAME = "file-manager"; + public static final String GRPC_USER_MANAGER_CLIENT_NAME = "user-manager"; + + @GrpcClient(GRPC_VORGANG_MANAGER_CLIENT_NAME) + private final ClientAttributeServiceBlockingStub clientAttributeServiceBlockingStub; + + @GrpcClient(GRPC_COMMAND_MANAGER_CLIENT_NAME) + private final CommandServiceBlockingStub commandServiceStub; + + @GrpcClient(GRPC_USER_MANAGER_CLIENT_NAME) + private final UserProfileServiceBlockingStub userProfileServiceBlockingStub; + + @GrpcClient(GRPC_FILE_MANAGER_CLIENT_NAME) + private final BinaryFileServiceBlockingStub binaryFileServiceBlockingStub; + + @GrpcClient(GRPC_FILE_MANAGER_CLIENT_NAME) + private final BinaryFileServiceStub binaryFileServiceStub; + + @Bean(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) // NOSONAR + OzgCloudFileService ozgCloudFileService(OzgCloudFileMapper mapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new GrpcOzgCloudFileService(binaryFileServiceBlockingStub, binaryFileServiceStub, callContextProvider, mapper); + } + + @Bean(ArchiveManagerConfiguration.OZGCLOUD_USER_PROFILE_SERVICE_NAME) // NOSONAR + OzgCloudUserProfileService grpcOzgCloudUserProfileService(UserProfileMapper userProfileMapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new GrpcOzgCloudUserProfileService(userProfileServiceBlockingStub, userProfileMapper, callContextProvider); + } + + @Bean(OZGCLOUD_CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR + OzgCloudClientAttributeService ozgCloudAttributesService(OzgCloudClientAttributeMapper mapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new OzgCloudClientAttributeGrpcService(clientAttributeServiceBlockingStub, mapper, callContextProvider); + } + @Bean(OZGCLOUD_COMMAND_SERVICE_NAME) // NOSONAR + OzgCloudCommandService ozgCloudCommandService(CommandMapper commandMapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new GrpcOzgCloudCommandService(commandServiceStub, commandMapper, callContextProvider, + GrpcOzgCloudCommandService.DEFAULT_COMMAND_REQUEST_THRESHOLD_MILLIS); + } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/OzgcloudConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/OzgcloudConfiguration.java deleted file mode 100644 index 0311d0420c079af88e3f04daa8e831741f7d359b..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/OzgcloudConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.ozgcloud.archive; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; -import de.ozgcloud.apilib.file.OzgCloudFileService; -import de.ozgcloud.apilib.file.grpc.GrpcOzgCloudFileService; -import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; -import de.ozgcloud.apilib.user.GrpcOzgCloudUserProfileService; -import de.ozgcloud.apilib.user.OzgCloudUserProfileService; -import de.ozgcloud.apilib.user.UserProfileMapper; -import de.ozgcloud.archive.common.GrpcUtil; -import de.ozgcloud.user.grpc.userprofile.UserProfileServiceGrpc.UserProfileServiceBlockingStub; -import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; -import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub; -import net.devh.boot.grpc.client.inject.GrpcClient; - -@Configuration -class OzgcloudConfiguration { - - @GrpcClient(GrpcUtil.USER_MANAGER_GRPC_CLIENT) - private UserProfileServiceBlockingStub userProfileServiceBlockingStub; - - @GrpcClient(GrpcUtil.FILE_MANAGER_GRPC_CLIENT) - private BinaryFileServiceBlockingStub binaryFileServiceBlockingStub; - - @GrpcClient(GrpcUtil.FILE_MANAGER_GRPC_CLIENT) - private BinaryFileServiceStub binaryFileServiceStub; - - @Bean(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) - OzgCloudFileService ozgCloudFileService( - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) OzgCloudCallContextProvider contextProvider, - OzgCloudFileMapper mapper) { - - return new GrpcOzgCloudFileService(binaryFileServiceBlockingStub, binaryFileServiceStub, contextProvider, mapper); - } - - @Bean(ArchiveManagerConfiguration.OZGCLOUD_USER_PROFILE_SERVICE_NAME) // NOSONAR - OzgCloudUserProfileService grpcOzgCloudUserProfileService( - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) OzgCloudCallContextProvider callContextProvider, - UserProfileMapper userProfileMapper) { - return new GrpcOzgCloudUserProfileService(userProfileServiceBlockingStub, userProfileMapper, callContextProvider); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/attributes/ClientAttributeService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/attributes/ClientAttributeService.java new file mode 100644 index 0000000000000000000000000000000000000000..21d24f804eb7d430b399243e9af5baaa8affecb8 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/attributes/ClientAttributeService.java @@ -0,0 +1,61 @@ +/* + * 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.archive.attributes; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import de.ozgcloud.apilib.client_attribute.OzgCloudAccessPermission; +import de.ozgcloud.apilib.client_attribute.OzgCloudBooleanClientAttribute; +import de.ozgcloud.apilib.client_attribute.OzgCloudClientAttributeService; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.common.callcontext.CallContextUser; +import lombok.RequiredArgsConstructor; + +@Service(ArchiveManagerConfiguration.CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor +public class ClientAttributeService { + + public static final String ATTRIBUTE_NAME_ANTRAG_ARCHIVING = "ARCHIVING"; + + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR + private final OzgCloudClientAttributeService ozgCloudAttributesService; + + private final OzgCloudVorgangIdMapper vorgangIdMapper; + + public void setVorgangArchiving(String vorgangId) { + ozgCloudAttributesService.setClientAttribute(buildBooleanClientAttribute(true), vorgangIdMapper.fromString(vorgangId)); + } + + OzgCloudBooleanClientAttribute buildBooleanClientAttribute(boolean isArchiving) { + return OzgCloudBooleanClientAttribute.builder() + .clientName(CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME) + .access(OzgCloudAccessPermission.READ_ONLY) + .attributeName(ATTRIBUTE_NAME_ANTRAG_ARCHIVING) + .value(isArchiving) + .build(); + } + +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java index eda3d0ccd43ec3a5c9a419f183af1a13015e08e7..7b1e5095cc9d5f4f4afc72be229788472c3817c8 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java @@ -2,29 +2,27 @@ package de.ozgcloud.archive.bescheid; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.document.bescheid.BescheidServiceGrpc.BescheidServiceBlockingStub; import de.ozgcloud.document.bescheid.GrpcGetAllBescheidRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @Service(ArchiveManagerConfiguration.BESCHEID_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class BescheidRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private BescheidServiceBlockingStub grpcService; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) + private final BescheidServiceBlockingStub grpcService; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; @Qualifier(ArchiveManagerConfiguration.BESCHEID_MAPPER_NAME) // NOSONAR - private BescheidMapper bescheidMapper; + private final BescheidMapper bescheidMapper; public Stream<Bescheid> findByVorgangId(String vorgangId) { var request = buildGetAllBescheidRequest(vorgangId); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java index 1eead2e35a5cef9783cf6f9bbb465179a619e001..5428fdda81422b96ac5ee1d0490e2e7773367785 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java @@ -1,29 +1,27 @@ package de.ozgcloud.archive.bescheid; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.common.binaryfile.FileId; import de.ozgcloud.document.DocumentServiceGrpc.DocumentServiceBlockingStub; import de.ozgcloud.document.GrpcGetDocumentRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; -@Service +@Service(ArchiveManagerConfiguration.DOCUMENT_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class DocumentRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private DocumentServiceBlockingStub grpcService; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final DocumentServiceBlockingStub grpcService; @Qualifier(ArchiveManagerConfiguration.DOCUMENT_MAPPER_NAME) // NOSONAR - private DocumentMapper documentMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + private final DocumentMapper documentMapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public FileId getDocument(String documentId) { var response = getGrpcServiceWithInterceptor().getDocument(GrpcGetDocumentRequest.newBuilder().setId(documentId).build()); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java index 7fe61a04059da950ac3cd7950cc0f8854ed4dc3b..0a120e71f6e69af9060f471df95714e3713ec328 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java @@ -23,6 +23,7 @@ public class ExportBescheidService { @Qualifier(ArchiveManagerConfiguration.BINARY_FILE_SERVICE_NAME) // NOSONAR private final BinaryFileService binaryFileService; + @Qualifier(ArchiveManagerConfiguration.DOCUMENT_REMOTE_SERVICE_NAME) // NOSONAR private final DocumentRemoteService documentRemoteService; @Qualifier(ArchiveManagerConfiguration.USER_SERVICE_NAME) // NOSONAR diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/GrpcUtil.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/GrpcUtil.java deleted file mode 100644 index c7ecb0d7e72af32754fcb642ed011d36c58ab42c..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/GrpcUtil.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.ozgcloud.archive.common; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class GrpcUtil { - - public static final String VORGANG_MANAGER_GRPC_CLIENT = "vorgang-manager"; - public static final String FILE_MANAGER_GRPC_CLIENT = "file-manager"; - public static final String USER_MANAGER_GRPC_CLIENT = "user-manager"; - -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java index 81d450f5df26ba8bb5eb6f02e0e49a5477929bd1..733788b6492552491eb97d7ad78a1486d813c697 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java @@ -4,7 +4,6 @@ import java.io.OutputStream; import java.util.List; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -12,32 +11,32 @@ import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterce import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.apilib.file.OzgCloudFileService; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.archive.file.OzgFile; import de.ozgcloud.archive.file.OzgFileMapper; import de.ozgcloud.common.binaryfile.FileId; import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFilesRequest; import de.ozgcloud.vorgang.grpc.binaryFile.GrpcFindFilesResponse; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @Service(ArchiveManagerConfiguration.BINARY_FILE_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class BinaryFileRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private BinaryFileServiceBlockingStub grpcService; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) - private OzgCloudFileService ozgCloudFileService; - @Autowired - private OzgFileMapper ozgFileMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; - - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final BinaryFileServiceBlockingStub grpcService; + + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) // NOSONAR + private final OzgCloudFileService ozgCloudFileService; + + private final OzgFileMapper ozgFileMapper; + + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; + @Qualifier(ArchiveManagerConfiguration.FILE_ID_MAPPER_NAME) // NOSONAR - private FileIdMapper fileIdMapper; + private final FileIdMapper fileIdMapper; public Stream<OzgFile> getFiles(List<FileId> fileIds) { var response = getGrpcServiceWithInterceptor().findBinaryFilesMetaData(buildBinaryFilesRequest(fileIds)); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContext.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContext.java deleted file mode 100644 index 20d128669fb7401b5339119bee5b092da1ffa5f9..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContext.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import java.util.Collection; -import java.util.UUID; - -import lombok.Builder; -import lombok.Getter; -import lombok.Singular; - -@Builder -@Getter -public class ArchiveCallContext { - - static final String CLIENT_NAME = "OzgCloud_ArchiveManager"; - - @Builder.Default - private String clientName = CLIENT_NAME; - private String userId; - - @Builder.Default - private String requestId = UUID.randomUUID().toString(); - @Builder.Default - private boolean accessLimited = false; - @Singular - private Collection<String> accessLimitedToOrgaIds; -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapper.java deleted file mode 100644 index 43c2125c9914a943cf5a2ceba8dcc6558658e33c..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -import de.ozgcloud.apilib.common.callcontext.CallContext; -import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; - -@Mapper(uses = OzgCloudUserIdMapper.class) -public interface ArchiveCallContextMapper { - - @Mapping(target = "accessLimitedToOrgaId", ignore = true) - CallContext toOzgCloudCallContext(ArchiveCallContext archiveCallContext); - -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java new file mode 100644 index 0000000000000000000000000000000000000000..156357c600baab2fe7d0034cdb77729a24fd709e --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java @@ -0,0 +1,66 @@ +/* + * 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.archive.common.callcontext; + +import java.util.Collection; +import java.util.stream.Collectors; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Getter +@EqualsAndHashCode(callSuper = true) +public class CallContextAuthenticationToken extends AbstractAuthenticationToken { + + private final CallContextUser user; + + static CallContextAuthenticationToken authenticate(CallContextUser user) { + return new CallContextAuthenticationToken(user); + } + + private CallContextAuthenticationToken(CallContextUser user) { + super(user.getAccessLimitedToOrgaIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); + this.user = user; + super.setAuthenticated(true); + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getPrincipal() { + return getUser(); + } + + @Override + public Collection<GrantedAuthority> getAuthorities() { + return user.getAccessLimitedToOrgaIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toUnmodifiableSet()); + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextConfiguration.java deleted file mode 100644 index ffaabe7c2236d88f41f561056f620ac9306817cb..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextConfiguration.java +++ /dev/null @@ -1,16 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; -import de.ozgcloud.archive.ArchiveManagerConfiguration; - -@Configuration -public class CallContextConfiguration { - - @Bean(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - OzgCloudCallContextProvider callContextProvider(ArchiveCallContextMapper mapper) { - return new CallContextProvider(mapper, CallContextInterceptor.CONTEXT_KEY_CALL_CONTEXT::get); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptor.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..3ea2660d6c5ca7cee1400f01a572da5ab9cb87a3 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptor.java @@ -0,0 +1,86 @@ +package de.ozgcloud.archive.common.callcontext; + +import java.util.UUID; + +import org.apache.logging.log4j.CloseableThreadContext; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.stereotype.Component; + +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.ForwardingServerCallListener; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCall.Listener; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import lombok.RequiredArgsConstructor; + +@Component(ArchiveManagerConfiguration.CALL_CONTEXT_SERVER_INTERCEPTOR_NAME) // NOSONAR +@RequiredArgsConstructor +public class CallContextGrpcServerInterceptor implements ServerInterceptor { + + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_MAPPER_NAME) // NOSONAR + private final CallContextMapper callContextMapper; + + @Override + public <A, B> Listener<A> interceptCall(ServerCall<A, B> call, Metadata headers, ServerCallHandler<A, B> next) { + return new LogContextSettingListener<>(next.startCall(call, headers), headers); + } + + class LogContextSettingListener<A> extends ForwardingServerCallListener.SimpleForwardingServerCallListener<A> { + + private final String requestId; + private final Metadata headers; + + public LogContextSettingListener(ServerCall.Listener<A> delegate, Metadata headers) { + super(delegate); + this.headers = headers; + this.requestId = getRequestId(headers); + } + + String getRequestId(Metadata headers) { + return GrpcUtil.getRequestId(headers).orElseGet(() -> UUID.randomUUID().toString()); + } + + @Override + public void onMessage(A message) { + doSurroundOn(() -> super.onMessage(message)); + } + + @Override + public void onHalfClose() { + doSurroundOn(super::onHalfClose); + } + + @Override + public void onCancel() { + doSurroundOn(super::onCancel); + } + + @Override + public void onComplete() { + doSurroundOn(super::onComplete); + } + + @Override + public void onReady() { + doSurroundOn(super::onReady); + } + + void doSurroundOn(Runnable runnable) { + SecurityContext securityContext = null; + try (var ctc = CloseableThreadContext.put(GrpcUtil.KEY_REQUEST_ID, requestId)) { + securityContext = currentUserService.startAndReturnPreviousSecurityContext(callContextMapper.toCallContextUser(headers, requestId)); + runnable.run(); + } finally { + currentUserService.resetSecurityContext(securityContext); + } + } + + } + +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptor.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptor.java deleted file mode 100644 index f2736787df9f53f3bb11ced8b6af76b9d2d7d24e..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptor.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static de.ozgcloud.common.grpc.GrpcUtil.*; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -import io.grpc.Context; -import io.grpc.Contexts; -import io.grpc.Metadata; -import io.grpc.ServerCall; -import io.grpc.ServerCall.Listener; -import io.grpc.ServerCallHandler; -import io.grpc.ServerInterceptor; -import lombok.RequiredArgsConstructor; - -@Component -@RequiredArgsConstructor -public class CallContextInterceptor implements ServerInterceptor { - - static final String KEY_USER_ID = "USER_ID-bin"; - static final String KEY_ACCESS_LIMITED = "ACCESS_LIMITED-bin"; - static final String KEY_ACCESS_LIMITED_ORGAID = "ACCESS_LIMITED_TO_ORGANISATORISCHEEINHEITENID-bin"; - - public static final Context.Key<ArchiveCallContext> CONTEXT_KEY_CALL_CONTEXT = Context.key("archiveCallContext"); - - @Override - public <A, B> Listener<A> interceptCall(ServerCall<A, B> call, Metadata headers, ServerCallHandler<A, B> next) { - var newContext = Context.current().withValue(CONTEXT_KEY_CALL_CONTEXT, createArchiveCallContext(headers)); - return Contexts.interceptCall(newContext, call, headers, next); - } - - ArchiveCallContext createArchiveCallContext(Metadata headers) { - return ArchiveCallContext.builder() - .userId(getFromHeaders(KEY_USER_ID, headers).orElse(StringUtils.EMPTY)) - .accessLimited(getFromHeaders(KEY_ACCESS_LIMITED, headers).map(isLimited -> isLimited.equals("true")).orElse(false)) - .accessLimitedToOrgaIds(getCollection(KEY_ACCESS_LIMITED_ORGAID, headers)) - .build(); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5731f307fa3e96f9c59692bb28da2b33665031ba --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextMapper.java @@ -0,0 +1,60 @@ +/* + * 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.archive.common.callcontext; + +import org.mapstruct.AnnotateWith; +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.springframework.stereotype.Component; + +import de.ozgcloud.apilib.common.callcontext.CallContext; +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.Metadata; +import lombok.extern.log4j.Log4j2; + +@Mapper(uses = OzgCloudUserIdMapper.class, collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +@AnnotateWith(value = Component.class, elements = @AnnotateWith.Element(strings = ArchiveManagerConfiguration.CALL_CONTEXT_MAPPER_NAME)) +@Log4j2 +abstract class CallContextMapper { // NOSONAR + + @Mapping(target = "accessLimitedToOrgaId", ignore = true) + @Mapping(target = "clientName", constant = CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME) + abstract CallContext toOzgCloudCallContext(CallContextUser callContextUser); + + public CallContextUser toCallContextUser(Metadata headers, String requestId) { + var builder = CallContextUser.builder() + .requestId(requestId) + .userId(GrpcUtil.getUserId(headers)) + .userName(GrpcUtil.getUserName(headers)); + GrpcUtil.getAccessLimited(headers).ifPresentOrElse( + isAccessLimited -> builder.accessLimited(isAccessLimited).accessLimitedToOrgaIds(GrpcUtil.getAccessLimitedOrgaIds(headers)), + () -> builder.accessLimited(false)); + // TODO throw exception if missing required data as soon all clients are fine + GrpcUtil.getClientName(headers).ifPresentOrElse(builder::clientName, () -> LOG.warn("Missing client name in grpc header.")); + return builder.build(); + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java index 5ce75ee17473a0f65c2483dc18cc1c2ec7f8a718..9fd0d350ed11048aded7be7715f289c52cf6c941 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java @@ -1,18 +1,24 @@ package de.ozgcloud.archive.common.callcontext; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + import de.ozgcloud.apilib.common.callcontext.CallContext; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import lombok.RequiredArgsConstructor; +@Component(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR @RequiredArgsConstructor public class CallContextProvider implements OzgCloudCallContextProvider { - private final ArchiveCallContextMapper mapper; - private final GrpcCallContextSupplier contextSupplier; + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_MAPPER_NAME) // NOSONAR + private final CallContextMapper mapper; @Override public CallContext provideContext() { - var archiveCallContext = contextSupplier.get(); - return mapper.toOzgCloudCallContext(archiveCallContext); + return mapper.toOzgCloudCallContext(currentUserService.getUser()); } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java new file mode 100644 index 0000000000000000000000000000000000000000..0d74bf0b07f69f8f5ca9da3b1805f4483147716a --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java @@ -0,0 +1,41 @@ +package de.ozgcloud.archive.common.callcontext; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Collection; +import java.util.Optional; + +import org.springframework.security.core.AuthenticatedPrincipal; + +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +@Builder +@Getter +public class CallContextUser implements AuthenticatedPrincipal, Serializable { + + public static final String ARCHIVE_MANAGER_CLIENT_NAME = "OzgCloud_ArchiveManager"; + + @Serial + private static final long serialVersionUID = 1L; + + private String requestId; + + private String clientName; + + @Builder.Default + private Optional<String> userId = Optional.empty(); + @Builder.Default + private Optional<String> userName = Optional.empty(); + @Builder.Default + private boolean accessLimited = false; + + @Singular + private Collection<String> accessLimitedToOrgaIds; + + @Override + public String getName() { + return clientName; + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java new file mode 100644 index 0000000000000000000000000000000000000000..07e867d69de62efecc026ddec84cf92644a3e241 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java @@ -0,0 +1,116 @@ +/* + * 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.archive.common.callcontext; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.ThreadContext; +import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.command.Command; +import de.ozgcloud.common.grpc.GrpcUtil; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR +public class CurrentUserService { + + private final AuthenticationTrustResolver trustResolver; + + public CallContextUser getUser() { + return findUser().orElseThrow(() -> new IllegalStateException("No authenticated User found")); + } + + public Optional<CallContextUser> findUser() { + return findTrustedAuthentication() + .map(this::mapToCallContextUser) + // remove this filter as soon we have a trusted authentication + .filter(user -> StringUtils.isNotBlank(user.getClientName())); + } + + CallContextUser mapToCallContextUser(Authentication auth) { + return auth instanceof CallContextAuthenticationToken token ? token.getUser() : buildDefaultCallContextUser(auth); + } + + CallContextUser buildDefaultCallContextUser(Authentication auth) { + var defaultContextUser = CallContextUser.builder().clientName(auth.getName()); + auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).forEach(defaultContextUser::accessLimitedToOrgaId); + return defaultContextUser.build(); + } + + public Optional<Authentication> findAuthentication() { + return findTrustedAuthentication(); + } + + Optional<Authentication> findTrustedAuthentication() { + return Optional.ofNullable(SecurityContextHolder.getContext()) + .map(SecurityContext::getAuthentication) + .filter(auth -> !trustResolver.isAnonymous(auth)) + .filter(Authentication::isAuthenticated); + } + + public SecurityContext startAndReturnPreviousSecurityContext(Command command) { + return startAndReturnPreviousSecurityContext(createUser(command)); + } + + CallContextUser createUser(Command command) { + return CallContextUser.builder() + .userId(Optional.ofNullable(command.getCreatedBy())) + .userName(Optional.ofNullable(command.getCreatedByName())) + .clientName(command.getCreatedByClientName()) + .requestId(getRequestId()) + .accessLimited(false) + .build(); + } + + String getRequestId() { + return ThreadContext.getContext().getOrDefault(GrpcUtil.KEY_REQUEST_ID, UUID.randomUUID().toString()); + } + + + public SecurityContext startAndReturnPreviousSecurityContext(CallContextUser user) { + var prevContext = SecurityContextHolder.getContext(); + + SecurityContextHolder.clearContext(); + SecurityContextHolder.getContext().setAuthentication(CallContextAuthenticationToken.authenticate(user)); + + return prevContext; + } + + public void resetSecurityContext(SecurityContext context) { + SecurityContextHolder.clearContext(); + if (Objects.nonNull(context)) { + SecurityContextHolder.setContext(context); + } + } +} \ No newline at end of file diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/GrpcCallContextSupplier.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/GrpcCallContextSupplier.java deleted file mode 100644 index a5237a7877c7805d6724a480b3062a257028dadb..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/GrpcCallContextSupplier.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import java.util.function.Supplier; - -interface GrpcCallContextSupplier extends Supplier<ArchiveCallContext> { - -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/Command.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/ArchiveManagerCommand.java similarity index 89% rename from archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/Command.java rename to archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/ArchiveManagerCommand.java index 2be6ee74722f57a42577fbf788fff4a976090fb9..e8842ffa7461ffa364f88758cca8bfa4bacb7882 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/Command.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/ArchiveManagerCommand.java @@ -8,7 +8,7 @@ import lombok.Getter; @Builder(toBuilder = true) @Getter -public class Command { +public class ArchiveManagerCommand { private ZonedDateTime finishedAt; private String createdByName; diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandMapper.java index 5a43480617a6f567e436223f50d54777e97b356c..f31c35ce669cf019ac4e47cadd88d01b1c91a25d 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandMapper.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandMapper.java @@ -21,7 +21,7 @@ interface CommandMapper { @Mapping(target = "body", source = "bodyObj") @Mapping(target = "order", source = "orderString") @Mapping(target = "finishedAt", expression = "java(mapToZonedDateTime(grpcCommand.getFinishedAt()))") - Command fromGrpc(GrpcCommand grpcCommand); + ArchiveManagerCommand fromGrpc(GrpcCommand grpcCommand); default ZonedDateTime mapToZonedDateTime(String value) { return StringUtils.isEmpty(value) ? null : ZonedDateTime.parse(value); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java index 1e54516036e69e23b8e188f45b26826ed19d9b00..d011eddc02da2d0ff58d09ec8dfe4dbb82a406b8 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java @@ -3,31 +3,29 @@ package de.ozgcloud.archive.common.command; import java.util.Optional; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc.CommandServiceBlockingStub; import de.ozgcloud.vorgang.grpc.command.GrpcFindCommandsRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; +@RequiredArgsConstructor @Service(ArchiveManagerConfiguration.COMMAND_REMOTE_SERVICE_NAME) // NOSONAR class CommandRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private CommandServiceBlockingStub grpcService; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final CommandServiceBlockingStub grpcService; @Qualifier(ArchiveManagerConfiguration.COMMAND_MAPPER_NAME) // NOSONAR - private CommandMapper mapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + private final CommandMapper mapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; - public Stream<Command> findCommands(String vorgangId, Optional<String> status, Optional<String> order) { + public Stream<ArchiveManagerCommand> findCommands(String vorgangId, Optional<String> status, Optional<String> order) { var response = getGrpcServiceWithInterceptor().findCommands(buildFindCommandsRequest(vorgangId, status, order)); return response.getCommandList().stream().map(mapper::fromGrpc); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java index 5f8c5ec4100915c6ce187fa873759ccf356a4e37..7696a5817bb640cb81a0c4223cb930a0b68944cd 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java @@ -17,7 +17,7 @@ public class CommandService { @Qualifier(ArchiveManagerConfiguration.COMMAND_REMOTE_SERVICE_NAME) // NOSONAR private final CommandRemoteService remoteService; - public Stream<Command> findFinishedCommands(@NonNull String vorgangId) { + public Stream<ArchiveManagerCommand> findFinishedCommands(@NonNull String vorgangId) { return remoteService.findCommands(vorgangId, Optional.of("FINISHED"), Optional.empty()); } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandWithPrevious.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandWithPrevious.java index 62b22631beb14a63539ca5c681284e03d719dd80..16858f58818566d2998efae1ed330d318912df5a 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandWithPrevious.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandWithPrevious.java @@ -7,6 +7,6 @@ import lombok.Getter; @Getter public class CommandWithPrevious { - private Command command; - private Command previous; + private ArchiveManagerCommand command; + private ArchiveManagerCommand previous; } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java index d662419ad8a5e575b713e40fe9a09ba927688404..0c41a4e443df0290a12785c043df33b28068b7af 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java @@ -1,5 +1,7 @@ package de.ozgcloud.archive.common.user; +import java.util.Optional; + import org.mapstruct.Mapper; import de.ozgcloud.apilib.user.OzgCloudUserId; @@ -7,6 +9,10 @@ import de.ozgcloud.apilib.user.OzgCloudUserId; @Mapper public interface OzgCloudUserIdMapper { + default OzgCloudUserId fromString(Optional<String> id) { + return id.map(this::fromString).orElse(null); + } + default OzgCloudUserId fromString(String id) { return OzgCloudUserId.from(id); } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java index 48f92d0a8105bdd771405e74c845dc5093ee3755..ebf673e0f49a534a01a714fb50aff04dfca5dd61 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java @@ -6,7 +6,7 @@ import org.springframework.core.task.TaskExecutor; import com.google.protobuf.ByteString; -import de.ozgcloud.archive.common.callcontext.CallContextInterceptor; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.archive.grpc.export.ExportServiceGrpc.ExportServiceImplBase; import de.ozgcloud.archive.grpc.export.GrpcExportVorgangRequest; import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse; @@ -17,7 +17,7 @@ import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.server.service.GrpcService; -@GrpcService(interceptors = { CallContextInterceptor.class }) +@GrpcService(interceptorNames = { ArchiveManagerConfiguration.CALL_CONTEXT_SERVER_INTERCEPTOR_NAME }) @RequiredArgsConstructor class ExportGrpcService extends ExportServiceImplBase { diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java index c2a4f346f0c4cc13d9cfbaa5d07550b692971280..8ec623f59340deff8448dd5fe267ab31285d26fd 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java @@ -12,8 +12,10 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.archive.bescheid.ExportBescheidService; import de.ozgcloud.archive.common.ExportFilenameGenerator; import de.ozgcloud.archive.file.ExportFileService; @@ -23,7 +25,7 @@ import de.ozgcloud.archive.kommentar.ExportKommentarService; import de.ozgcloud.archive.postfach.ExportNachrichtService; import de.ozgcloud.archive.vorgang.Eingang; import de.ozgcloud.archive.vorgang.EingangHeader; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.common.errorhandling.TechnicalException; import de.xoev.xdomea.AbgabeAbgabe0401; @@ -39,8 +41,10 @@ class ExportService { private final XdomeaXmlMarshaller xDomeaXmlMarshaller; private final ExportFileService exportFileService; - private final ExportVorgangService exportVorgangService; + @Qualifier(ArchiveManagerConfiguration.VORGANG_SERVICE_NAME) // NOSONAR + private final VorgangService vorgangService; private final ExportHistorieService exportHistorieService; + @Qualifier(ArchiveManagerConfiguration.KOMMENTAR_SERVICE_NAME) // NOSONAR private final ExportKommentarService exportKommentarService; private final ExportNachrichtService exportNachrichtService; private final ExportBescheidService exportBescheidService; @@ -51,7 +55,7 @@ class ExportService { } ExportData collectExportData(String vorgangId, String filenameId) { - var vorgang = exportVorgangService.getVorgang(vorgangId); + var vorgang = vorgangService.getVorgang(vorgangId); var kommentarsData = exportKommentarService.createExportData(vorgang); var postfachMailData = exportNachrichtService.createExportData(vorgang); var bescheidData = exportBescheidService.createExportData(vorgang); @@ -59,9 +63,9 @@ class ExportService { var attachments = exportFileService.getAttachments(vorgang).toList(); var formEngineName = getFormEngineName(vorgang); var abgabe = XdomeaNachrichtBuilder.builder() - .withKopf(exportVorgangService.createKopf(vorgang)) - .withVorgang(exportVorgangService.createVorgangType(vorgang)) - .withAktenzeichen(exportVorgangService.createAkteType(vorgang)) + .withKopf(vorgangService.createKopf(vorgang)) + .withVorgang(vorgangService.createVorgangType(vorgang)) + .withAktenzeichen(vorgangService.createAkteType(vorgang)) .withRepresentations(exportFileService.createDokumentTypes(representations, formEngineName).toList()) .withAttachments(exportFileService.createDokumentTypes(attachments, formEngineName).toList()) .withHistorie(exportHistorieService.createHistorienProtokollInformationTypes(vorgang).toList()) diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java index aca984a632b909c87ec502ee7e9c8b4bd9cebc91..89968a704a490af97603a2fb33bd35e0bd62e79c 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java @@ -2,29 +2,27 @@ package de.ozgcloud.archive.file; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.grpc.file.FileServiceGrpc.FileServiceBlockingStub; import de.ozgcloud.vorgang.grpc.file.GrpcGetAttachmentsRequest; import de.ozgcloud.vorgang.grpc.file.GrpcGetRepresentationsRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @Service +@RequiredArgsConstructor class OzgFileRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private FileServiceBlockingStub grpcService; - @Autowired - private OzgFileMapper fileMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final FileServiceBlockingStub grpcService; + private final OzgFileMapper fileMapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public Stream<OzgFile> getAttachments(String vorgangId) { return getGrpcServiceWithInterceptor().getAttachments(buildGrpcGetAttachmentsRequest(vorgangId)).getFileList().stream() diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilder.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilder.java index 448e7c5a22959ee54be735176439f5bd46feb538..bf8c08601b272b9794e6841897da56893397315a 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilder.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilder.java @@ -4,7 +4,7 @@ import java.util.Optional; import org.apache.commons.lang3.StringUtils; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandWithPrevious; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -20,7 +20,7 @@ class AktenzeichenChangeHistoryBuilder extends ChangeHistoryBuilder<Aktenzeichen } @Override - boolean isRelevant(Command command) { + boolean isRelevant(ArchiveManagerCommand command) { return SET_AKTENZEICHEN_ORDER.equals(command.getOrder()); } @@ -42,7 +42,7 @@ class AktenzeichenChangeHistoryBuilder extends ChangeHistoryBuilder<Aktenzeichen return getAktenzeichen(commandWithPrevious.getCommand()); } - String getAktenzeichen(Command command) { + String getAktenzeichen(ArchiveManagerCommand command) { return getValueFromCommandBody(BODY_PROPERTY_AKTENZEICHEN, command); } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilder.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilder.java index 111343d9c98a2a68237a7973e2334d45fffa946d..3aebc7527cfcfa59f75e5a05cf058cf7f151ede7 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilder.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilder.java @@ -4,7 +4,7 @@ import java.util.Optional; import org.apache.commons.lang3.StringUtils; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandWithPrevious; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -27,7 +27,7 @@ class AssignedUserChangeHistoryBuilder extends ChangeHistoryBuilder<AssignedUser } @Override - boolean isRelevant(Command command) { + boolean isRelevant(ArchiveManagerCommand command) { return ASSIGN_USER_ORDER.equals(command.getOrder()); } @@ -49,7 +49,7 @@ class AssignedUserChangeHistoryBuilder extends ChangeHistoryBuilder<AssignedUser return getAssignedUserFullNameFromCommand(commandWithPrevious.getCommand()); } - String getAssignedUserFullNameFromCommand(Command command) { + String getAssignedUserFullNameFromCommand(ArchiveManagerCommand command) { var assignedUserId = getValueFromCommandBody(BODY_PROPERTY_ASSIGNED_USER, command); return userProfileCache.getUserProfile(assignedUserId).getFullName(); } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/ChangeHistoryBuilder.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/ChangeHistoryBuilder.java index 0d81f48e004679a68e79b59774e89ede046e3616..60460c4f0d1037f0815ecd45f022343b26616aa1 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/ChangeHistoryBuilder.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/ChangeHistoryBuilder.java @@ -8,17 +8,17 @@ import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandWithPrevious; import de.ozgcloud.archive.common.command.CommandWithPrevious.CommandWithPreviousBuilder; abstract class ChangeHistoryBuilder<T extends ChangeHistoryBuilder<T>> { - List<Command> commands; + List<ArchiveManagerCommand> commands; String organisationseinheitenID; @SuppressWarnings("unchecked") - public T withCommands(List<Command> commands) { + public T withCommands(List<ArchiveManagerCommand> commands) { this.commands = commands; return (T) this; } @@ -37,17 +37,17 @@ abstract class ChangeHistoryBuilder<T extends ChangeHistoryBuilder<T>> { .flatMap(this::toVorgangChanges); } - Stream<Command> retrieveRelevantCommands() { + Stream<ArchiveManagerCommand> retrieveRelevantCommands() { return commands.stream().filter(this::isRelevant); } - abstract boolean isRelevant(Command command); + abstract boolean isRelevant(ArchiveManagerCommand command); - Stream<Command> inChronologicalOrder(Stream<Command> commands) { - return commands.sorted(Comparator.comparing(Command::getFinishedAt)); + Stream<ArchiveManagerCommand> inChronologicalOrder(Stream<ArchiveManagerCommand> commands) { + return commands.sorted(Comparator.comparing(ArchiveManagerCommand::getFinishedAt)); } - Stream<CommandWithPrevious> addPreviousCommand(Stream<Command> commands) { + Stream<CommandWithPrevious> addPreviousCommand(Stream<ArchiveManagerCommand> commands) { var commandsList = commands.toList(); var result = new ArrayList<CommandWithPrevious>(commandsList.size()); for (int i = 0; i < commandsList.size(); i++) { @@ -81,10 +81,10 @@ abstract class ChangeHistoryBuilder<T extends ChangeHistoryBuilder<T>> { .build(); } - String getValueFromCommandBody(String propertyName, Command command) { + String getValueFromCommandBody(String propertyName, ArchiveManagerCommand command) { return Optional.ofNullable(command.getBody()).map(body -> body.get(propertyName)).map(Object::toString).orElse(StringUtils.EMPTY); } - record CommandWithChangeValues(Command command, String valueBeforeChange, String valueAfterChange) { + record CommandWithChangeValues(ArchiveManagerCommand command, String valueBeforeChange, String valueAfterChange) { } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilder.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilder.java index 62f67e63528bcf08969c5b8b457acfe677c54ed8..32e8a93f2952912e291306c4db2cc5846ef4bc84 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilder.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilder.java @@ -3,7 +3,7 @@ package de.ozgcloud.archive.historie; import java.util.Map; import java.util.Optional; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandWithPrevious; class StatusChangeHistoryBuilder extends ChangeHistoryBuilder<StatusChangeHistoryBuilder> { @@ -34,7 +34,7 @@ class StatusChangeHistoryBuilder extends ChangeHistoryBuilder<StatusChangeHistor } @Override - boolean isRelevant(Command command) { + boolean isRelevant(ArchiveManagerCommand command) { return ORDER_TO_STATUS_NAME.keySet().contains(command.getOrder()); } @@ -55,7 +55,7 @@ class StatusChangeHistoryBuilder extends ChangeHistoryBuilder<StatusChangeHistor return getStatus(commandWithPrevious.getCommand()); } - String getStatus(Command command) { + String getStatus(ArchiveManagerCommand command) { if (!ORDER_TO_STATUS_NAME.containsKey(command.getOrder())) { throw new IllegalArgumentException("Unexpected or unknown command order " + command.getOrder()); } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/VorgangChangeHistoryService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/VorgangChangeHistoryService.java index 1dba7b76084bf1e738dd9e3f970f53567255cb89..6ea510b71b985a7908bda360007144cc6fdf4afd 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/VorgangChangeHistoryService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/historie/VorgangChangeHistoryService.java @@ -7,7 +7,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandService; import de.ozgcloud.archive.common.user.UserService; import de.ozgcloud.archive.vorgang.VorgangWithEingang; @@ -32,21 +32,21 @@ class VorgangChangeHistoryService { .build(); } - Stream<VorgangChange> createStatusChangeHistory(VorgangWithEingang vorgang, List<Command> commands) { + Stream<VorgangChange> createStatusChangeHistory(VorgangWithEingang vorgang, List<ArchiveManagerCommand> commands) { return StatusChangeHistoryBuilder.builder() .withCommands(commands) .withOrganisationseinheitenID(vorgang.getOrganisationseinheitenID()) .build(); } - Stream<VorgangChange> createAktenzeichenChangeHistory(VorgangWithEingang vorgang, List<Command> commands) { + Stream<VorgangChange> createAktenzeichenChangeHistory(VorgangWithEingang vorgang, List<ArchiveManagerCommand> commands) { return AktenzeichenChangeHistoryBuilder.builder() .withCommands(commands) .withOrganisationseinheitenID(vorgang.getOrganisationseinheitenID()) .build(); } - Stream<VorgangChange> createAssignedUserChangeHistory(VorgangWithEingang vorgang, List<Command> commands) { + Stream<VorgangChange> createAssignedUserChangeHistory(VorgangWithEingang vorgang, List<ArchiveManagerCommand> commands) { return AssignedUserChangeHistoryBuilder.builder() .withCommands(commands) .withOrganisationseinheitenID(vorgang.getOrganisationseinheitenID()) diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java index 4790c966b921543e3982778cf65bf7e35b712699..147ca0b8104ef487ecbbd00a89f2e82553476561 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java @@ -15,10 +15,12 @@ import de.ozgcloud.archive.vorgang.VorgangWithEingang; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor -@Service +@Service(ArchiveManagerConfiguration.KOMMENTAR_SERVICE_NAME) public class ExportKommentarService { + @Qualifier(ArchiveManagerConfiguration.KOMMENTAR_REMOTE_SERVICE_NAME) // NOSONAR private final KommentarRemoteService kommentarRemoteService; + @Qualifier(ArchiveManagerConfiguration.BINARY_FILE_SERVICE_NAME) // NOSONAR private final BinaryFileService binaryFileService; @Qualifier(ArchiveManagerConfiguration.USER_SERVICE_NAME) // NOSONAR private final UserService userService; diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java index 0fc1e206b70090a2ab26a0714d44139c5c1bad26..f42be6e0c777fbae782c822e3cef108d7ec812f1 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java @@ -25,30 +25,28 @@ package de.ozgcloud.archive.kommentar; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemRequest; import de.ozgcloud.vorgang.vorgangAttachedItem.VorgangAttachedItemServiceGrpc.VorgangAttachedItemServiceBlockingStub; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; -@Service +@Service(ArchiveManagerConfiguration.KOMMENTAR_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class KommentarRemoteService { static final String ITEM_NAME = "Kommentar"; - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private VorgangAttachedItemServiceBlockingStub grpcService; - @Autowired - private KommentarMapper mapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) + private final VorgangAttachedItemServiceBlockingStub grpcService; + private final KommentarMapper mapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public Stream<Kommentar> findByVorgangId(String vorgangId) { var response = getGrpcServiceWithInterceptor().find(buildFindRequest(vorgangId)); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java index 26cf2d7e8d59fe78ed1a627265ac5e9a7ce15c75..6510a7cb91cde5ac1a01751cdc2b636b5696ba4e 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java @@ -28,7 +28,7 @@ import java.util.stream.Stream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import de.ozgcloud.archive.common.GrpcUtil; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.nachrichten.postfach.GrpcFindPostfachMailsRequest; import de.ozgcloud.nachrichten.postfach.PostfachServiceGrpc.PostfachServiceBlockingStub; import net.devh.boot.grpc.client.inject.GrpcClient; @@ -36,7 +36,7 @@ import net.devh.boot.grpc.client.inject.GrpcClient; @Service class PostfachMailRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) private PostfachServiceBlockingStub grpcService; @Autowired private PostfachMailMapper postfachNachrichtMapper; diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java new file mode 100644 index 0000000000000000000000000000000000000000..83e74246a033293f93b5790a2c74d50f982043ae --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java @@ -0,0 +1,105 @@ +/* + * 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.archive.vorgang; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.event.EventListener; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.stereotype.Component; + +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.attributes.ClientAttributeService; +import de.ozgcloud.archive.common.callcontext.CurrentUserService; +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandCreatedEvent; +import de.ozgcloud.command.CommandFailedEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Component() +@RequiredArgsConstructor +@Log4j2 +class ArchiveEventListener { + + private static final String LOG_MESSAGE_TEMPLATE = "{}. Command failed."; + private static final String ERROR_MESSAGE_TEMPLATE = "Error on executing %s Command (id: %s)."; + + static final String ARCHIVE_VORGANG_ORDER = "ARCHIVE_VORGANG"; + private static final String IS_ARCHIVE_VORGANG_EVENT = + "{T(de.ozgcloud.archive.vorgang.ArchiveEventListener).IS_ARCHIVE_VORGANG_COMMAND.test(event.getSource())}"; + public static final Predicate<Command> IS_ARCHIVE_VORGANG_COMMAND = command -> ARCHIVE_VORGANG_ORDER.equals(command.getOrder()); + + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + + @Qualifier(ArchiveManagerConfiguration.CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR + private final ClientAttributeService clientAttributeService; + + @Qualifier(ArchiveManagerConfiguration.VORGANG_SERVICE_NAME) // NOSONAR + private final VorgangService vorgangService; + + private final ApplicationEventPublisher eventPublisher; + + @EventListener(condition = IS_ARCHIVE_VORGANG_EVENT) + void onArchiveVorgangEvent(CommandCreatedEvent event) { + runWithSecurityContext(event.getSource(), this::doLockVorgang); + } + + void doLockVorgang(Command command) { + clientAttributeService.setVorgangArchiving(command.getVorgangId()); + vorgangService.lockVorgang(command); + } + + void runWithSecurityContext(Command command, Consumer<Command> commandExecutor) { + SecurityContext prevContext = null; + try { + prevContext = currentUserService.startAndReturnPreviousSecurityContext(command); + commandExecutor.accept(command); + } catch (Exception e) { + var errorMessage = ERROR_MESSAGE_TEMPLATE.formatted(command.getOrder(), command.getId()); + LOG.error(LOG_MESSAGE_TEMPLATE, errorMessage, e); + eventPublisher.publishEvent(new CommandFailedEvent(command.getId(), buildErrorMessage(errorMessage, e))); + } finally { + currentUserService.resetSecurityContext(prevContext); + } + } + + private String buildErrorMessage(String message, Exception cause) { + try { + StringBuilder sb = new StringBuilder(message); + if (StringUtils.isNotBlank(cause.getMessage())) { + sb.append(" Cause: ").append(cause.getMessage()); + } + return sb.toString(); + } catch (Exception e2) { + LOG.error("Error in building Error Message (sick).", e2); + return message; + } + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ExportVorgangService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ExportVorgangService.java deleted file mode 100644 index 4e3644613b0233d654d652afae09ef2c69cbaa84..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ExportVorgangService.java +++ /dev/null @@ -1,58 +0,0 @@ -package de.ozgcloud.archive.vorgang; - -import java.util.Optional; -import java.util.UUID; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.xoev.xdomea.AkteType; -import de.xoev.xdomea.AllgemeineMetadatenType; -import de.xoev.xdomea.IdentifikationObjektType; -import de.xoev.xdomea.NkAbgabeType; -import de.xoev.xdomea.VorgangType; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Service -public class ExportVorgangService { - - @Qualifier(ArchiveManagerConfiguration.VORGANG_REMOTE_MANAGER_SERVICE_NAME) // NOSONAR - private final VorgangRemoteService vorgangRemoteService; - - private final VorgangTypeCreator vorgangTypeCreator; - private final KopfCreator kopfCreator; - - public VorgangWithEingang getVorgang(String vorgangId) { - return vorgangRemoteService.findVorgangWithEingang(vorgangId); - } - - public VorgangType createVorgangType(VorgangWithEingang vorgangWithEingang) { - return vorgangTypeCreator.create(vorgangWithEingang); - } - - public NkAbgabeType createKopf(VorgangWithEingang vorgangWithEingang) { - return kopfCreator.createKopf(vorgangWithEingang); - } - - public AkteType createAkteType(VorgangWithEingang vorgangWithEingang) { - var akteType = new AkteType(); - akteType.setIdentifikation(createIdentifikationObjektType()); - akteType.setAllgemeineMetadaten(createAllgemeineMetadatenType(vorgangWithEingang)); - return akteType; - } - - IdentifikationObjektType createIdentifikationObjektType() { - var identifikationObjektType = new IdentifikationObjektType(); - identifikationObjektType.setID(UUID.randomUUID().toString()); - return identifikationObjektType; - } - - AllgemeineMetadatenType createAllgemeineMetadatenType(VorgangWithEingang vorgangWithEingang) { - var allgemeineMetadatenType = new AllgemeineMetadatenType(); - allgemeineMetadatenType.setKennzeichen(Optional.ofNullable(vorgangWithEingang.getAktenzeichen()).orElse(StringUtils.EMPTY)); - return allgemeineMetadatenType; - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java index f78836c848ab2d65bb92f2717a1578421053d224..3ae751e6d9f0131bc611195e49408948d26fc1bb 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java @@ -1,13 +1,11 @@ package de.ozgcloud.archive.vorgang; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.vorgang.GrpcFindVorgangWithEingangRequest; import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub; import lombok.RequiredArgsConstructor; @@ -17,14 +15,14 @@ import net.devh.boot.grpc.client.inject.GrpcClient; @RequiredArgsConstructor class VorgangRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private VorgangServiceBlockingStub grpcService; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final VorgangServiceBlockingStub grpcService; + @Qualifier(ArchiveManagerConfiguration.VORGANG_WITH_EINGANG_MAPPER_NAME) // NOSONAR - private VorgangWithEingangMapper vorgangWithEingangMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + private final VorgangWithEingangMapper vorgangWithEingangMapper; + + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public VorgangWithEingang findVorgangWithEingang(String vorgangId) { return vorgangWithEingangMapper diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangService.java new file mode 100644 index 0000000000000000000000000000000000000000..39b3df7a10fbcf0dc2dece9c7b04254b5c939d1d --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangService.java @@ -0,0 +1,110 @@ +package de.ozgcloud.archive.vorgang; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import de.ozgcloud.apilib.common.command.OzgCloudCommand; +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequest; +import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.apilib.user.OzgCloudUserId; +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.common.callcontext.CallContextUser; +import de.ozgcloud.archive.common.callcontext.CurrentUserService; +import de.ozgcloud.command.Command; +import de.xoev.xdomea.AkteType; +import de.xoev.xdomea.AllgemeineMetadatenType; +import de.xoev.xdomea.IdentifikationObjektType; +import de.xoev.xdomea.NkAbgabeType; +import de.xoev.xdomea.VorgangType; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service(ArchiveManagerConfiguration.VORGANG_SERVICE_NAME) // NOSONAR +public class VorgangService { + + static final String LOCK_VORGANG_ORDER = "LOCK_VORGANG"; + static final String KEY_LOCK_VORGANG_REASON = "reason"; + static final String LOCK_VORGANG_REASON = "Vorgang wird archiviert."; + static final String SUB_COMMAND_EXECUTION_MODE = "PARALLEL"; + + @Qualifier(ArchiveManagerConfiguration.VORGANG_REMOTE_MANAGER_SERVICE_NAME) // NOSONAR + private final VorgangRemoteService vorgangRemoteService; + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_COMMAND_SERVICE_NAME) // NOSONAR + private final OzgCloudCommandService ozgCloudCommandService; + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + private final CommandMapper commandMapper; + + private final VorgangTypeCreator vorgangTypeCreator; + private final KopfCreator kopfCreator; + + public VorgangWithEingang getVorgang(String vorgangId) { + return vorgangRemoteService.findVorgangWithEingang(vorgangId); + } + + public VorgangType createVorgangType(VorgangWithEingang vorgangWithEingang) { + return vorgangTypeCreator.create(vorgangWithEingang); + } + + public NkAbgabeType createKopf(VorgangWithEingang vorgangWithEingang) { + return kopfCreator.createKopf(vorgangWithEingang); + } + + public AkteType createAkteType(VorgangWithEingang vorgangWithEingang) { + var akteType = new AkteType(); + akteType.setIdentifikation(createIdentifikationObjektType()); + akteType.setAllgemeineMetadaten(createAllgemeineMetadatenType(vorgangWithEingang)); + return akteType; + } + + IdentifikationObjektType createIdentifikationObjektType() { + var identifikationObjektType = new IdentifikationObjektType(); + identifikationObjektType.setID(UUID.randomUUID().toString()); + return identifikationObjektType; + } + + AllgemeineMetadatenType createAllgemeineMetadatenType(VorgangWithEingang vorgangWithEingang) { + var allgemeineMetadatenType = new AllgemeineMetadatenType(); + allgemeineMetadatenType.setKennzeichen(Optional.ofNullable(vorgangWithEingang.getAktenzeichen()).orElse(StringUtils.EMPTY)); + return allgemeineMetadatenType; + } + + public void lockVorgang(Command command) { + ozgCloudCommandService.addSubCommands(buildCreateSubCommandsRequest(command.getId(), buildLockVorgangSubCommand(command))); + } + + OzgCloudCommand buildLockVorgangSubCommand(Command command) { + var commandBuilder = OzgCloudCommand.builder() + .order(LOCK_VORGANG_ORDER) + .vorgangId(commandMapper.toOzgCloudVorgangId(command.getVorgangId())) + .relationId(commandMapper.mapRelationId(command.getVorgangId())) + .relationVersion(command.getRelationVersion()) + .bodyObject(buildObjectBody()); + getUserId().ifPresent(commandBuilder::createdBy); + return commandBuilder.build(); + } + + Map<String, Object> buildObjectBody() { + return Map.of(KEY_LOCK_VORGANG_REASON, LOCK_VORGANG_REASON); + } + + Optional<OzgCloudUserId> getUserId() { + return currentUserService.findUser().flatMap(CallContextUser::getUserId).map(commandMapper::toOzgCloudUserId); + } + + OzgCloudCreateSubCommandsRequest buildCreateSubCommandsRequest(String parentCommandId, OzgCloudCommand command) { + return OzgCloudCreateSubCommandsRequest.builder() + .parentId(parentCommandId) + .subCommand(command) + .completedIfSubsCompleted(false) + .executionMode(SUB_COMMAND_EXECUTION_MODE) + .build(); + } + +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java index 4f1c57a4e21c095b17723896430dc67bfb25b970..c071d21507c9ca6eff5f88c682b027b3d16a049d 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java @@ -1,15 +1,57 @@ package de.ozgcloud.archive; +import java.util.TimeZone; + +import org.mapstruct.factory.Mappers; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.info.BuildProperties; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.authentication.AuthenticationTrustResolverImpl; + +import de.ozgcloud.apilib.client_attribute.grpc.OzgCloudClientAttributeMapper; +import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; +import de.ozgcloud.apilib.user.UserProfileMapper; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; +import de.ozgcloud.apilib.vorgang.grpc.OzgCloudVorgangMapper; +import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc; @SpringBootApplication @ComponentScan({ "de.ozgcloud.*" }) public class ArchiveManagerTestApplication { + @MockBean + private OzgCloudVorgangMapper vorgangMapper; + @MockBean + private VorgangServiceGrpc.VorgangServiceBlockingStub vorgangServiceStub; + @MockBean + private OzgCloudVorgangIdMapper vorgangIdMapper; + @MockBean + private UserProfileMapper userProfileMapper; + @MockBean + private OzgCloudFileMapper fileMapper; + @MockBean + private BuildProperties properties; + @MockBean + private OzgCloudClientAttributeMapper clientAttributeMapper; + public static void main(String[] args) { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); SpringApplication.run(ArchiveManagerTestApplication.class, args); } + @Bean + AuthenticationTrustResolver trustResolver() { + return new AuthenticationTrustResolverImpl(); + } + + @Bean + CommandMapper commandMapper() { + return Mappers.getMapper(CommandMapper.class); + } + } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/OzgcloudTestConfiguration.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/OzgcloudTestConfiguration.java deleted file mode 100644 index b7b9f9c88a1b1816735750a7dfe1ded355890c1c..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/OzgcloudTestConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.ozgcloud.archive; - -import org.mapstruct.factory.Mappers; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; -import de.ozgcloud.apilib.user.UserProfileMapper; -import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; -import de.ozgcloud.apilib.vorgang.grpc.OzgCloudVorgangMapper; -import de.ozgcloud.apilib.vorgang.grpc.OzgCloudVorgangStubMapper; - -@Configuration -class OzgcloudTestConfiguration { - - @Bean - @ConditionalOnMissingBean - OzgCloudVorgangMapper ozgCloudVorgangMapper() { - return Mappers.getMapper(OzgCloudVorgangMapper.class); - } - - @Bean - @ConditionalOnMissingBean - OzgCloudVorgangStubMapper ozgCloudVorgangStubMapper() { - return Mappers.getMapper(OzgCloudVorgangStubMapper.class); - } - - @Bean - @ConditionalOnMissingBean - OzgCloudVorgangIdMapper ozgCloudVorgangIdMapper() { - return Mappers.getMapper(OzgCloudVorgangIdMapper.class); - } - - @Bean - @ConditionalOnMissingBean - UserProfileMapper ozgCloudUserProfileMapper() { - return Mappers.getMapper(UserProfileMapper.class); - } - - @Bean - @ConditionalOnMissingBean - OzgCloudFileMapper fileMapper() { - return Mappers.getMapper(OzgCloudFileMapper.class); - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapperTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapperTest.java deleted file mode 100644 index 9f6b7bf30bafe159d441694294509113035ff5c1..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapperTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mapstruct.factory.Mappers; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; - -class ArchiveCallContextMapperTest { - - @InjectMocks - private final ArchiveCallContextMapper mapper = Mappers.getMapper(ArchiveCallContextMapper.class); - - @Mock - private OzgCloudUserIdMapper ozgCloudUserIdMapper; - - @Nested - class TestToOzgCloudCallContext { - - @BeforeEach - void setUpCallToUserIdMapper() { - when(ozgCloudUserIdMapper.fromString(any())).thenCallRealMethod(); - } - - @Test - void shouldMap() { - var mappedContext = mapper.toOzgCloudCallContext(ArchiveCallContextTestFactory.create()); - - assertThat(mappedContext).usingRecursiveComparison().isEqualTo(CallContextTestFactory.create()); - } - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextTestFactory.java deleted file mode 100644 index 004f98698822d130b8b91a17d0eb99025b04eed7..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextTestFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static de.ozgcloud.common.grpc.GrpcUtil.*; - -import java.util.List; -import java.util.UUID; - -import com.thedeanda.lorem.LoremIpsum; - -import de.ozgcloud.archive.common.callcontext.ArchiveCallContext.ArchiveCallContextBuilder; -import io.grpc.Metadata; - -public class ArchiveCallContextTestFactory { - - public static final String REQUEST_ID = UUID.randomUUID().toString(); - public static final String USER_ID = UUID.randomUUID().toString(); - public static final String CLIENT_NAME = LoremIpsum.getInstance().getName(); - public static final List<String> ORGANISATIONS_EINHEITEN_IDS = List.of(UUID.randomUUID().toString()); - public static final Boolean ACCESS_LIMITED = true; - - public static ArchiveCallContext create() { - return createBuilder() - .build(); - } - - public static ArchiveCallContextBuilder createBuilder() { - return ArchiveCallContext.builder() - .requestId(REQUEST_ID) - .clientName(CLIENT_NAME) - .userId(USER_ID) - .accessLimited(ACCESS_LIMITED) - .accessLimitedToOrgaIds(ORGANISATIONS_EINHEITEN_IDS); - } - - public static Metadata createMetadata() { - var metadata = new Metadata(); - metadata.put(createKeyOf(CallContextInterceptor.KEY_ACCESS_LIMITED), ACCESS_LIMITED.toString().getBytes()); - metadata.put(createKeyOf(CallContextInterceptor.KEY_ACCESS_LIMITED_ORGAID), ORGANISATIONS_EINHEITEN_IDS.get(0).getBytes()); - metadata.put(createKeyOf(CallContextInterceptor.KEY_USER_ID), USER_ID.getBytes()); - return metadata; - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptorTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..437490ce8620a3f5af6f6b587fae62e2a7e021ad --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptorTest.java @@ -0,0 +1,242 @@ +/* + * 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.archive.common.callcontext; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; +import java.util.UUID; + +import org.apache.logging.log4j.CloseableThreadContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.util.ReflectionTestUtils; + +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.Metadata; +import io.grpc.ServerCall; + +class CallContextGrpcServerInterceptorTest { + + @InjectMocks + private CallContextGrpcServerInterceptor interceptor; + + @Mock + private CurrentUserService currentUserService; + @Mock + private CallContextMapper callContextMapper; + @Mock + private ServerCall.Listener<RequestTest> callListener; + @Mock + private Metadata metadata; + + private CallContextGrpcServerInterceptor.LogContextSettingListener<RequestTest> listener; + + @BeforeEach + void init() { + listener = spy(interceptor.new LogContextSettingListener<>(callListener, metadata)); + } + + @Nested + class TestGetRequestId { + + @Test + void shouldCallGetRequestId() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + listener.getRequestId(metadata); + + grpcUtilMock.verify(() -> GrpcUtil.getRequestId(metadata)); + } + } + + @Test + void shouldGetRequestIdFromMetadata() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + var requestId = UUID.randomUUID().toString(); + grpcUtilMock.when(() -> GrpcUtil.getRequestId(any())).thenReturn(Optional.of(requestId)); + + var result = listener.getRequestId(metadata); + + assertThat(result).isEqualTo(requestId); + } + } + + @Test + void shouldReturnGeneratedId() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getRequestId(any())).thenReturn(Optional.empty()); + + var result = listener.getRequestId(metadata); + + assertThat(result).isNotEmpty(); + } + } + } + + @Nested + class TestOnMessage { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onMessage(new RequestTest()); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnHalfClose { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onHalfClose(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnCancel { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onCancel(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnComplete { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onComplete(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnReady { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onReady(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestDoSurroundOn { + + @Mock + private Runnable runnable; + + private String requestId; + + @BeforeEach + void init() { + requestId = (String) ReflectionTestUtils.getField(listener, "requestId"); + } + + @Test + void shouldSetThreadContext() { + try (var contextMock = mockStatic(CloseableThreadContext.class)) { + doSurroundOn(); + + contextMock.verify(() -> CloseableThreadContext.put(GrpcUtil.KEY_REQUEST_ID, requestId)); + } + } + + @Test + void shouldCallToCallContextMapper() { + doSurroundOn(); + + verify(callContextMapper).toCallContextUser(metadata, requestId); + } + + @Test + void shouldCallStartSecurityContext() { + var user = CallContextUserTestFactory.create(); + when(callContextMapper.toCallContextUser(any(), any())).thenReturn(user); + + doSurroundOn(); + + verify(currentUserService).startAndReturnPreviousSecurityContext(user); + } + + @Test + void shouldExecuteRunnable() { + doSurroundOn(); + + verify(runnable).run(); + } + + @Test + void shouldResetSecurityContext() { + doSurroundOn(); + + verify(currentUserService).resetSecurityContext(any()); + } + + @Test + void shouldResetSecurityContextOnException() { + doThrow(new RuntimeException()).when(runnable).run(); + + try { + doSurroundOn(); + } catch (RuntimeException e) { + // expected + } + + verify(currentUserService).resetSecurityContext(any()); + } + + private void doSurroundOn() { + listener.doSurroundOn(runnable); + } + } + + private record RequestTest() { + } + + private record ResponseTest() { + } +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptorTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptorTest.java deleted file mode 100644 index 644c95dfbb8a9b4161bf1ce709589240635c9f4b..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptorTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Spy; - -import io.grpc.Context; -import io.grpc.Contexts; -import io.grpc.Metadata; -import io.grpc.ServerCall; -import io.grpc.ServerCall.Listener; -import io.grpc.ServerCallHandler; - -class CallContextInterceptorTest { - - @Spy - private CallContextInterceptor interceptor; - - @Nested - class TestInterceptCall { - - @Mock - private ServerCall<Object, Object> call; - @Mock - private Metadata headers; - @Mock - private ServerCallHandler<Object, Object> next; - @Mock - private Context grpcContext; - @Mock - private Context newGrpcContext; - @Mock - private Listener<Object> listener; - - private MockedStatic<Context> mockedStaticContext; - - private final ArchiveCallContext archiveCallContext = ArchiveCallContextTestFactory.create(); - - @BeforeEach - void setUpMock() { - doReturn(archiveCallContext).when(interceptor).createArchiveCallContext(headers); - mockedStaticContext = mockStatic(Context.class); - mockedStaticContext.when(Context::current).thenReturn(grpcContext); - when(grpcContext.withValue(CallContextInterceptor.CONTEXT_KEY_CALL_CONTEXT, archiveCallContext)).thenReturn(newGrpcContext); - } - - @AfterEach - void closeMock() { - mockedStaticContext.close(); - } - - @Test - void shouldCreateArchiveCallContext() { - intercept(); - - verify(interceptor).createArchiveCallContext(headers); - } - - @Test - void shouldSetArchiveCallContextInGrpcContext() { - intercept(); - - verify(grpcContext).withValue(CallContextInterceptor.CONTEXT_KEY_CALL_CONTEXT, archiveCallContext); - } - - @Test - void shouldAttachNewGrpcContextToCall() { - try (var mockedStaticContexts = mockStatic(Contexts.class)) { - intercept(); - - mockedStaticContexts.verify(() -> Contexts.interceptCall(newGrpcContext, call, headers, next)); - } - } - - @Test - void shouldReturnListenerWithAttachedGrpcContext() { - try (var mockedStaticContexts = mockStatic(Contexts.class)) { - mockedStaticContexts.when(() -> Contexts.interceptCall(newGrpcContext, call, headers, next)).thenReturn(listener); - - var returnedListener = intercept(); - - assertThat(returnedListener).isEqualTo(listener); - } - } - - private Listener<Object> intercept() { - return interceptor.interceptCall(call, headers, next); - } - } - - @Nested - class TestCreateArchiveCallContext { - - @Test - void shouldCreateArchiveCallContext() { - var archiveCallContext = callInterceptor(); - - assertThat(archiveCallContext).usingRecursiveComparison().ignoringFields("requestId") - .isEqualTo(ArchiveCallContextTestFactory.createBuilder() - .clientName(ArchiveCallContext.CLIENT_NAME) - .build()); - } - - @Test - void shouldHaveRequestId() { - var archiveCallContext = callInterceptor(); - - assertThat(archiveCallContext.getRequestId()).isNotBlank(); - } - - private ArchiveCallContext callInterceptor() { - return interceptor.createArchiveCallContext(ArchiveCallContextTestFactory.createMetadata()); - } - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java index 6abea45385afc05903fad1155b64e3908e5db0b6..a396a5ea1b771ad31953a07a03b837c195853330 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java @@ -19,38 +19,38 @@ class CallContextProviderTest { private CallContextProvider contextProvider; @Mock - private ArchiveCallContextMapper mapper; + private CallContextMapper mapper; @Mock - private GrpcCallContextSupplier contextSupplier; + private CurrentUserService currentUserService; @Nested class TestProvideContext { - private final ArchiveCallContext archiveCallContext = ArchiveCallContextTestFactory.create(); + private final CallContextUser callContextUser = CallContextUserTestFactory.create(); @BeforeEach void mock() { - when(contextSupplier.get()).thenReturn(archiveCallContext); + when(currentUserService.getUser()).thenReturn(callContextUser); } @Test void shouldGetArchiveCallContextFromGrpcContext() { callProvider(); - verify(contextSupplier).get(); + verify(currentUserService).getUser(); } @Test void shouldMapArchiveCallContext() { callProvider(); - verify(mapper).toOzgCloudCallContext(archiveCallContext); + verify(mapper).toOzgCloudCallContext(callContextUser); } @Test void shouldReturnMappedCallContext() { var mappedCallContext = CallContextTestFactory.create(); - when(mapper.toOzgCloudCallContext(archiveCallContext)).thenReturn(mappedCallContext); + when(mapper.toOzgCloudCallContext(callContextUser)).thenReturn(mappedCallContext); var context = callProvider(); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java index f6886e13340b0efb58c9abc42dff50334b30ccb4..922d37fa72bc5dc45ac97e9f49193cf227d77cbf 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java @@ -1,6 +1,6 @@ package de.ozgcloud.archive.common.callcontext; -import java.util.Collection; +import java.util.List; import de.ozgcloud.apilib.common.callcontext.CallContext; import de.ozgcloud.apilib.common.callcontext.CallContext.CallContextBuilder; @@ -8,11 +8,11 @@ import de.ozgcloud.apilib.user.OzgCloudUserId; public class CallContextTestFactory { - public static final String REQUEST_ID = ArchiveCallContextTestFactory.REQUEST_ID; - public static final OzgCloudUserId USER_ID = OzgCloudUserId.from(ArchiveCallContextTestFactory.USER_ID); - public static final String CLIENT_NAME = ArchiveCallContextTestFactory.CLIENT_NAME; - private static final Collection<? extends String> ORGANISATIONS_EINHEITEN_IDS = ArchiveCallContextTestFactory.ORGANISATIONS_EINHEITEN_IDS; - private static final boolean ACCESS_LIMITED = ArchiveCallContextTestFactory.ACCESS_LIMITED; + public static final String REQUEST_ID = CallContextUserTestFactory.REQUEST_ID; + public static final OzgCloudUserId USER_ID = OzgCloudUserId.from(CallContextUserTestFactory.USER_ID); + public static final String CLIENT_NAME = CallContextUserTestFactory.CLIENT_NAME; + public static final String ORGANISATIONS_EINHEITEN_ID = CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID; + public static final boolean ACCESS_LIMITED = CallContextUserTestFactory.ACCESS_LIMITED; public static CallContext create() { return createBuilder() @@ -25,6 +25,6 @@ public class CallContextTestFactory { .clientName(CLIENT_NAME) .userId(USER_ID) .accessLimited(ACCESS_LIMITED) - .accessLimitedToOrgaIds(ORGANISATIONS_EINHEITEN_IDS); + .accessLimitedToOrgaIds(List.of(ORGANISATIONS_EINHEITEN_ID)); } } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserMapperTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5150f31c021c766130b21ecb1386bbb666b030e8 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserMapperTest.java @@ -0,0 +1,132 @@ +package de.ozgcloud.archive.common.callcontext; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.Metadata; + +class CallContextUserMapperTest { + + @InjectMocks + private final CallContextMapper mapper = Mappers.getMapper(CallContextMapper.class); + + @Mock + private OzgCloudUserIdMapper ozgCloudUserIdMapper; + + @Nested + class TestToOzgCloudCallContext { + + @BeforeEach + void setUpCallToUserIdMapper() { + when(ozgCloudUserIdMapper.fromString(any(Optional.class))).thenReturn(CallContextTestFactory.USER_ID); + } + + @Test + void shouldMap() { + var mappedContext = CallContextTestFactory.createBuilder().clientName(CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME).build(); + + var result = mapper.toOzgCloudCallContext(CallContextUserTestFactory.create()); + + assertThat(result).usingRecursiveComparison().isEqualTo(mappedContext); + } + } + + @Nested + class TestToCallContextUser { + + @Mock + private Metadata headers; + + @Test + void shouldMapRequestId() { + var result = toCallContextUser(); + + assertThat(result.getRequestId()).isSameAs(CallContextUserTestFactory.REQUEST_ID); + } + + @Test + void shouldMapClientName() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getClientName(headers)).thenReturn(Optional.of(CallContextUserTestFactory.CLIENT_NAME)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getClientName(headers)); + assertThat(result.getClientName()).isSameAs(CallContextUserTestFactory.CLIENT_NAME); + } + } + + @Test + void shouldMapUserId() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getUserId(headers)).thenReturn(Optional.of(CallContextUserTestFactory.USER_ID)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getUserId(headers)); + assertThat(result.getUserId()).contains(CallContextUserTestFactory.USER_ID); + + } + } + + @Test + void shouldMapUserName() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getUserName(headers)).thenReturn(Optional.of(CallContextUserTestFactory.USER_NAME)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getUserName(headers)); + assertThat(result.getUserName()).contains(CallContextUserTestFactory.USER_NAME); + } + } + + @Test + void shouldMapAccessLimited() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getAccessLimited(headers)).thenReturn(Optional.of(CallContextUserTestFactory.ACCESS_LIMITED)); + grpcUtilMock.when(() -> GrpcUtil.getAccessLimitedOrgaIds(headers)) + .thenReturn(List.of(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getAccessLimited(headers)); + grpcUtilMock.verify(() -> GrpcUtil.getAccessLimitedOrgaIds(headers)); + assertThat(result.isAccessLimited()).isEqualTo(CallContextUserTestFactory.ACCESS_LIMITED); + assertThat(result.getAccessLimitedToOrgaIds()).containsExactly(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID); + } + } + + @Test + void shouldMapNoAccessLimited() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getAccessLimited(any())).thenReturn(Optional.empty()); + grpcUtilMock.when(() -> GrpcUtil.getAccessLimitedOrgaIds(any())) + .thenReturn(List.of(CallContextTestFactory.ORGANISATIONS_EINHEITEN_ID)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getAccessLimited(headers)); + assertThat(result.isAccessLimited()).isFalse(); + assertThat(result.getAccessLimitedToOrgaIds()).isEmpty(); + } + } + + private CallContextUser toCallContextUser() { + return mapper.toCallContextUser(headers, CallContextUserTestFactory.REQUEST_ID); + } + } +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..f91d32af84e6ac4de855e6e91420ec3675ff08e4 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserTestFactory.java @@ -0,0 +1,35 @@ +package de.ozgcloud.archive.common.callcontext; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.archive.common.callcontext.CallContextUser.CallContextUserBuilder; + +public class CallContextUserTestFactory { + + public static final String REQUEST_ID = UUID.randomUUID().toString(); + public static final String USER_ID = UUID.randomUUID().toString(); + public static final String USER_NAME = LoremIpsum.getInstance().getName(); + public static final String CLIENT_NAME = LoremIpsum.getInstance().getName(); + public static final String ORGANISATIONS_EINHEITEN_ID = UUID.randomUUID().toString(); + public static final Boolean ACCESS_LIMITED = true; + + public static CallContextUser create() { + return createBuilder() + .build(); + } + + public static CallContextUserBuilder createBuilder() { + return CallContextUser.builder() + .requestId(REQUEST_ID) + .clientName(CLIENT_NAME) + .userId(Optional.of(USER_ID)) + .userName(Optional.of(USER_NAME)) + .accessLimited(ACCESS_LIMITED) + .accessLimitedToOrgaIds(List.of(ORGANISATIONS_EINHEITEN_ID)); + } + +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CurrentUserServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CurrentUserServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2ada38a29b5b6dd1fb78f9655786f6c4b9f727c6 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CurrentUserServiceTest.java @@ -0,0 +1,499 @@ +/* + * 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.archive.common.callcontext; + +import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.apache.logging.log4j.ThreadContext; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Spy; +import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandTestFactory; +import de.ozgcloud.common.grpc.GrpcUtil; + +class CurrentUserServiceTest { + + @Spy + @InjectMocks + private CurrentUserService service; + + @Mock + private AuthenticationTrustResolver trustResolver; + + @Nested + class TestGetUser { + + @Test + void shouldCallFindUser() { + doReturn(Optional.of(CallContextUserTestFactory.create())).when(service).findUser(); + + service.getUser(); + + verify(service).findUser(); + } + + @Test + void shouldReturnUser() { + var user = CallContextUserTestFactory.create(); + doReturn(Optional.of(user)).when(service).findUser(); + + var result = service.getUser(); + + assertThat(result).isSameAs(user); + } + + @Test + void shouldThrowException() { + doReturn(Optional.empty()).when(service).findUser(); + + assertThatThrownBy(service::getUser).isInstanceOf(IllegalStateException.class); + } + } + + @Nested + class TestFindUser { + + @Mock + private Authentication auth; + + @BeforeEach + void init() { + doReturn(Optional.of(auth)).when(service).findTrustedAuthentication(); + } + + @Test + void shouldCallFindTrustedAuthentication() { + service.findUser(); + + verify(service).findTrustedAuthentication(); + } + + @Test + void shouldCallMapToCallContextUser() { + service.findUser(); + + verify(service).mapToCallContextUser(auth); + } + + @Test + void shouldReturnUser() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).mapToCallContextUser(auth); + + var result = service.findUser(); + + assertThat(result).contains(user); + } + + @Test + void shouldFilterEmptyClientName() { + doReturn(CallContextUserTestFactory.createBuilder().clientName(null).build()).when(service).mapToCallContextUser(auth); + + var result = service.findUser(); + + assertThat(result).isEmpty(); + } + } + + @Nested + class TestMapToCallContextUser { + + @Mock + private Authentication auth; + + @Test + void shouldReturnUser() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).buildDefaultCallContextUser(any()); + + var result = service.mapToCallContextUser(auth); + + assertThat(result).isSameAs(user); + } + + @Test + void shouldCallBuildDefaultCallContextUser() { + service.mapToCallContextUser(auth); + + verify(service).buildDefaultCallContextUser(auth); + } + + @Test + void shouldReturnDefaultUser() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).buildDefaultCallContextUser(auth); + + var result = service.mapToCallContextUser(auth); + + assertThat(result).isSameAs(user); + } + } + + @Nested + class TestBuildDefaultCallContextUser { + + @Mock + private Authentication auth; + @Mock + private GrantedAuthority grantedAuthority; + + @Test + void shouldSetClientName() { + doReturn(CallContextUserTestFactory.CLIENT_NAME).when(auth).getName(); + + var result = service.buildDefaultCallContextUser(auth); + + assertThat(result.getClientName()).isEqualTo(CallContextUserTestFactory.CLIENT_NAME); + } + + @Test + void shouldSetAccessLimited() { + when(grantedAuthority.getAuthority()).thenReturn(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID); + doReturn(List.of(grantedAuthority)).when(auth).getAuthorities(); + + var user = service.buildDefaultCallContextUser(auth); + + assertThat(user.getAccessLimitedToOrgaIds()).asInstanceOf(InstanceOfAssertFactories.LIST) + .containsExactly(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID); + } + + } + + @Nested + class TestFindAuthentication { + + @Mock + private Authentication auth; + + @Test + void shouldCallFindTrustedAuthentication() { + service.findAuthentication(); + + verify(service).findTrustedAuthentication(); + } + + @Test + void shouldReturnAuthentication() { + doReturn(Optional.of(auth)).when(service).findTrustedAuthentication(); + + var result = service.findAuthentication(); + + assertThat(result).contains(auth); + } + } + + @Nested + class TestFindTrustedAuthentication { + + @Mock + private SecurityContext context; + @Mock + private Authentication auth; + + private MockedStatic<SecurityContextHolder> contextHolderMock; + + @BeforeEach + void init() { + contextHolderMock = mockStatic(SecurityContextHolder.class); + contextHolderMock.when(SecurityContextHolder::getContext).thenReturn(context); + when(context.getAuthentication()).thenReturn(auth); + } + + @AfterEach + void cleanup() { + contextHolderMock.close(); + } + + @Test + void shouldCallGetContext() { + service.findTrustedAuthentication(); + + contextHolderMock.verify(SecurityContextHolder::getContext); + } + + @Test + void shouldCallGetAuthentication() { + service.findTrustedAuthentication(); + + verify(context).getAuthentication(); + } + + @Test + void shouldCallIsAnonymous() { + service.findTrustedAuthentication(); + + verify(trustResolver).isAnonymous(auth); + } + + @Test + void shouldCallIsAuthenticated() { + service.findTrustedAuthentication(); + + verify(auth).isAuthenticated(); + } + + @Test + void shouldFilterAnonymous() { + when(trustResolver.isAnonymous(any())).thenReturn(true); + + var result = service.findTrustedAuthentication(); + + assertThat(result).isEmpty(); + verify(auth, never()).isAuthenticated(); + } + + @Test + void shouldFilterNotAuthenticated() { + doReturn(false).when(trustResolver).isAnonymous(auth); + doReturn(false).when(auth).isAuthenticated(); + + var result = service.findTrustedAuthentication(); + + assertThat(result).isEmpty(); + } + } + + @DisplayName("Create user") + @Nested + class TestCreateUser { + + @Test + void shouldSetUserId() { + var user = service.createUser(CommandTestFactory.create()); + + assertThat(user.getUserId()).contains(CommandTestFactory.CREATED_BY); + } + + @Test + void shouldSetUserName() { + var createdByName = "user-name"; + + var user = service.createUser(CommandTestFactory.createBuilder().createdByName(createdByName).build()); + + assertThat(user.getUserName()).contains(createdByName); + } + + @Test + void shouldSetClientName() { + var clientName = "client"; + + var user = service.createUser(CommandTestFactory.createBuilder().createdByClientName(clientName).build()); + + assertThat(user.getClientName()).isEqualTo(clientName); + } + + @Test + void shouldSetAccessLimited() { + var user = service.createUser(CommandTestFactory.create()); + + assertThat(user.isAccessLimited()).isFalse(); + } + + @Test + void shouldCallGetRequestId() { + service.createUser(CommandTestFactory.create()); + + verify(service).getRequestId(); + } + + @Test + void shouldSetRequestId() { + var requestId = UUID.randomUUID().toString(); + doReturn(requestId).when(service).getRequestId(); + + var user = service.createUser(CommandTestFactory.create()); + + assertThat(user.getRequestId()).isEqualTo(requestId); + } + } + + @Nested + class TestGetRequestId { + + @Test + void shouldReturnRequestId() { + var requestId = UUID.randomUUID().toString(); + try (var contextMock = mockStatic(ThreadContext.class)) { + contextMock.when(ThreadContext::getContext).thenReturn(Map.of(GrpcUtil.KEY_REQUEST_ID, requestId)); + + var result = service.getRequestId(); + + assertThat(result).isEqualTo(requestId); + } + } + + @Test + void shouldReturnNewRequestId() { + try (var ctc = mockStatic(ThreadContext.class)) { + ctc.when(ThreadContext::getContext).thenReturn(Collections.emptyMap()); + + var result = service.getRequestId(); + + assertThat(result).isNotEmpty(); + } + } + } + + @Nested + class TestStartAndReturnPreviousSecurityContext { + + @Nested + class TestWithCommand { + + private static final Command COMMAND = CommandTestFactory.create(); + + @Mock + private SecurityContext securityContext; + + @Test + void shouldCallCreateUser() { + startAndReturnPreviousSecurityContext(); + + verify(service).createUser(COMMAND); + } + + @Test + void shouldCallStartAndReturnPreviousSecurityContext() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).createUser(any()); + + startAndReturnPreviousSecurityContext(); + + verify(service).startAndReturnPreviousSecurityContext(user); + } + + @Test + void shouldReturnContext() { + doReturn(securityContext).when(service).startAndReturnPreviousSecurityContext(any(CallContextUser.class)); + + var result = startAndReturnPreviousSecurityContext(); + + assertThat(result).isSameAs(securityContext); + } + + private SecurityContext startAndReturnPreviousSecurityContext() { + return service.startAndReturnPreviousSecurityContext(COMMAND); + } + } + + @Nested + class TestWithCallContextUser { + + private final CallContextUser newUser = CallContextUserTestFactory.create(); + private final CallContextAuthenticationToken newAuthentication = CallContextAuthenticationToken.authenticate(newUser); + + @Mock + private SecurityContext previousSecurityContext; + + @BeforeEach + void init() { + SecurityContextHolder.setContext(previousSecurityContext); + } + + @Test + void shouldReturnPreviousSecurityContext() { + var returnedContext = startAndReturnPreviousSecurityContext(); + + assertThat(returnedContext).isSameAs(previousSecurityContext); + } + + @Test + void shouldSetContextWithNewUser() { + startAndReturnPreviousSecurityContext(); + + var currentAuthentication = SecurityContextHolder.getContext().getAuthentication(); + assertThat(currentAuthentication).usingRecursiveComparison().isEqualTo(newAuthentication); + } + + private SecurityContext startAndReturnPreviousSecurityContext() { + return service.startAndReturnPreviousSecurityContext(newUser); + } + } + } + + @Nested + class TestResetSecurityContext { + + @Mock + private SecurityContext securityContext; + + private MockedStatic<SecurityContextHolder> contextHolderMock; + + @BeforeEach + void init() { + contextHolderMock = mockStatic(SecurityContextHolder.class); + } + + @AfterEach + void cleanup() { + contextHolderMock.close(); + } + + @Test + void shouldClearContext() { + resetSecurityContext(); + + contextHolderMock.verify(SecurityContextHolder::clearContext); + } + + @Test + void shouldSetContext() { + resetSecurityContext(); + + contextHolderMock.verify(() -> SecurityContextHolder.setContext(securityContext)); + } + + @Test + void shouldNotSetContext() { + service.resetSecurityContext(null); + + contextHolderMock.verify(() -> SecurityContextHolder.setContext(any()), never()); + } + + private void resetSecurityContext() { + service.resetSecurityContext(securityContext); + } + } +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandTestFactory.java index bb508d79448427d869ede6808be0f48c0a883136..a9ce69fe415db37f2f86998df7a5f707bdf4edef 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandTestFactory.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandTestFactory.java @@ -5,7 +5,7 @@ import java.util.Map; import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.archive.common.command.Command.CommandBuilder; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand.ArchiveManagerCommandBuilder; import de.ozgcloud.archive.common.user.UserProfileTestFactory; public class CommandTestFactory { @@ -20,13 +20,13 @@ public class CommandTestFactory { public static final String VALUE_2 = LoremIpsum.getInstance().getWords(1); public static final Map<String, Object> BODY = Map.of(PROPERTY_1, VALUE_1, PROPERTY_2, VALUE_2); - public static Command create() { + public static ArchiveManagerCommand create() { return createBuilder() .build(); } - public static CommandBuilder createBuilder() { - return Command.builder().body(BODY) + public static ArchiveManagerCommandBuilder createBuilder() { + return ArchiveManagerCommand.builder().body(BODY) .finishedAt(FINISHED_AT) .createdByName(CREATED_BY_NAME) .order(ORDER); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandWithPreviousTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandWithPreviousTestFactory.java index 49e257850ea218c46d987be288e7d9bc81c27c79..588cbcae2eae704aa39d4ad5e834204cd7645330 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandWithPreviousTestFactory.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandWithPreviousTestFactory.java @@ -4,8 +4,8 @@ import de.ozgcloud.archive.common.command.CommandWithPrevious.CommandWithPreviou public class CommandWithPreviousTestFactory { - public static final Command COMMAND = CommandTestFactory.create(); - public static final Command PREVIOUS_COMMAND = CommandTestFactory.create(); + public static final ArchiveManagerCommand COMMAND = CommandTestFactory.create(); + public static final ArchiveManagerCommand PREVIOUS_COMMAND = CommandTestFactory.create(); public static CommandWithPrevious create() { return createBuilder().build(); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java index 4cd7e987ec6d1f04d39054a83746f32c517d4775..713288dd1158fab2bf9c57877ae729b067e02681 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java @@ -1,11 +1,13 @@ package de.ozgcloud.archive.export; import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Iterator; @@ -13,13 +15,13 @@ import java.util.stream.Stream; import java.util.zip.ZipInputStream; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import com.thedeanda.lorem.LoremIpsum; @@ -29,7 +31,7 @@ import de.ozgcloud.archive.common.binaryfile.BinaryFileService; import de.ozgcloud.archive.common.user.UserProfileTestFactory; import de.ozgcloud.archive.common.user.UserService; import de.ozgcloud.archive.file.ExportFileService; -import de.ozgcloud.archive.grpc.export.ExportServiceGrpc; +import de.ozgcloud.archive.grpc.export.ExportServiceGrpc.ExportServiceBlockingStub; import de.ozgcloud.archive.grpc.export.GrpcExportVorgangRequest; import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse; import de.ozgcloud.archive.historie.ExportHistorieService; @@ -39,7 +41,7 @@ import de.ozgcloud.archive.kommentar.KommentarsExportData; import de.ozgcloud.archive.kommentar.KommentarsExportDataTestFactory; import de.ozgcloud.archive.postfach.ExportNachrichtService; import de.ozgcloud.archive.postfach.PostfachMailExportData; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangTypeTestFactory; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; @@ -51,18 +53,17 @@ import net.devh.boot.grpc.client.inject.GrpcClient; "grpc.server.inProcessName=GrpcExportService-test", "grpc.client.inProcess.address=in-process:GrpcExportService-test" }) -@SpringJUnitConfig(classes = { GrpcIntegrationTestConfiguration.class }) @ITCase @DirtiesContext class ExportGrpcServiceITCase { @GrpcClient("inProcess") - private ExportServiceGrpc.ExportServiceBlockingStub clientService; + private ExportServiceBlockingStub serviceStub; @MockBean private ExportFileService exportFileService; @MockBean - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @MockBean private ExportHistorieService exportHistorieService; @MockBean @@ -84,15 +85,15 @@ class ExportGrpcServiceITCase { @BeforeEach void setUpCommonMocks() { - when(exportVorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); + when(vorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); when(exportNachrichtService.createExportData(vorgang)).thenReturn(PostfachMailExportData.builder().build()); when(exportBescheidService.createExportData(vorgang)).thenReturn(BescheidExportData.builder().build()); when(exportFileService.getRepresentations(vorgang)).thenReturn(Stream.empty()); when(exportFileService.getAttachments(vorgang)).thenReturn(Stream.empty()); - when(exportVorgangService.createKopf(vorgang)).thenReturn(NkAbgabeTypeTestFactory.create()); - when(exportVorgangService.createVorgangType(vorgang)).thenReturn(VorgangTypeTestFactory.create()); - when(exportVorgangService.createAkteType(vorgang)).thenReturn(AkteTypeTestFactory.create()); + when(vorgangService.createKopf(vorgang)).thenReturn(NkAbgabeTypeTestFactory.create()); + when(vorgangService.createVorgangType(vorgang)).thenReturn(VorgangTypeTestFactory.create()); + when(vorgangService.createAkteType(vorgang)).thenReturn(AkteTypeTestFactory.create()); } @@ -107,7 +108,7 @@ class ExportGrpcServiceITCase { @Test @SneakyThrows void shouldHaveOneZipEntry() { - var response = callService(); + var response = exportVorgang(); int numEntry; try (var outputStream = new ByteArrayOutputStream()) { @@ -121,7 +122,7 @@ class ExportGrpcServiceITCase { @Test @SneakyThrows void shouldContainVorgangKopfDataInXml() { - var response = callService(); + var response = exportVorgang(); var content = new String[2]; try (var outputStream = new ByteArrayOutputStream()) { @@ -154,7 +155,7 @@ class ExportGrpcServiceITCase { @Test @SneakyThrows void shouldHaveTwoZipEntries() { - var response = callService(); + var response = exportVorgang(); int numEntry; try (var outputStream = new ByteArrayOutputStream()) { @@ -168,7 +169,7 @@ class ExportGrpcServiceITCase { @Test @SneakyThrows void shouldHaveKommentarAttachment() { - var response = callService(); + var response = exportVorgang(); String[] content = new String[2]; try (var outputStream = new ByteArrayOutputStream()) { @@ -183,7 +184,14 @@ class ExportGrpcServiceITCase { @SneakyThrows private void collectResponseInStream(Iterator<GrpcExportVorgangResponse> response, ByteArrayOutputStream outputStream) { while (response.hasNext()) { - outputStream.write(response.next().getVorgangFile().getFileContent().toByteArray()); + var next = response.next(); + if (StringUtils.EMPTY.equals(next.getVorgangFile().getFileName())) { + try { + outputStream.write(next.getVorgangFile().getFileContent().toByteArray()); + } catch (IOException e) { + fail(e); + } + } } } @@ -211,8 +219,8 @@ class ExportGrpcServiceITCase { } } - private Iterator<GrpcExportVorgangResponse> callService() { - return clientService.exportVorgang(request); + private Iterator<GrpcExportVorgangResponse> exportVorgang() { + return serviceStub.exportVorgang(request); } } -} +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java index d085f3d41f19d41bcaa323dbe984f95cebb739f0..74b813c3d8ecb10ffd58e0dde14d1f25e818f977 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java @@ -30,7 +30,7 @@ import de.ozgcloud.archive.postfach.ExportNachrichtService; import de.ozgcloud.archive.postfach.PostfachMail; import de.ozgcloud.archive.postfach.PostfachMailExportDataTestFactory; import de.ozgcloud.archive.postfach.PostfachMailTestFactory; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; import de.ozgcloud.common.test.ITCase; @@ -41,7 +41,7 @@ class ExportServiceITCase { @SpyBean private ExportFileService exportFileService; @SpyBean - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @MockBean private ExportHistorieService exportHistorieService; @MockBean @@ -66,7 +66,7 @@ class ExportServiceITCase { @BeforeEach void setup() { - doReturn(vorgang).when(exportVorgangService).getVorgang(VorgangWithEingangTestFactory.ID); + doReturn(vorgang).when(vorgangService).getVorgang(VorgangWithEingangTestFactory.ID); doReturn(Stream.of(OzgFileTestFactory.createWithUniqueId())).when(exportFileService).getRepresentations(vorgang); doReturn(Stream.of(OzgFileTestFactory.createWithUniqueId())).when(exportFileService).getAttachments(vorgang); doReturn(Stream.of(OzgFileTestFactory.createWithUniqueId())).when(binaryFileService).getFiles(postfachMail.getAttachments()); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java index 4e6039ba992fe23de31c6d77faedc1a44efdc11b..aeaa5059a05bf4f2910605774fcbe2b5cf38087e 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java @@ -43,7 +43,7 @@ import de.ozgcloud.archive.postfach.PostfachMailExportData; import de.ozgcloud.archive.postfach.PostfachMailExportDataTestFactory; import de.ozgcloud.archive.vorgang.EingangHeaderTestFactory; import de.ozgcloud.archive.vorgang.EingangTestFactory; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangTypeTestFactory; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; @@ -68,7 +68,7 @@ class ExportServiceTest { @Mock private ExportFileService exportFileService; @Mock - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @Mock private ExportHistorieService exportHistorieService; @Mock @@ -155,10 +155,10 @@ class ExportServiceTest { } private void setUpVorgangService() { - when(exportVorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); - when(exportVorgangService.createVorgangType(vorgang)).thenReturn(vorgangType); - when(exportVorgangService.createKopf(vorgang)).thenReturn(kopfType); - when(exportVorgangService.createAkteType(vorgang)).thenReturn(akteType); + when(vorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); + when(vorgangService.createVorgangType(vorgang)).thenReturn(vorgangType); + when(vorgangService.createKopf(vorgang)).thenReturn(kopfType); + when(vorgangService.createAkteType(vorgang)).thenReturn(akteType); } private void setUpXdomeaNachrichtBuilder() { @@ -213,7 +213,7 @@ class ExportServiceTest { void shouldLoadVorgang() { callService(); - verify(exportVorgangService).getVorgang(VorgangWithEingangTestFactory.ID); + verify(vorgangService).getVorgang(VorgangWithEingangTestFactory.ID); } @Test @@ -241,14 +241,14 @@ class ExportServiceTest { void shouldCreateKopf() { callService(); - verify(exportVorgangService).createKopf(vorgang); + verify(vorgangService).createKopf(vorgang); } @Test void shouldCreateVorgangType() { callService(); - verify(exportVorgangService).createVorgangType(vorgang); + verify(vorgangService).createVorgangType(vorgang); } @Test @@ -276,7 +276,7 @@ class ExportServiceTest { void shouldCreateAkteType() { callService(); - verify(exportVorgangService).createAkteType(vorgang); + verify(vorgangService).createAkteType(vorgang); } @Test diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/GrpcIntegrationTestConfiguration.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/GrpcIntegrationTestConfiguration.java index 72f2dff37a4cb92d7afac10f8090bdad7166db47..0079cfeda7a15e8fd7b6de64f5a2df302d27268e 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/GrpcIntegrationTestConfiguration.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/GrpcIntegrationTestConfiguration.java @@ -17,4 +17,4 @@ import net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguratio @ComponentScan({ "de.ozgcloud.*" }) public class GrpcIntegrationTestConfiguration { -} +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilderTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilderTest.java index 7498a37edac3c09a7a762fad33cefd04f057bf86..5916666dfdbc625f4ba3ce40b8545c7bd9f6a058 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilderTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AktenzeichenChangeHistoryBuilderTest.java @@ -16,7 +16,7 @@ import org.mockito.Spy; import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandTestFactory; import de.ozgcloud.archive.common.command.CommandWithPrevious; import de.ozgcloud.archive.common.command.CommandWithPreviousTestFactory; @@ -25,9 +25,9 @@ public class AktenzeichenChangeHistoryBuilderTest { private static final String ORGANISATIONSEINHEITEN_ID = UUID.randomUUID().toString(); - private final Command previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); - private final Command command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); - private final List<Command> commands = List.of(previousCommand, command); + private final ArchiveManagerCommand previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); + private final ArchiveManagerCommand command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); + private final List<ArchiveManagerCommand> commands = List.of(previousCommand, command); @Spy private AktenzeichenChangeHistoryBuilder builder = AktenzeichenChangeHistoryBuilder.builder() diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilderTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilderTest.java index 361fb909f335d83ea420a135fc4791ee1be7bae9..a29a29cb3408fb65e9329430d76efbd7967f9679 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilderTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/AssignedUserChangeHistoryBuilderTest.java @@ -18,7 +18,7 @@ import org.mockito.Spy; import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandTestFactory; import de.ozgcloud.archive.common.command.CommandWithPrevious; import de.ozgcloud.archive.common.command.CommandWithPreviousTestFactory; @@ -29,9 +29,9 @@ public class AssignedUserChangeHistoryBuilderTest { private static final String ORGANISATIONSEINHEITEN_ID = UUID.randomUUID().toString(); - private final Command previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); - private final Command command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); - private final List<Command> commands = List.of(previousCommand, command); + private final ArchiveManagerCommand previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); + private final ArchiveManagerCommand command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); + private final List<ArchiveManagerCommand> commands = List.of(previousCommand, command); @Mock private UserProfileCache userProfileCache; @@ -193,7 +193,7 @@ public class AssignedUserChangeHistoryBuilderTest { private static final String USER_ID = UUID.randomUUID().toString(); private static final UserProfile USER_PROFILE = UserProfileTestFactory.create(); - private final Command command = previousCommand; + private final ArchiveManagerCommand command = previousCommand; @BeforeEach void init() { diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/ChangeHistoryBuilderTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/ChangeHistoryBuilderTest.java index 2a749f303c547ea56dd0e8fa402c9cbbeed41646..0011d609a7a016f94e06ec10b49f6be90f65b4d8 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/ChangeHistoryBuilderTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/ChangeHistoryBuilderTest.java @@ -23,7 +23,7 @@ import org.testcontainers.shaded.org.apache.commons.lang3.NotImplementedExceptio import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandTestFactory; import de.ozgcloud.archive.common.command.CommandWithPrevious; import de.ozgcloud.archive.common.command.CommandWithPreviousTestFactory; @@ -34,9 +34,9 @@ public class ChangeHistoryBuilderTest { private static final String ORGANISATIONSEINHEITEN_ID = UUID.randomUUID().toString(); - private final Command previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); - private final Command command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); - private final List<Command> commands = List.of(previousCommand, command); + private final ArchiveManagerCommand previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); + private final ArchiveManagerCommand command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); + private final List<ArchiveManagerCommand> commands = List.of(previousCommand, command); @Spy private TestChangeHistoryBuilder builder = new TestChangeHistoryBuilder() @@ -97,7 +97,7 @@ public class ChangeHistoryBuilderTest { @Nested class TestInChronologicalOrder { - private final Stream<Command> unorderedCommands = Stream.of(command, previousCommand); + private final Stream<ArchiveManagerCommand> unorderedCommands = Stream.of(command, previousCommand); @Test void shouldSortAscendingByFinishedAt() { @@ -257,7 +257,7 @@ public class ChangeHistoryBuilderTest { } } - static Command commandFinishedAt(LocalDateTime finishedAt) { + static ArchiveManagerCommand commandFinishedAt(LocalDateTime finishedAt) { return CommandTestFactory.createBuilder() .finishedAt(ZonedDateTime.of(finishedAt, ZoneId.of("UTC"))) .build(); @@ -266,7 +266,7 @@ public class ChangeHistoryBuilderTest { private static class TestChangeHistoryBuilder extends ChangeHistoryBuilder<TestChangeHistoryBuilder> { @Override - boolean isRelevant(Command command) { + boolean isRelevant(ArchiveManagerCommand command) { throw new NotImplementedException(); } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilderTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilderTest.java index 947d8783c6d0a979b49a50c687ed373460f3bdd0..be6c61ce8b125f0c9a165f8ff20203464133a08a 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilderTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/StatusChangeHistoryBuilderTest.java @@ -17,7 +17,7 @@ import org.mockito.Spy; import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandTestFactory; import de.ozgcloud.archive.common.command.CommandWithPrevious; import de.ozgcloud.archive.common.command.CommandWithPreviousTestFactory; @@ -26,9 +26,9 @@ public class StatusChangeHistoryBuilderTest { private static final String ORGANISATIONSEINHEITEN_ID = UUID.randomUUID().toString(); - private final Command previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); - private final Command command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); - private final List<Command> commands = List.of(previousCommand, command); + private final ArchiveManagerCommand previousCommand = commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); + private final ArchiveManagerCommand command = commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); + private final List<ArchiveManagerCommand> commands = List.of(previousCommand, command); @Spy private StatusChangeHistoryBuilder builder = StatusChangeHistoryBuilder.builder() diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/VorgangChangeHistoryServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/VorgangChangeHistoryServiceTest.java index ed472242b4959d3f703d2c5bcc28568c5fdd394c..912d0ad90b097a5e33b10391ec8853aec971a324 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/VorgangChangeHistoryServiceTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/historie/VorgangChangeHistoryServiceTest.java @@ -23,7 +23,7 @@ import org.mockito.Spy; import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.archive.common.command.Command; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandService; import de.ozgcloud.archive.common.user.UserProfile; import de.ozgcloud.archive.common.user.UserService; @@ -36,9 +36,9 @@ public class VorgangChangeHistoryServiceTest { private static final String ORGANISATIONSEINHEITEN_ID = ZustaendigeStelleTestFactory.ORGANISATIONSEINHEITEN_ID; private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); - private final Command command0105 = ChangeHistoryBuilderTest.commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); - private final Command command0106 = ChangeHistoryBuilderTest.commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); - private final List<Command> commands = List.of(command0105, command0106); + private final ArchiveManagerCommand command0105 = ChangeHistoryBuilderTest.commandFinishedAt(LocalDateTime.of(2023, 5, 1, 12, 0)); + private final ArchiveManagerCommand command0106 = ChangeHistoryBuilderTest.commandFinishedAt(LocalDateTime.of(2023, 6, 1, 12, 0)); + private final List<ArchiveManagerCommand> commands = List.of(command0105, command0106); private final VorgangChange vorgangChange0105 = VorgangChangeTestFactory.createBuilder() .valueBeforeChange(LoremIpsum.getInstance().getWords(2)) diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java new file mode 100644 index 0000000000000000000000000000000000000000..e72c6347f66a6c5e27cf33583a37198bcb84a71a --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java @@ -0,0 +1,71 @@ +/* + * 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.archive.vorgang; + +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.ApplicationEventPublisher; + +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandCreatedEventTestFactory; +import de.ozgcloud.command.CommandTestFactory; +import de.ozgcloud.common.test.ITCase; +import de.ozgcloud.vorgang.callcontext.WithMockCustomUser; + +@ITCase +@WithMockCustomUser +class ArchiveEventListenerITCase { + + @SpyBean + private ArchiveEventListener eventListener; + + @Autowired + private ApplicationEventPublisher publisher; + + @Nested + class TestOnArchiveVorgang { + + private static final Command COMMAND = CommandTestFactory.createBuilder().order(ArchiveEventListener.ARCHIVE_VORGANG_ORDER).build(); + + @Test + void shouldReactOnOrder() { + var event = CommandCreatedEventTestFactory.withCommand(COMMAND); + + publisher.publishEvent(event); + + verify(eventListener).onArchiveVorgangEvent(event); + } + + @Test + void shouldNotReactOnOtherOrder() { + publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(CommandTestFactory.createBuilder().order("OTHER").build())); + + verifyNoInteractions(eventListener); + } + } +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0a2f444469ebf75b153eeeb3c64d5bd68f29ed5a --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java @@ -0,0 +1,168 @@ +/* + * 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.archive.vorgang; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.function.Consumer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.core.context.SecurityContext; + +import de.ozgcloud.archive.attributes.ClientAttributeService; +import de.ozgcloud.archive.common.callcontext.CurrentUserService; +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandCreatedEventTestFactory; +import de.ozgcloud.command.CommandFailedEvent; +import de.ozgcloud.command.CommandTestFactory; + +class ArchiveEventListenerTest { + + private static final Command COMMAND = CommandTestFactory.create(); + + @Spy + @InjectMocks + private ArchiveEventListener eventListener; + + @Mock + private CurrentUserService currentUserService; + @Mock + private ClientAttributeService clientAttributeService; + @Mock + private VorgangService vorgangService; + @Mock + private ApplicationEventPublisher eventPublisher; + + @Captor + private ArgumentCaptor<Consumer<Command>> commandExecutorCapture; + + @Nested + class TestOnArchiveEvent { + + @BeforeEach + void init() { + doNothing().when(eventListener).doLockVorgang(any()); + } + + @Test + void shouldCallRunWithSecurityContext() { + doNothing().when(eventListener).runWithSecurityContext(any(), any()); + + eventListener.onArchiveVorgangEvent(CommandCreatedEventTestFactory.withCommand(COMMAND)); + + verify(eventListener).runWithSecurityContext(eq(COMMAND), commandExecutorCapture.capture()); + commandExecutorCapture.getValue().accept(COMMAND); + verify(eventListener).doLockVorgang(COMMAND); + } + } + + @Nested + class TestDoLockVorgang { + + @Test + void shouldCallSetVorgangArchiving() { + doLockVorgang(); + + verify(clientAttributeService).setVorgangArchiving(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldCallLockVorgang() { + doLockVorgang(); + + verify(vorgangService).lockVorgang(COMMAND); + } + + private void doLockVorgang() { + eventListener.doLockVorgang(COMMAND); + } + } + + @Nested + class TestRunWithSecurityContext { + + @Mock + private Consumer<Command> commandExecutor; + @Mock + private SecurityContext secContext; + @Captor + private ArgumentCaptor<CommandFailedEvent> commandFailedEventCaptor; + + @BeforeEach + void init() { + when(currentUserService.startAndReturnPreviousSecurityContext(any(Command.class))).thenReturn(secContext); + } + + @Test + void shouldStartSecurityContext() { + eventListener.runWithSecurityContext(COMMAND, commandExecutor); + + verify(currentUserService).startAndReturnPreviousSecurityContext(COMMAND); + } + + @Test + void shouldExecuteCommand() { + eventListener.runWithSecurityContext(COMMAND, commandExecutor); + + verify(commandExecutor).accept(COMMAND); + } + + @Test + void shouldResetSecurityContext() { + eventListener.runWithSecurityContext(COMMAND, commandExecutor); + + verify(currentUserService).resetSecurityContext(secContext); + } + + @Test + void shouldResetSecurityContextAfterException() { + doThrow(new RuntimeException("ups")).when(commandExecutor).accept(any()); + + eventListener.runWithSecurityContext(COMMAND, commandExecutor); + + verify(currentUserService).resetSecurityContext(secContext); + } + + @Test + void shouldPublishCommandFailedEvent() { + doThrow(new RuntimeException("ups")).when(commandExecutor).accept(any()); + + eventListener.runWithSecurityContext(COMMAND, commandExecutor); + + verify(eventPublisher).publishEvent(commandFailedEventCaptor.capture()); + assertThat(commandFailedEventCaptor.getValue().getSource()).isEqualTo(CommandTestFactory.ID); + assertThat(commandFailedEventCaptor.getValue().getErrorMessage()).isNotEmpty(); + } + } +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceTest.java deleted file mode 100644 index f5e4f059002b028ce6d91d9ef823132ab6fe0c7e..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package de.ozgcloud.archive.vorgang; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; - -import de.ozgcloud.archive.export.AllgemeineMetadatenTypeTestFactory; -import de.ozgcloud.archive.export.IdentifikationObjektTypeTestFactory; - -public class ExportVorgangServiceTest { - - private final static String VORGANG_ID = VorgangWithEingangTestFactory.ID; - private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); - - @Spy - @InjectMocks - private ExportVorgangService exportVorgangService; - - @Mock - private VorgangRemoteService vorgangRemoteService; - - @Nested - class TestGetVorgang { - - @BeforeEach - void init() { - when(vorgangRemoteService.findVorgangWithEingang(VORGANG_ID)).thenReturn(vorgang); - } - - @Test - void shouldCallVorgangRemoteService() { - callService(); - - verify(vorgangRemoteService).findVorgangWithEingang(VORGANG_ID); - } - - @Test - void shouldReturnVorgangWithEingang() { - var vorgangWithEingang = callService(); - - assertThat(vorgangWithEingang).isEqualTo(vorgang); - } - - private VorgangWithEingang callService() { - return exportVorgangService.getVorgang(VORGANG_ID); - } - } - - @Nested - class TestCreateAkteType { - - @Test - void shouldCallCreateIdentifikationObjektType() { - exportVorgangService.createAkteType(vorgang); - - verify(exportVorgangService).createIdentifikationObjektType(); - } - - @Test - void shouldSetIdentifikationObjektType() { - var identifikationObjektType = IdentifikationObjektTypeTestFactory.create(); - doReturn(identifikationObjektType).when(exportVorgangService).createIdentifikationObjektType(); - - var akteType = exportVorgangService.createAkteType(vorgang); - - assertThat(akteType.getIdentifikation()).isEqualTo(identifikationObjektType); - } - - @Test - void shouldCallCreateAllgemeineMetadatenType() { - exportVorgangService.createAkteType(vorgang); - - verify(exportVorgangService).createAllgemeineMetadatenType(vorgang); - } - - @Test - void shouldSetAllgemeineMetadatenType() { - var allgemeineMetadatenType = AllgemeineMetadatenTypeTestFactory.create(); - doReturn(allgemeineMetadatenType).when(exportVorgangService).createAllgemeineMetadatenType(vorgang); - - var akteType = exportVorgangService.createAkteType(vorgang); - - assertThat(akteType.getAllgemeineMetadaten()).isEqualTo(allgemeineMetadatenType); - } - } - - @Nested - class TestCreateIdentifikationObjektType { - - @Test - void shouldSetID() { - var identifikationObjektType = exportVorgangService.createIdentifikationObjektType(); - - assertThat(identifikationObjektType.getID()).isNotBlank(); - } - } - - @Nested - class TestCreateAllgemeineMetadatenType { - - @Test - void shouldSetKennzeichen() { - var allgemeineMetadatenType = exportVorgangService.createAllgemeineMetadatenType(vorgang); - - assertThat(allgemeineMetadatenType.getKennzeichen()).isEqualTo(VorgangWithEingangTestFactory.AKTENZEICHEN); - } - - @Test - void shouldSetEmptyKennzeichen() { - var akteType = exportVorgangService.createAkteType(VorgangWithEingangTestFactory.createBuilder().aktenzeichen(null).build()); - - assertThat(akteType.getAllgemeineMetadaten().getKennzeichen()).isEmpty(); - } - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceITCase.java similarity index 92% rename from archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceITCase.java rename to archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceITCase.java index 67dd7e23b03f61bc7cc68eff597e4110c85d4dfb..9bca539cd8db32349881da4186e00aa73cbe0799 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceITCase.java @@ -17,10 +17,10 @@ import de.xoev.xdomea.AntragsdatenItemType; import de.xoev.xdomea.AntragsdatenSingleValueFieldType; @ITCase -class ExportVorgangServiceITCase { +class VorgangServiceITCase { @Autowired - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @Nested class TestMapVorgang { @@ -38,7 +38,7 @@ class ExportVorgangServiceITCase { @Test void shouldContainSingleAntragsdatenElement() { - var vorgangType = exportVorgangService.createVorgangType(VorgangWithEingangTestFactory.create()); + var vorgangType = vorgangService.createVorgangType(VorgangWithEingangTestFactory.create()); assertThat(vorgangType.getAnwendungsspezifischeErweiterungXML().getAny()).hasSize(1).first().isInstanceOf(Antragsdaten.class); } @@ -91,7 +91,7 @@ class ExportVorgangServiceITCase { .antragsteller(AntragstellerTestFactory.createBuilder().otherData(OTHER_DATA).build()) .build(); var vorgangWithEingang = VorgangWithEingangTestFactory.createBuilder().eingang(eingang).build(); - var vorgangType = exportVorgangService.createVorgangType(vorgangWithEingang); + var vorgangType = vorgangService.createVorgangType(vorgangWithEingang); return (Antragsdaten) vorgangType.getAnwendungsspezifischeErweiterungXML().getAny().get(0); } } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b0df2b83c00eceb10e9a27975c37739904187238 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceTest.java @@ -0,0 +1,357 @@ +package de.ozgcloud.archive.vorgang; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import de.ozgcloud.apilib.common.command.OzgCloudCommand; +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequest; +import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequestTestFactory; +import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.apilib.common.command.grpc.OzgCloudCommandTestFactory; +import de.ozgcloud.apilib.common.datatypes.GenericId; +import de.ozgcloud.apilib.user.OzgCloudUserId; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; +import de.ozgcloud.archive.common.callcontext.CallContextUser; +import de.ozgcloud.archive.common.callcontext.CallContextUserTestFactory; +import de.ozgcloud.archive.common.callcontext.CurrentUserService; +import de.ozgcloud.archive.export.AllgemeineMetadatenTypeTestFactory; +import de.ozgcloud.archive.export.IdentifikationObjektTypeTestFactory; +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandTestFactory; + +public class VorgangServiceTest { + + private static final String VORGANG_ID = VorgangWithEingangTestFactory.ID; + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @Spy + @InjectMocks + private VorgangService vorgangService; + + @Mock + private VorgangRemoteService vorgangRemoteService; + @Mock + private OzgCloudCommandService ozgCloudCommandService; + @Mock + private CurrentUserService currentUserService; + @Mock + private OzgCloudVorgangIdMapper ozgCloudVorgangIdMapper; + @Mock + private CommandMapper commandMapper; + + @Nested + class TestGetVorgang { + + @BeforeEach + void init() { + when(vorgangRemoteService.findVorgangWithEingang(VORGANG_ID)).thenReturn(vorgang); + } + + @Test + void shouldCallVorgangRemoteService() { + callService(); + + verify(vorgangRemoteService).findVorgangWithEingang(VORGANG_ID); + } + + @Test + void shouldReturnVorgangWithEingang() { + var vorgangWithEingang = callService(); + + assertThat(vorgangWithEingang).isEqualTo(vorgang); + } + + private VorgangWithEingang callService() { + return vorgangService.getVorgang(VORGANG_ID); + } + } + + @Nested + class TestCreateAkteType { + + @Test + void shouldCallCreateIdentifikationObjektType() { + vorgangService.createAkteType(vorgang); + + verify(vorgangService).createIdentifikationObjektType(); + } + + @Test + void shouldSetIdentifikationObjektType() { + var identifikationObjektType = IdentifikationObjektTypeTestFactory.create(); + doReturn(identifikationObjektType).when(vorgangService).createIdentifikationObjektType(); + + var akteType = vorgangService.createAkteType(vorgang); + + assertThat(akteType.getIdentifikation()).isEqualTo(identifikationObjektType); + } + + @Test + void shouldCallCreateAllgemeineMetadatenType() { + vorgangService.createAkteType(vorgang); + + verify(vorgangService).createAllgemeineMetadatenType(vorgang); + } + + @Test + void shouldSetAllgemeineMetadatenType() { + var allgemeineMetadatenType = AllgemeineMetadatenTypeTestFactory.create(); + doReturn(allgemeineMetadatenType).when(vorgangService).createAllgemeineMetadatenType(vorgang); + + var akteType = vorgangService.createAkteType(vorgang); + + assertThat(akteType.getAllgemeineMetadaten()).isEqualTo(allgemeineMetadatenType); + } + } + + @Nested + class TestCreateIdentifikationObjektType { + + @Test + void shouldSetID() { + var identifikationObjektType = vorgangService.createIdentifikationObjektType(); + + assertThat(identifikationObjektType.getID()).isNotBlank(); + } + } + + @Nested + class TestCreateAllgemeineMetadatenType { + + @Test + void shouldSetKennzeichen() { + var allgemeineMetadatenType = vorgangService.createAllgemeineMetadatenType(vorgang); + + assertThat(allgemeineMetadatenType.getKennzeichen()).isEqualTo(VorgangWithEingangTestFactory.AKTENZEICHEN); + } + + @Test + void shouldSetEmptyKennzeichen() { + var akteType = vorgangService.createAkteType(VorgangWithEingangTestFactory.createBuilder().aktenzeichen(null).build()); + + assertThat(akteType.getAllgemeineMetadaten().getKennzeichen()).isEmpty(); + } + } + + @Nested + class TestLockVorgang { + + private static final Command COMMAND = CommandTestFactory.create(); + private static final OzgCloudCommand SUB_COMMAND = OzgCloudCommandTestFactory.create(); + private static final OzgCloudCreateSubCommandsRequest CREATE_SUB_COMMANDS_REQUEST = OzgCloudCreateSubCommandsRequestTestFactory.create(); + + @BeforeEach + void init() { + doReturn(SUB_COMMAND).when(vorgangService).buildLockVorgangSubCommand(any()); + doReturn(CREATE_SUB_COMMANDS_REQUEST).when(vorgangService).buildCreateSubCommandsRequest(any(), any()); + } + + @Test + void shouldCallBuildLockVorgangSubCommand() { + vorgangService.lockVorgang(COMMAND); + + verify(vorgangService).buildLockVorgangSubCommand(COMMAND); + } + + @Test + void shouldCallBuildCreateSubCommandsRequest() { + vorgangService.lockVorgang(COMMAND); + + verify(vorgangService).buildCreateSubCommandsRequest(CommandTestFactory.ID, SUB_COMMAND); + } + + @Test + void shouldCallAddSubCommands() { + vorgangService.lockVorgang(COMMAND); + + verify(ozgCloudCommandService).addSubCommands(CREATE_SUB_COMMANDS_REQUEST); + } + } + + @Nested + class TestBuildLockVorgangSubCommand { + + private static final long RELATION_VERSION = 10; + private static final Command COMMAND = CommandTestFactory.createBuilder().relationVersion(RELATION_VERSION).build(); + + @BeforeEach + void init() { + doReturn(Optional.of(OzgCloudCommandTestFactory.CREATED_BY)).when(vorgangService).getUserId(); + } + + @Test + void shouldSetOrder() { + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getOrder()).isEqualTo(VorgangService.LOCK_VORGANG_ORDER); + } + + @Test + void shouldSetVorgangId() { + when(commandMapper.toOzgCloudVorgangId(anyString())).thenReturn(OzgCloudVorgangId.from(CommandTestFactory.VORGANG_ID)); + + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID); + assertThat(result.getVorgangId()).hasToString(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldSetRelationId() { + when(commandMapper.mapRelationId(anyString())).thenReturn(GenericId.from(CommandTestFactory.VORGANG_ID)); + + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(commandMapper).mapRelationId(CommandTestFactory.VORGANG_ID); + assertThat(result.getRelationId()).hasToString(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldSetRelationVersion() { + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getRelationVersion()).isEqualTo(RELATION_VERSION); + } + + @Test + void shouldCallBuildObjectBody() { + vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(vorgangService).buildObjectBody(); + } + + @Test + void shouldSetBodyObject() { + var bodyObject = Map.<String, Object>of("key", "value"); + doReturn(bodyObject).when(vorgangService).buildObjectBody(); + + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getBodyObject()).containsExactlyEntriesOf(bodyObject); + } + + @Test + void shouldCallGetUserId() { + vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(vorgangService).getUserId(); + } + + @Test + void shouldSetCreatedBy() { + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getCreatedBy()).isEqualTo(OzgCloudCommandTestFactory.CREATED_BY); + } + } + + @Nested + class TestBuildObjectBody { + + @Test + void shouldReturnBodyObject() { + var result = vorgangService.buildObjectBody(); + + assertThat(result).containsExactly(Map.entry(VorgangService.KEY_LOCK_VORGANG_REASON, VorgangService.LOCK_VORGANG_REASON)); + } + } + + @Nested + class TestGetUserId { + + @Nested + class TestWithUser { + + private static final CallContextUser CALL_CONTEXT_USER = CallContextUserTestFactory.create(); + + @BeforeEach + void init() { + when(currentUserService.findUser()).thenReturn(Optional.of(CALL_CONTEXT_USER)); + } + + @Test + void shouldCallFindUserId() { + vorgangService.getUserId(); + + verify(currentUserService).findUser(); + } + + @Test + void shouldReturnUserId() { + when(commandMapper.toOzgCloudUserId(anyString())).thenReturn(OzgCloudUserId.from(CallContextUserTestFactory.USER_ID)); + + var result = vorgangService.getUserId(); + + verify(commandMapper).toOzgCloudUserId(CallContextUserTestFactory.USER_ID); + assertThat(result).get().hasToString(CallContextUserTestFactory.USER_ID); + } + } + + @Nested + class TestMissingUser { + + @Test + void shouldHandleMissingUser() { + var result = vorgangService.getUserId(); + + assertThat(result).isEmpty(); + } + + @Test + void shouldHandleMissingUserId() { + when(currentUserService.findUser()).thenReturn( + Optional.of(CallContextUserTestFactory.createBuilder().userId(Optional.empty()).build())); + + var result = vorgangService.getUserId(); + + assertThat(result).isEmpty(); + } + } + } + + @Nested + class TestBuildCreateSubCommandsRequest { + + @Test + void shouldSetParentId() { + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, OzgCloudCommandTestFactory.create()); + + assertThat(result.getParentId()).isEqualTo(CommandTestFactory.ID); + } + + @Test + void shouldSetSubCommand() { + var subCommand = OzgCloudCommandTestFactory.create(); + + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, subCommand); + + assertThat(result.getSubCommands()).containsExactly(subCommand); + } + + @Test + void shouldSetCompletedIfSubsCompleted() { + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, OzgCloudCommandTestFactory.create()); + + assertThat(result.isCompletedIfSubsCompleted()).isFalse(); + } + + @Test + void shouldSetExecutionMode() { + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, OzgCloudCommandTestFactory.create()); + + assertThat(result.getExecutionMode()).isEqualTo(VorgangService.SUB_COMMAND_EXECUTION_MODE); + } + } +} diff --git a/archive-manager-server/src/test/resources/application-itcase.yaml b/archive-manager-server/src/test/resources/application-itcase.yaml index 9b265da3d97bcf15a69eb41c456810e518dbd49b..04ca541b6f2396d09a347684021e152ce0812abe 100644 --- a/archive-manager-server/src/test/resources/application-itcase.yaml +++ b/archive-manager-server/src/test/resources/application-itcase.yaml @@ -6,4 +6,4 @@ ozgcloud: grpc: server: - port: -1 \ No newline at end of file + port: -1 diff --git a/lombok.config b/lombok.config index a0e918012b6da2b2cd06374cf7ac35d085bfa3e0..8e315e3261a9b09aaf535702db799d3991736230 100644 --- a/lombok.config +++ b/lombok.config @@ -28,4 +28,5 @@ lombok.log.log4j.flagUsage = ERROR lombok.data.flagUsage = ERROR lombok.nonNull.exceptionType = IllegalArgumentException lombok.addLombokGeneratedAnnotation = true -lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier \ No newline at end of file +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.copyableAnnotations += net.devh.boot.grpc.client.inject.GrpcClient diff --git a/pom.xml b/pom.xml index 0901b8c80b582ff7fd1bed4feded480cf94c179e..29fb0aec3be376e32b1dfaab95a89f1299335472 100644 --- a/pom.xml +++ b/pom.xml @@ -27,11 +27,11 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <vorgang-manager.version>2.18.0</vorgang-manager.version> <nachrichten-manager.version>2.15.0</nachrichten-manager.version> - <api-lib.version>0.13.0</api-lib.version> + <api-lib.version>0.14.0</api-lib.version> <find-and-replace-maven-plugin.version>1.2.0</find-and-replace-maven-plugin.version> <protoc-jar-plugin.version>3.11.4</protoc-jar-plugin.version> - <ozgcloud-common.version>4.5.0</ozgcloud-common.version> - <document-manager.version>1.1.0-SNAPSHOT</document-manager.version> + <ozgcloud-common.version>4.7.0-SNAPSHOT</ozgcloud-common.version> + <document-manager.version>1.1.0</document-manager.version> </properties> <dependencyManagement> <dependencies> @@ -41,16 +41,36 @@ <artifactId>vorgang-manager-interface</artifactId> <version>${vorgang-manager.version}</version> </dependency> + <dependency> + <groupId>de.ozgcloud.command</groupId> + <artifactId>command-manager</artifactId> + <version>${vorgang-manager.version}</version> + </dependency> + <dependency> + <groupId>de.ozgcloud.command</groupId> + <artifactId>command-manager</artifactId> + <version>${vorgang-manager.version}</version> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>de.ozgcloud.vorgang</groupId> + <artifactId>vorgang-manager-base</artifactId> + <version>${vorgang-manager.version}</version> + <type>test-jar</type> + </dependency> + <dependency> <groupId>de.ozgcloud.nachrichten</groupId> <artifactId>nachrichten-manager-interface</artifactId> <version>${nachrichten-manager.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> @@ -61,6 +81,8 @@ <artifactId>document-manager-interface</artifactId> <version>${document-manager.version}</version> </dependency> + + <!-- test --> <dependency> <groupId>de.ozgcloud.api-lib</groupId> <artifactId>api-lib-core</artifactId>