From 04590baac4dcbdb47b3ca82ea423c74715fd14e8 Mon Sep 17 00:00:00 2001 From: OZGCloud <ozgcloud@mgm-tp.com> Date: Tue, 29 Oct 2024 21:16:52 +0100 Subject: [PATCH] OZG-6991 implement lock vorgang --- .../java/de/ozgcloud/command/Command.java | 1 + .../java/de/ozgcloud/command/TestCommand.java | 1 + .../vorgang/command/PersistedCommand.java | 1 + .../de/ozgcloud/vorgang/vorgang/Vorgang.java | 1 + .../ozgcloud/vorgang/vorgang/VorgangHead.java | 2 + .../vorgang/vorgang/VorgangService.java | 27 +++++ .../vorgang/command/CommandTestFactory.java | 3 + .../vorgang/vorgang/VorgangServiceTest.java | 109 ++++++++++++++++++ 8 files changed, 145 insertions(+) diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java index 61876bd40..03beadfa1 100644 --- a/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java @@ -44,6 +44,7 @@ public interface Command { public String getCreatedBy(); public String getCreatedByName(); public CommandStatus getStatus(); + String getCreatedByClient(); public Map<String, Object> getBodyObject(); public Map<String, String> getBody(); diff --git a/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java b/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java index 3ebddf936..3d2c5d826 100644 --- a/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java +++ b/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java @@ -21,6 +21,7 @@ public class TestCommand implements Command { private ZonedDateTime finishedAt; private String createdBy; private String createdByName; + private String createdByClient; private CommandStatus status; diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java index 71964af4d..0973a3979 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java @@ -63,6 +63,7 @@ public class PersistedCommand implements Command { private String createdBy; private String createdByName; + private String createdByClient; @Setter private CommandStatus status; diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java index 88557e44c..979de7347 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java @@ -50,6 +50,7 @@ public class Vorgang { static final String MONGODB_FIELDNAME_CREATED_AT = "createdAt"; public static final String MONGODB_FIELDNAME_ASSIGNED_TO = "assignedTo"; public static final String MONGODB_FIELDNAME_IN_CREATION = "inCreation"; + public static final String MONGODB_FIELDNAME_HEADER = "header"; public static final String FIELD_EINGANGSKENNZ = "eingangs.header.requestId"; public static final String FIELD_AKTENZEICHEN = "aktenzeichen"; diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java index ee5dc6b92..2f3cb7ddd 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java @@ -11,6 +11,8 @@ import lombok.Getter; @TypeAlias("VorgangHeader") public class VorgangHead { + public static final String FIELD_LOCK = "lock"; + private ServiceKonto serviceKonto; private String organisationsEinheitId; 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 274e1945c..801685f1f 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 @@ -23,10 +23,13 @@ */ package de.ozgcloud.vorgang.vorgang; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; @@ -45,6 +48,7 @@ import de.ozgcloud.command.Command; import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; import de.ozgcloud.command.VorgangLockedEvent; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.vorgang.clientattribute.ClientAttributeMap; import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted; import de.ozgcloud.vorgang.clientattribute.ClientAttributesMap; @@ -58,6 +62,7 @@ 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; @@ -226,9 +231,31 @@ public class VorgangService { } public void lockVorgang(Command command) { + validateLockCommand(command); + repository.patch(command.getVorgangId(), command.getRelationVersion(), buildLockPatch(command)); publisher.publishEvent(new VorgangLockedEvent(command)); } + void validateLockCommand(Command command) { + if (Objects.isNull(command.getCreatedByClient())) { + throw new TechnicalException("Missing client name in lock command"); + } + if (Objects.isNull(getReason(command.getBodyObject()))) { + throw new TechnicalException("Missing reason in lock command"); + } + } + + Map<String, Object> buildLockPatch(Command command) { + return Map.of(KEY_HEADER_LOCK, Map.of( + Lock.FIELD_CLIENT_NAME, command.getCreatedByClient(), + Lock.FIELD_LOCKED_SINCE, ZonedDateTime.now(ZoneId.of("UTC")), + Lock.FIELD_REASON, getReason(command.getBodyObject()))); + } + + String getReason(Map<String, Object> commandBody) { + return StringUtils.trimToNull(MapUtils.getString(commandBody, Lock.FIELD_REASON)); + } + public void unlockVorgang(Command command) { // TODO wird implementiert in OZG-6992 // publisher.publishEvent(new CommandRevokedEvent(command)); diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java index ff3e080ef..47f9149c3 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java @@ -29,6 +29,7 @@ import java.util.UUID; import de.ozgcloud.command.CommandStatus; import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory; +import de.ozgcloud.vorgang.callcontext.CallContextTestFactory; import de.ozgcloud.vorgang.callcontext.UserTestFactory; import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; @@ -39,6 +40,7 @@ public class CommandTestFactory { public static final ZonedDateTime CREATED_AT = ZonedDateTime.parse(CREATED_AT_STR); public static final String CREATED_BY = UserTestFactory.ID; public static final String CREATED_BY_NAME = UserTestFactory.NAME; + public static final String CREATED_BY_CLIENT = CallContextTestFactory.CLIENT; public static final CommandStatus STATUS = CommandStatus.PENDING; public static final String RELATION_ID = VorgangAttachedItemTestFactory.ID; @@ -59,6 +61,7 @@ public class CommandTestFactory { .createdAt(CREATED_AT) .createdBy(CREATED_BY) .createdByName(CREATED_BY_NAME) + .createdByClient(CREATED_BY_CLIENT) .status(STATUS) .relationId(RELATION_ID) .relationVersion(RELATION_VERSION) 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 c6a8daf26..db34a67ab 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 @@ -28,10 +28,13 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.Optional; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -49,6 +52,8 @@ import org.springframework.security.access.AccessDeniedException; import de.ozgcloud.command.Command; import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; +import de.ozgcloud.command.VorgangLockedEvent; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted; import de.ozgcloud.vorgang.command.CommandTestFactory; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; @@ -507,4 +512,108 @@ class VorgangServiceTest { verify(repository).setAktenzeichen(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, null); } } + + @Nested + class TestLockVorgang { + + private static final Command LOCK_COMMAND = CommandTestFactory.create(); + private static final Map<String, Object> LOCK_PATCH = Map.of("key", "value"); + + @Captor + private ArgumentCaptor<VorgangLockedEvent> eventCaptor; + + @BeforeEach + void init() { + doNothing().when(service).validateLockCommand(any()); + doReturn(LOCK_PATCH).when(service).buildLockPatch(any()); + } + + @Test + void shouldCallValidateLockCommand() { + service.lockVorgang(LOCK_COMMAND); + + verify(service).validateLockCommand(LOCK_COMMAND); + } + + @Test + void shouldCallBuildLockPatch() { + service.lockVorgang(LOCK_COMMAND); + + verify(service).buildLockPatch(LOCK_COMMAND); + } + + @Test + void shouldCallRepository() { + service.lockVorgang(LOCK_COMMAND); + + verify(repository).patch(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, LOCK_PATCH); + } + + @Test + void shouldCallPublishEvent() { + service.lockVorgang(LOCK_COMMAND); + + verify(publisher).publishEvent(eventCaptor.capture()); + assertThat(eventCaptor.getValue().getCommand()).isSameAs(LOCK_COMMAND); + } + } + + @Nested + class TestValidateLockCommand { + + @Test + void shouldThrowExceptionOnMissingClient() { + var command = CommandTestFactory.createBuilder().createdByClient(null).build(); + + assertThrows(TechnicalException.class, () -> service.validateLockCommand(command)); + } + + @Test + void shouldThrowExceptionOnMissingReason() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build(); + + assertThrows(TechnicalException.class, () -> service.validateLockCommand(command)); + } + + @Test + void shouldAcceptValidCommand() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + + assertDoesNotThrow(() -> service.validateLockCommand(command)); + } + } + + @Nested + class TestBuildLockPatch { + + @Test + void shouldSetClientName() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + + var result = service.buildLockPatch(command); + + assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP) + .containsEntry(Lock.FIELD_CLIENT_NAME, CommandTestFactory.CREATED_BY_CLIENT); + } + + @Test + void shouldSetLockedSince() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + + var result = service.buildLockPatch(command); + + assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP) + .extractingByKey(Lock.FIELD_LOCKED_SINCE, InstanceOfAssertFactories.ZONED_DATE_TIME) + .isCloseTo(ZonedDateTime.now(), within(1, ChronoUnit.SECONDS)); + } + + @Test + void shouldSetReason() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + + var result = service.buildLockPatch(command); + + assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP).containsEntry(Lock.FIELD_REASON, LockTestFactory.REASON); + } + } } \ No newline at end of file -- GitLab