diff --git a/bescheid-manager/pom.xml b/bescheid-manager/pom.xml index 1a68e867137a6b69567130194e403315d74c70dd..08aa46a6bad2f372f7a30193c7de3d387a735789 100644 --- a/bescheid-manager/pom.xml +++ b/bescheid-manager/pom.xml @@ -12,12 +12,12 @@ <groupId>de.ozgcloud.bescheid</groupId> <artifactId>bescheid-manager</artifactId> <name>OZG-Cloud Bescheid Manager</name> - <version>1.21.0-SNAPSHOT</version> + <version>1.22.0-SNAPSHOT</version> <properties> - <vorgang-manager.version>2.18.0-SNAPSHOT</vorgang-manager.version> + <vorgang-manager.version>2.19.0-SNAPSHOT</vorgang-manager.version> <nachrichten-manager.version>2.14.0</nachrichten-manager.version> - <document-manager.version>1.1.0-SNAPSHOT</document-manager.version> + <document-manager.version>1.1.0</document-manager.version> <api-lib.version>0.13.0</api-lib.version> <spring-cloud-config-client.version>4.1.3</spring-cloud-config-client.version> </properties> diff --git a/pom.xml b/pom.xml index 6b7687d7ad095a08ede0e47302cb681c8758f4d8..494b935a4f31039cfce14ab9cbacf431bcb5b818 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager</artifactId> - <version>2.18.0-SNAPSHOT</version> + <version>2.19.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager</name> <packaging>pom</packaging> diff --git a/vorgang-manager-base/pom.xml b/vorgang-manager-base/pom.xml index c83597fa5a58ebe7a7f6505a895f3a5a4ae57ef2..c7172d29448e987cfdce84cca7f287ac610cdd54 100644 --- a/vorgang-manager-base/pom.xml +++ b/vorgang-manager-base/pom.xml @@ -12,7 +12,7 @@ <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-base</artifactId> - <version>2.18.0-SNAPSHOT</version> + <version>2.19.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager Base</name> @@ -25,7 +25,7 @@ <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency> - + <dependency> <groupId>net.devh</groupId> <artifactId>grpc-server-spring-boot-starter</artifactId> @@ -34,7 +34,7 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> - + <!-- TEST --> <dependency> <groupId>org.springframework.security</groupId> @@ -42,7 +42,7 @@ <scope>test</scope> </dependency> </dependencies> - + <build> <plugins> <plugin> diff --git a/vorgang-manager-command/pom.xml b/vorgang-manager-command/pom.xml index 43d5db3f766ff8c111b9014da615c53f287fbc39..f93d67bd17606e486b5141534a01bdeba40f5423 100644 --- a/vorgang-manager-command/pom.xml +++ b/vorgang-manager-command/pom.xml @@ -7,16 +7,16 @@ <version>4.6.0-OZG-7143-download-timeout-SNAPSHOT</version> <relativePath/> </parent> - + <groupId>de.ozgcloud.command</groupId> <artifactId>command-manager</artifactId> - <version>2.18.0-SNAPSHOT</version> + <version>2.19.0-SNAPSHOT</version> <name>OZG-Cloud Command Manager</name> <properties> <maven-jar-plugin.version>3.3.0</maven-jar-plugin.version> </properties> - + <dependencies> <dependency> <groupId>org.springframework</groupId> @@ -34,7 +34,7 @@ <optional>true</optional> </dependency> </dependencies> - + <build> <plugins> <plugin> diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangUnlockedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangUnlockedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..167a7e49b7590fb40f6b7764c0a7feaf1a5d4170 --- /dev/null +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangUnlockedEvent.java @@ -0,0 +1,31 @@ +/* + * 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.command; + +public class VorgangUnlockedEvent extends CommandExecutedEvent { + + public VorgangUnlockedEvent(Command command) { + super(command); + } +} diff --git a/vorgang-manager-interface/pom.xml b/vorgang-manager-interface/pom.xml index 27bed8971a78be17aed5f0edba00c03e65b38c66..33a50b101f9f2bd1b7786459f609aba4d804a7f1 100644 --- a/vorgang-manager-interface/pom.xml +++ b/vorgang-manager-interface/pom.xml @@ -36,7 +36,7 @@ <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-interface</artifactId> - <version>2.18.0-SNAPSHOT</version> + <version>2.19.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager gRPC Interface</name> <description>Interface (gRPC) for Vorgang Manager Server</description> diff --git a/vorgang-manager-server/pom.xml b/vorgang-manager-server/pom.xml index 6b32baf91bac7d3f94db0d79f1ad5c7ebec244eb..c2e8544c94f3a2d3665c86e4861e465c9577b3d4 100644 --- a/vorgang-manager-server/pom.xml +++ b/vorgang-manager-server/pom.xml @@ -32,13 +32,13 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.6.0-OZG-7143-download-timeout-SNAPSHOT</version> + <version>4.7.0-OZG-7143-download-timeout-SNAPSHOT</version> <relativePath /> </parent> <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-server</artifactId> - <version>2.18.0-SNAPSHOT</version> + <version>2.19.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager Server</name> <description>Server Implementierung des VorgangManagers</description> @@ -53,12 +53,12 @@ <zufi-manager-interface.version>1.4.0</zufi-manager-interface.version> <user-manager-interface.version>2.9.0</user-manager-interface.version> - <bescheid-manager.version>1.21.0-SNAPSHOT</bescheid-manager.version> + <bescheid-manager.version>1.22.0-SNAPSHOT</bescheid-manager.version> <processor-manager.version>0.5.0</processor-manager.version> <nachrichten-manager.version>2.14.1</nachrichten-manager.version> - <ozgcloud-starter.version>0.14.0-SNAPSHOT</ozgcloud-starter.version> + <ozgcloud-starter.version>0.14.0</ozgcloud-starter.version> <notification-manager.version>2.12.0</notification-manager.version> - <collaboration-manager.version>0.5.0-SNAPSHOT</collaboration-manager.version> + <collaboration-manager.version>0.5.0</collaboration-manager.version> <archive-manager.version>0.1.0-OZG-7143-download-timeout-SNAPSHOT</archive-manager.version> <document-manager.version>1.1.0-SNAPSHOT</document-manager.version> diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java index 7ff69bdda006fb2d969558ea1f60dc7cc23f99e3..735062519c9fab1aded45bb777bdf6492715178e 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java @@ -72,14 +72,14 @@ public class CommandService { private CurrentUserService userService; public Command createCommand(CreateCommandRequest request) { - validateVorgang(request.getVorgangId()); + validateVorgang(request.getVorgangId(), request.getOrder()); var persisted = saveCommand(buildCommand(request)); publisher.publishEvent(new CommandCreatedEvent(persisted)); return persisted; } - void validateVorgang(String vorgangId) { - if (vorgangService.isVorgangLocked(vorgangId)) { + void validateVorgang(String vorgangId, String order) { + if (!Order.UNLOCK_VORGANG.isMeant(order) && vorgangService.isVorgangLocked(vorgangId)) { throw new TechnicalException("Cannot create command. Vorgang %s is locked.".formatted(vorgangId)); } } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java index f51468b4f6c1b2b2021edea87a9e3fb718e764b4..8129105065f4ac879de49f0c4eb1b53323e6b0d8 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java @@ -41,6 +41,7 @@ public enum Order { VORGANG_ZUM_LOESCHEN_MARKIEREN, VORGANG_LOESCHEN, LOCK_VORGANG, + UNLOCK_VORGANG, ASSIGN_USER, diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java index fe62492f032f6f357a8df8db7fbecee6ce1031c2..326cea62655275c0caa6bd9ddb315a1c5cddef54 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java @@ -26,7 +26,6 @@ package de.ozgcloud.vorgang.vorgang; import java.util.Collections; import java.util.function.Predicate; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -38,41 +37,43 @@ import de.ozgcloud.command.CommandFailedEvent; import de.ozgcloud.command.CommandRevokeFailedEvent; import de.ozgcloud.command.CommandRevokedEvent; import de.ozgcloud.command.RevokeCommandEvent; +import de.ozgcloud.command.VorgangUnlockedEvent; import de.ozgcloud.vorgang.command.CommandService; import de.ozgcloud.vorgang.command.Order; import de.ozgcloud.vorgang.files.FileService; import de.ozgcloud.vorgang.status.StatusService; import de.ozgcloud.vorgang.vorgang.redirect.VorgangForwardFailedEvent; import de.ozgcloud.vorgang.vorgang.redirect.VorgangRedirectedEvent; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Component +@RequiredArgsConstructor @Log4j2 public class VorgangEventListener { private static final String IS_ASSIGN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_ASSIGN_COMMAND.test(event.getSource())}"; - private static final String IS_LOESCHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOESCHEN_COMMAND.test(event.getSource())}"; - private static final String IS_SET_AKTENZEICHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_SET_AKTENZEICHEN_COMMAND.test(event.getSource())}"; public static final Predicate<Command> IS_ASSIGN_COMMAND = command -> Order.ASSIGN_USER.isMeant(command.getOrder()); + + private static final String IS_LOESCHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOESCHEN_COMMAND.test(event.getSource())}"; public static final Predicate<Command> IS_LOESCHEN_COMMAND = command -> Order.VORGANG_LOESCHEN.isMeant(command.getOrder()); + + private static final String IS_SET_AKTENZEICHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_SET_AKTENZEICHEN_COMMAND.test(event.getSource())}"; public static final Predicate<Command> IS_SET_AKTENZEICHEN_COMMAND = command -> Order.SET_AKTENZEICHEN.isMeant(command.getOrder()); private static final String IS_LOCK_VORGANG_COMMAND = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOCK_VORGANG_ORDER.test(event.getSource())}"; public static final Predicate<Command> IS_LOCK_VORGANG_ORDER = command -> Order.LOCK_VORGANG.isMeant(command.getOrder()); - @Autowired - private StatusService statusService; - @Autowired - private VorgangService vorgangService; - @Autowired - private VorgangHeaderService vorgangHeaderService; - @Autowired - private FileService fileService; - @Autowired - private CommandService commandService; + private static final String IS_UNLOCK_VORGANG_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_UNLOCK_VORGANG_COMMAND.test(event.getSource())}"; + public static final Predicate<Command> IS_UNLOCK_VORGANG_COMMAND = command -> Order.UNLOCK_VORGANG.isMeant(command.getOrder()); - @Autowired - private ApplicationEventPublisher publisher; + private final StatusService statusService; + private final VorgangService vorgangService; + private final VorgangHeaderService vorgangHeaderService; + private final FileService fileService; + private final CommandService commandService; + + private final ApplicationEventPublisher publisher; @EventListener public void updateStatus(VorgangRedirectedEvent event) { @@ -153,4 +154,16 @@ public class VorgangEventListener { private String getAktenzeichen(String vorgangId) { return vorgangHeaderService.getById(vorgangId).getAktenzeichen(); } + + @EventListener(condition = IS_UNLOCK_VORGANG_COMMAND_CONDITION) + public void onUnlockVorgang(CommandCreatedEvent event) { + var command = event.getSource(); + try { + vorgangService.unlockVorgang(command); + publisher.publishEvent(new VorgangUnlockedEvent(command)); + } catch (RuntimeException e) { + LOG.error("Error unlocking vorgang.", e); + publisher.publishEvent(new CommandFailedEvent(command.getId(), e.getMessage())); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java index 26d04339e3b70b7d4223f9767b369769565e4d2b..73b8056a21f14627df0a698190236e834641e59c 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java @@ -73,10 +73,25 @@ class VorgangRepository { } public void patch(String vorgangId, long version, Map<String, Object> patch) { - var update = new Update().inc(Vorgang.MONGODB_FIELDNAME_VERSION, 1); + updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), createPatchUpdate(patch)); + } + + private Update createPatchUpdate(Map<String, Object> patch) { + var update = createVersionIncUpdate(); patch.forEach(update::set); + return update; + } + + public void removeLock(String vorgangId, long version) { + updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), createUnlockUpdate()); + } + + private Update createUnlockUpdate() { + return createVersionIncUpdate().unset(VorgangService.KEY_HEADER_LOCK); + } - updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), update); + private Update createVersionIncUpdate() { + return new Update().inc(Vorgang.MONGODB_FIELDNAME_VERSION, 1); } public void setAktenzeichen(String vorgangId, long version, String akteneinsicht) { diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java index bb11f2d9dd746310ba8ca7a2aa792347ae74498d..d74495d587f0f340e7cc5ba4bd1362017ff8e4b5 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java @@ -38,7 +38,6 @@ import jakarta.validation.Valid; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Service; @@ -55,33 +54,28 @@ import de.ozgcloud.vorgang.clientattribute.ClientAttributesMap; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; import de.ozgcloud.vorgang.servicekonto.ServiceKonto; import lombok.NonNull; +import lombok.RequiredArgsConstructor; @Validated @Service +@RequiredArgsConstructor public class VorgangService { private static final String BODY_ASSIGNED_TO_FIELD = "assignedTo"; public static final String BODY_OBJECT_AKTENZEICHEN = "aktenzeichen"; static final String KEY_HEADER_LOCK = "%s.%s".formatted(Vorgang.MONGODB_FIELDNAME_HEADER, VorgangHead.FIELD_LOCK); - @Autowired - private VorgangAuthorizationService vorgangAuthenticationService; - @Autowired - private VorgangRepository repository; + private final VorgangAuthorizationService vorgangAuthenticationService; + private final VorgangRepository repository; - @Autowired - private ApplicationEventPublisher publisher; - @Autowired - private AktenzeichenProvider aktenzeichenProvider; + private final ApplicationEventPublisher publisher; + private final AktenzeichenProvider aktenzeichenProvider; - @Autowired - private ClientAttributeReadPermitted readIsPermitted; + private final ClientAttributeReadPermitted readIsPermitted; - @Autowired - private LabelProcessor kopControlDataMapper; + private final LabelProcessor kopControlDataMapper; - @Autowired - private VorgangStubMapper stubMapper; + private final VorgangStubMapper stubMapper; public Vorgang startCreation(@Valid Eingang eingang) { var mappedEingang = kopControlDataMapper.moveLabelsToControlData(eingang); @@ -261,8 +255,24 @@ public class VorgangService { } public void unlockVorgang(Command command) { - // TODO wird implementiert in OZG-6992 - // publisher.publishEvent(new CommandRevokedEvent(command)); - throw new UnsupportedOperationException("Not yet implemented"); + validateUnlockingClient(command); + repository.removeLock(command.getVorgangId(), command.getRelationVersion()); } + + void validateUnlockingClient(Command command) { + var vorgang = repository.findById(command.getVorgangId()).orElseThrow(() -> new NotFoundException(Vorgang.class, command.getVorgangId())); + validateClientName(command.getCreatedByClientName(), Optional.ofNullable(vorgang.getHeader().getLock())); + } + + void validateClientName(String commandClientName, Optional<Lock> lock) { + if (hasNoPermissionToUnlock(commandClientName, lock)) { + throw new AccessDeniedException( + "Vorgang was locked by %s, but client name is %s!".formatted(lock.get().getClientName(), commandClientName)); + } + } + + boolean hasNoPermissionToUnlock(String clientName, Optional<Lock> lock) { + return lock.map(Lock::getClientName).filter(lockingClient -> !lockingClient.equals(clientName)).isPresent(); + } + } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java index 5cc668752eae4480fa6c9c8d4767483ab56db5a6..126443e9add8f118d47eb65f7bdc77e64bbc1cfe 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java @@ -25,19 +25,13 @@ package de.ozgcloud.vorgang; import static org.mockito.Mockito.*; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mail.javamail.JavaMailSender; -import de.ozgcloud.archive.common.callcontext.CallContextProvider; - @Configuration public class TestConfiguration { - @MockBean - private CallContextProvider callContextProvider; - @Bean JavaMailSender mockMailSender() { return mock(JavaMailSender.class); diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java index a129a4c389de52dbf8d0ef358efdec8ea5e6771c..364dfd5ed06c1ed1f95285ac4ac58115721039da 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java @@ -90,7 +90,7 @@ class CommandServiceTest { void shouldCallValidateVorgang() { service.createCommand(request); - verify(service).validateVorgang(VorgangTestFactory.ID); + verify(service).validateVorgang(VorgangTestFactory.ID, CreateCommandRequestTestFactory.ORDER.name()); } @Test @@ -182,16 +182,29 @@ class CommandServiceTest { @Test void shouldCallIsVorgangLocked() { - service.validateVorgang(VorgangTestFactory.ID); + service.validateVorgang(VorgangTestFactory.ID, Order.ASSIGN_USER.name()); verify(vorgangService).isVorgangLocked(VorgangTestFactory.ID); } @Test void shouldThrowExceptionIfVorgangLocked() { + var order = Order.ASSIGN_USER.name(); when(vorgangService.isVorgangLocked(anyString())).thenReturn(true); - Assertions.assertThrows(TechnicalException.class, () -> service.validateVorgang(VorgangTestFactory.ID)); + Assertions.assertThrows(TechnicalException.class, () -> service.validateVorgang(VorgangTestFactory.ID, order)); + } + + @Test + void shouldNotCallIsVorgangLockedForUnlockVorgangOrder() { + service.validateVorgang(VorgangTestFactory.ID, Order.UNLOCK_VORGANG.name()); + + verify(vorgangService, never()).isVorgangLocked(any()); + } + + @Test + void shouldNotThrowExceptionIfOrderIsUnlockVorgang() { + Assertions.assertDoesNotThrow(() -> service.validateVorgang(VorgangTestFactory.ID, Order.UNLOCK_VORGANG.name())); } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java index 7b4905e5280cf65dc77a65dae4888feb035e7f01..cdbbc7fa172617709dc7d4964dba7d3461b126f4 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java @@ -29,11 +29,12 @@ import java.util.Map; import com.thedeanda.lorem.LoremIpsum; +import de.ozgcloud.vorgang.command.CommandTestFactory; import de.ozgcloud.vorgang.vorgang.Lock.LockBuilder; public class LockTestFactory { - public static final String CLIENT_NAME = LoremIpsum.getInstance().getFirstName() + "-Client"; + public static final String CLIENT_NAME = CommandTestFactory.CREATED_BY_CLIENT; public static final String REASON = LoremIpsum.getInstance().getWords(5); public static final String LOCKED_SINCE_STR = ZonedDateTime.now().withNano(0).format(DateTimeFormatter.ISO_INSTANT); public static final ZonedDateTime LOCKED_SINCE = ZonedDateTime.parse(LOCKED_SINCE_STR); @@ -53,7 +54,6 @@ public class LockTestFactory { return Map.of( Lock.FIELD_CLIENT_NAME, CLIENT_NAME, Lock.FIELD_LOCKED_SINCE, LOCKED_SINCE, - Lock.FIELD_REASON, REASON - ); + Lock.FIELD_REASON, REASON); } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java index d57886aa60ea449c2003ecdbdf979614a259dc89..be162187880409f7b34a3329106ad843b1c4914c 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java @@ -44,11 +44,13 @@ import org.springframework.context.ApplicationEventPublisher; import com.thedeanda.lorem.LoremIpsum; import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandCreatedEvent; import de.ozgcloud.command.CommandExecutedEvent; import de.ozgcloud.command.CommandFailedEvent; import de.ozgcloud.command.CommandRevokeFailedEvent; import de.ozgcloud.command.CommandRevokedEvent; import de.ozgcloud.command.RevokeCommandEvent; +import de.ozgcloud.command.VorgangUnlockedEvent; import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory; import de.ozgcloud.vorgang.command.CommandService; @@ -307,4 +309,52 @@ class VorgangEventListenerTest { }); } } + + @Nested + class TestOnUnlockVorgang { + + private final Command command = CommandTestFactory.create(); + + @Captor + private ArgumentCaptor<VorgangUnlockedEvent> vorgangUnlockedEventCaptor; + @Captor + private ArgumentCaptor<CommandFailedEvent> commandFailedEventCaptor; + + @Test + void shouldUnlockVorgangOnUnlockVorgangOrder() { + onUnlockVorgang(); + + verify(service).unlockVorgang(command); + } + + @Test + void shouldPublishVorgangUnlockedEvent() { + onUnlockVorgang(); + + verify(publisher).publishEvent(vorgangUnlockedEventCaptor.capture()); + assertThat(vorgangUnlockedEventCaptor.getValue()).satisfies(event -> { + assertThat(event).isInstanceOf(VorgangUnlockedEvent.class); + assertThat(event.getCommand()).isEqualTo(command); + }); + + } + + @Test + void shouldPublishCommandFailedEvent() { + var errorMessage = "error message"; + doThrow(new RuntimeException(errorMessage)).when(service).unlockVorgang(command); + + onUnlockVorgang(); + + verify(publisher).publishEvent(commandFailedEventCaptor.capture()); + assertThat(commandFailedEventCaptor.getValue()).satisfies(event -> { + assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID); + assertThat(event.getErrorMessage()).isEqualTo(errorMessage); + }); + } + + private void onUnlockVorgang() { + listener.onUnlockVorgang(new CommandCreatedEvent(command)); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java index 9d19e8a701453ad636c4458f45d9de1f30b2927b..65fd1a6bf226e3ddc4f5a8ba761f490e9f501a0c 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java @@ -382,5 +382,57 @@ class VorgangRepositoryITCase { assertThat(isLocked).isFalse(); } + + @Test + void shouldReturnFalseAfterLockRemoved() { + var vorgang = mongoOperations.save( + VorgangTestFactory.createBuilder().id(null).version(0).header(VorgangHeadTestFactory.create()).build()); + repository.removeLock(vorgang.getId(), 0); + + var isLocked = repository.isVorgangLocked(vorgang.getId()); + + assertThat(isLocked).isFalse(); + } + } + + @Nested + class TestRemoveLock { + + private final Vorgang vorgang = VorgangTestFactory.createBuilder() + .header(VorgangHeadTestFactory.create()) + .build(); + + @BeforeEach + void persistVorgang() { + repository.save(vorgang); + } + + @Test + void shouldRemoveLock() { + removeLock(); + + assertThat(getVorgang().getHeader().getLock()).isNull(); + } + + @Test + void shouldIncrementVersion() { + removeLock(); + + assertThat(getVorgang().getVersion()).isEqualTo(VorgangTestFactory.VERSION + 1); + } + + private void removeLock() { + repository.removeLock(VorgangTestFactory.ID, VorgangTestFactory.VERSION); + } + + @Test + void shouldThrowExceptionByCollision() { + assertThrows(ConcurrentModificationException.class, + () -> repository.removeLock(VorgangTestFactory.ID, VorgangTestFactory.VERSION + 1)); + } + + private Vorgang getVorgang() { + return mongoOperations.findById(VorgangTestFactory.ID, Vorgang.class); + } } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java index 5e4c2e4690780c92555b58237d9662f6dafe91c8..8cda2f7766d0e4a776f9b4de9fc1d716d1951a27 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java @@ -24,6 +24,7 @@ package de.ozgcloud.vorgang.vorgang; import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.InstanceOfAssertFactories.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -352,7 +353,7 @@ class VorgangServiceTest { void shouldThrowAccessDeniedException() { when(vorgangAuthorizationService.authorizeByOrganisationseinheitenId(any(), any())).thenReturn(false); - assertThrows(AccessDeniedException.class, () -> service.getById(VorgangTestFactory.ID, FilterCriteriaTestFactory.create())); //NOSONAR + assertThrows(AccessDeniedException.class, () -> service.getById(VorgangTestFactory.ID, FilterCriteriaTestFactory.create())); // NOSONAR } } @@ -586,7 +587,7 @@ class VorgangServiceTest { @Nested class TestBuildLockPatch { - private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); @Test void shouldSetClientName() { @@ -632,4 +633,131 @@ class VorgangServiceTest { assertThat(result).isTrue(); } } + + @Nested + class TestUnlockVorgang { + + private final Command command = CommandTestFactory.create(); + + @BeforeEach + void mock() { + doNothing().when(service).validateUnlockingClient(any()); + } + + @Test + void shouldCallValidateUnlockingClient() { + unlockVorgang(); + + verify(service).validateUnlockingClient(command); + } + + @Test + void shouldCallRepository() { + unlockVorgang(); + + verify(repository).removeLock(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION); + } + + private void unlockVorgang() { + service.unlockVorgang(command); + } + } + + @Nested + class TestValidateUnlockingClient { + + private final Vorgang vorgang = VorgangTestFactory.createBuilder().header(VorgangHeadTestFactory.create()).build(); + private final Command command = CommandTestFactory.create(); + + @Test + void shouldGetVorgangFromRepository() { + givenRepositoryReturnsVorgang(); + + validateUnlockingClient(); + + verify(repository).findById(VorgangTestFactory.ID); + } + + @Test + void shouldThrowNotFoundException() { + when(repository.findById(VorgangTestFactory.ID)).thenReturn(Optional.empty()); + + assertThrows(NotFoundException.class, () -> validateUnlockingClient()); + } + + @Test + void shouldCallValidateClientName() { + givenRepositoryReturnsVorgang(); + + validateUnlockingClient(); + + verify(service).validateClientName(CommandTestFactory.CREATED_BY_CLIENT, Optional.of(VorgangHeadTestFactory.LOCK)); + } + + private void givenRepositoryReturnsVorgang() { + when(repository.findById(VorgangTestFactory.ID)).thenReturn(Optional.of(vorgang)); + } + + private void validateUnlockingClient() { + service.validateUnlockingClient(command); + } + } + + @Nested + class TestValidateClientName { + + private final Lock lock = LockTestFactory.create(); + + @Test + void shouldCallHasNoPermissionToUnlock() { + doReturn(false).when(service).hasNoPermissionToUnlock(any(), any()); + + validateClientName(); + + verify(service).hasNoPermissionToUnlock(CommandTestFactory.CREATED_BY_CLIENT, Optional.of(lock)); + } + + @Test + void shouldThrowAccessDeniedException() { + doReturn(true).when(service).hasNoPermissionToUnlock(any(), any()); + + assertThrows(AccessDeniedException.class, () -> validateClientName()); + } + + @Test + void shouldNotThrowException() { + doReturn(false).when(service).hasNoPermissionToUnlock(any(), any()); + + assertDoesNotThrow(() -> validateClientName()); + } + + private void validateClientName() { + service.validateClientName(CommandTestFactory.CREATED_BY_CLIENT, Optional.of(lock)); + } + } + + @Nested + class TestHasNoPermissionToUnlock { + + @Test + void shouldReturnFalseIfLockEmpty() { + var result = service.hasNoPermissionToUnlock(CommandTestFactory.CREATED_BY_CLIENT, Optional.empty()); + + assertThat(result).isFalse(); + } + + @Test + void shouldReturnTrueIfLockPresentAndClientNameNotMatching() { + var result = service.hasNoPermissionToUnlock("wrong name", Optional.of(LockTestFactory.create())); + + assertThat(result).isTrue(); + } + + @Test + void shouldReturnFalseIfLockPresentAndClientNameMatching() { + var result = service.hasNoPermissionToUnlock(LockTestFactory.CLIENT_NAME, Optional.of(LockTestFactory.create())); + + assertThat(result).isFalse(); + } + } } \ No newline at end of file diff --git a/vorgang-manager-utils/pom.xml b/vorgang-manager-utils/pom.xml index 37bbe96a2714cd01208cd601a7f512cd6c6746ea..b37c7650b958b3fd8a90044d9e4c931bb921ca04 100644 --- a/vorgang-manager-utils/pom.xml +++ b/vorgang-manager-utils/pom.xml @@ -37,16 +37,16 @@ <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-utils</artifactId> <name>OZG-Cloud Vorgang Manager Utils</name> - <version>2.18.0-SNAPSHOT</version> + <version>2.19.0-SNAPSHOT</version> <properties> <maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version> <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version> - + <maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version> <maven-failsafe-plugin.version>3.2.2</maven-failsafe-plugin.version> <lombok.version>1.18.34</lombok.version> - + </properties> <dependencies>