diff --git a/bescheid-manager/pom.xml b/bescheid-manager/pom.xml index 4da996d32dd21178fa46e1ccd3bd6efa1a786b1c..7e49b4339220cbfa22371a994b9ac6c1a037ef91 100644 --- a/bescheid-manager/pom.xml +++ b/bescheid-manager/pom.xml @@ -17,7 +17,8 @@ <properties> <vorgang-manager.version>2.13.0</vorgang-manager.version> <nachrichten-manager.version>2.9.0</nachrichten-manager.version> - <api-lib.version>0.11.0</api-lib.version> + <api-lib.version>0.12.0</api-lib.version> + <spring-cloud-config-client.version>4.1.3</spring-cloud-config-client.version> </properties> <dependencies> @@ -96,6 +97,11 @@ <optional>true</optional> </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-config</artifactId> + <version>${spring-cloud-config-client.version}</version> + </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/Bescheid.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/Bescheid.java index d181389e9cba0ebc0b7fa4f0ae3eecf9a1df3e3b..63f65d84733dae7ab98e63095234692c04f09dc7 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/Bescheid.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/Bescheid.java @@ -10,7 +10,7 @@ import lombok.Builder; import lombok.Getter; import lombok.Singular; -@Builder +@Builder(toBuilder = true) @Getter public class Bescheid { diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java index 6e6cdaf0d38f5e31d8ec32b6e6353ceb23b357ee..3beaadf3f4fd167bba8a29b34c613afe2348604c 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java @@ -106,7 +106,7 @@ class BescheidEventListener { } void doCreateBescheid(Command command) { - var createdItemId = attachedItemService.createBescheidDraft(command); + var createdItemId = service.createBescheidDraft(command); eventPublisher.publishEvent(new BescheidCreatedEvent(command, createdItemId)); } diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidMapper.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidMapper.java index 8abe425a3a1187b737bb41c851c1578a8db3e12c..28d4be14a789e33ff2b5b301c70341ad80f0b560 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidMapper.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidMapper.java @@ -1,9 +1,11 @@ package de.ozgcloud.bescheid; +import static de.ozgcloud.bescheid.Bescheid.*; + import java.time.LocalDate; -import java.time.ZonedDateTime; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -17,20 +19,27 @@ import org.mapstruct.Mapping; import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.ReportingPolicy; +import org.springframework.beans.factory.annotation.Autowired; -import de.ozgcloud.bescheid.Bescheid.SendBy; -import de.ozgcloud.bescheid.Bescheid.Status; import de.ozgcloud.bescheid.vorgang.VorgangId; +import de.ozgcloud.command.Command; import de.ozgcloud.common.attached_item.AttachedItem; +import de.ozgcloud.common.attached_item.AttachedItemService; import de.ozgcloud.common.binaryfile.FileId; +import de.ozgcloud.common.datatype.StringBasedValue; @Mapper(uses = { SentInfoMapper.class }, // unmappedTargetPolicy = ReportingPolicy.WARN, // collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, // nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, // nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) // -public interface BescheidMapper { +public abstract class BescheidMapper { + + @Autowired + private SentInfoMapper sentInfoMapper; + @Mapping(target = "sentInfoOrBuilder", ignore = true) + @Mapping(target = "defaultInstanceForType", ignore = true) @Mapping(target = "mergeFrom", ignore = true) @Mapping(target = "clearField", ignore = true) @Mapping(target = "clearOneof", ignore = true) @@ -49,50 +58,118 @@ public interface BescheidMapper { @Mapping(target = "nachrichtText", expression = "java(fromOptional(bescheid.getNachrichtText()))") @Mapping(target = "nachrichtSubject", expression = "java(fromOptional(bescheid.getNachrichtSubject()))") @Mapping(target = "attachmentsList", source = "attachments") - GrpcBescheid toBescheid(Bescheid bescheid); + abstract GrpcBescheid toBescheid(Bescheid bescheid); - default String toString(FileId fileId) { + String toString(FileId fileId) { return fileId.toString(); } - default String toString(BescheidId bescheidId) { + String toString(BescheidId bescheidId) { return bescheidId.toString(); } - default String fromOptional(Optional<String> optionalString) { + String fromOptional(Optional<String> optionalString) { return optionalString.orElse(StringUtils.EMPTY); } - default Bescheid mapFromAttachedItem(AttachedItem item) { - var itemMap = item.getItem(); - var builder = Bescheid.builder() + @Mapping(target = "featuresOrBuilder", ignore = true) + @Mapping(target = "defaultInstanceForType", ignore = true) + @Mapping(target = "mergeFrom", ignore = true) + @Mapping(target = "clearField", ignore = true) + @Mapping(target = "clearOneof", ignore = true) + @Mapping(target = "mergeFeatures", ignore = true) + @Mapping(target = "mergeUnknownFields", ignore = true) + @Mapping(target = "javaVersionBytes", ignore = true) + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "versionBytes", ignore = true) + @Mapping(target = "allFields", ignore = true) + abstract GrpcBescheidManagerConfigResponse fromBescheidManagerConfig(BescheidManagerConfig bescheidManagerConfig); + + @Mapping(target = "defaultInstanceForType", ignore = true) + @Mapping(target = "bescheidOrBuilder", ignore = true) + @Mapping(target = "bescheid", ignore = true) + @Mapping(target = "mergeFrom", ignore = true) + @Mapping(target = "clearField", ignore = true) + @Mapping(target = "clearOneof", ignore = true) + @Mapping(target = "mergeBescheid", ignore = true) + @Mapping(target = "mergeUnknownFields", ignore = true) + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "allFields", ignore = true) + abstract GrpcGetBescheidResponse toGetBescheidResponse(Bescheid bescheid); + + @Mapping(target = "defaultInstanceForType", ignore = true) + @Mapping(target = "bescheidOrBuilder", ignore = true) + @Mapping(target = "mergeFrom", ignore = true) + @Mapping(target = "clearField", ignore = true) + @Mapping(target = "clearOneof", ignore = true) + @Mapping(target = "mergeBescheid", ignore = true) + @Mapping(target = "mergeUnknownFields", ignore = true) + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "allFields", ignore = true) + abstract GrpcGetBescheidDraftResponse toGetBescheidDraftResponse(Bescheid bescheid); + + Bescheid mapFromAttachedItem(AttachedItem item) { + return buildBescheidBuilder(item.getItem()) .id(BescheidId.from(item.getId())) .version(item.getVersion()) .vorgangId(VorgangId.from(item.getVorgangId())) - .createdBy(UserId.from(MapUtils.getString(itemMap, Bescheid.FIELD_CREATED_BY))) - .bewilligt(MapUtils.getBoolean(itemMap, Bescheid.FIELD_BEWILLIGT)) - .nachrichtText(Optional.ofNullable(MapUtils.getString(itemMap, Bescheid.FIELD_NACHRICHT_TEXT))) - .nachrichtSubject(Optional.ofNullable(MapUtils.getString(itemMap, Bescheid.FIELD_NACHRICHT_SUBJECT))) - .status(Status.valueOf(MapUtils.getString(itemMap, Bescheid.FIELD_STATUS))) - .beschiedenAm(LocalDate.parse(MapUtils.getString(itemMap, Bescheid.FIELD_BESCHIEDEN_AM))); + .build(); + } - getBescheidDocument(itemMap).ifPresent(builder::bescheidDocument); - getAttachments(itemMap).ifPresent(builder::attachments); - getSendBy(itemMap).ifPresent(builder::sendBy); - getSentInfo(itemMap).ifPresent(builder::sentInfo); + Bescheid mapFromCommand(Command command) { + return buildBescheidBuilder(command.getBodyObject()) + .vorgangId(VorgangId.from(command.getVorgangId())) + .build(); + } + + private Bescheid.BescheidBuilder buildBescheidBuilder(Map<String, Object> bescheidMap) { + var bescheidBuilder = Bescheid.builder(); + Optional.ofNullable(MapUtils.getBoolean(bescheidMap, Bescheid.FIELD_BEWILLIGT)).ifPresent(bescheidBuilder::bewilligt); + getBeschiedenAm(bescheidMap).ifPresent(bescheidBuilder::beschiedenAm); + getStatus(bescheidMap).ifPresent(bescheidBuilder::status); + getCreatedBy(bescheidMap).ifPresent(bescheidBuilder::createdBy); + getBescheidDocument(bescheidMap).ifPresent(bescheidBuilder::bescheidDocument); + bescheidBuilder.nachrichtSubject(getNachrichtSubject(bescheidMap)); + bescheidBuilder.nachrichtText(getNachrichtText(bescheidMap)); + getSendBy(bescheidMap).ifPresent(bescheidBuilder::sendBy); + mapToAttachments(bescheidMap.get(Bescheid.FIELD_ATTACHMENTS)).ifPresent(bescheidBuilder::attachments); + getSentInfo(bescheidMap).ifPresent(bescheidBuilder::sentInfo); + return bescheidBuilder; + } + + Optional<LocalDate> getBeschiedenAm(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_BESCHIEDEN_AM).map(LocalDate::parse); + } + + Optional<Bescheid.Status> getStatus(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_STATUS).map(Bescheid.Status::valueOf); + } + + Optional<UserId> getCreatedBy(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_CREATED_BY).map(UserId::from); + } - return builder.build(); + Optional<SendBy> getSendBy(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_SEND_BY).map(SendBy::valueOf); } - default Optional<FileId> getBescheidDocument(Map<String, Object> itemMap) { - return Optional.ofNullable(MapUtils.getString(itemMap, Bescheid.FIELD_BESCHEID_DOCUMENT)).map(FileId::from); + Optional<FileId> getBescheidDocument(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_BESCHEID_DOCUMENT).map(FileId::from); } - default Optional<List<FileId>> getAttachments(Map<String, Object> itemMap) { - return mapToAttachments(MapUtils.getObject(itemMap, Bescheid.FIELD_ATTACHMENTS)); + private Optional<String> getNachrichtSubject(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_NACHRICHT_SUBJECT); } - default Optional<List<FileId>> mapToAttachments(Object attachments) { + private Optional<String> getNachrichtText(Map<String, Object> bescheidMap) { + return getStringValue(bescheidMap, Bescheid.FIELD_NACHRICHT_TEXT); + } + + private Optional<String> getStringValue(Map<String, Object> srcMap, String field) { + return Optional.ofNullable(MapUtils.getString(srcMap, field)).map(StringUtils::trimToNull); + } + + Optional<List<FileId>> mapToAttachments(Object attachments) { if (Objects.isNull(attachments) || StringUtils.isEmpty(String.valueOf(attachments))) { return Optional.empty(); } @@ -102,47 +179,55 @@ public interface BescheidMapper { return Optional.of(Collections.singletonList(FileId.from((String) attachments))); } - default Optional<SendBy> getSendBy(Map<String, Object> itemMap) { - return Optional.ofNullable(MapUtils.getString(itemMap, Bescheid.FIELD_SEND_BY)).map(SendBy::valueOf); + private Optional<SentInfo> getSentInfo(Map<String, Object> itemMap) { + return Optional.ofNullable(MapUtils.getMap(itemMap, Bescheid.FIELD_SENT_INFO)).map(sentInfoMapper::toSentInfo); } - default Optional<SentInfo> getSentInfo(Map<String, Object> itemMap) { - return Optional.ofNullable(MapUtils.getMap(itemMap, Bescheid.FIELD_SENT_INFO)).map(this::toSentInfo); + @Mapping(target = "client", constant = BescheidCallContextAttachingInterceptor.BESCHEID_MANAGER_CLIENT_NAME) + @Mapping(target = "itemName", constant = AttachedItemService.BESCHEID_ITEM_NAME) + @Mapping(target = "item", expression = "java(mapToItem(bescheid))") + public abstract AttachedItem mapFromBescheid(Bescheid bescheid); + + String mapToString(StringBasedValue value) { + return value.toString(); } - default SentInfo toSentInfo(Map<String, Object> sentInfoMap) { - return SentInfo.builder() - .sentBy(MapUtils.getString(sentInfoMap, SentInfo.FIELD_SENT_BY)) - .sentAt(ZonedDateTime.parse(MapUtils.getString(sentInfoMap, SentInfo.FIELD_SENT_AT))) - .build(); + public Map<String, Object> mapToItem(Bescheid bescheid) { + var result = new HashMap<String, Object>(); + result.put(Bescheid.FIELD_BEWILLIGT, bescheid.isBewilligt()); + mapBeschiedenAm(bescheid).ifPresent(beschiedenAm -> result.put(Bescheid.FIELD_BESCHIEDEN_AM, beschiedenAm)); + mapStatus(bescheid).ifPresent(status -> result.put(Bescheid.FIELD_STATUS, status)); + mapBescheidDocument(bescheid).ifPresent(bescheidDocumentId -> result.put(Bescheid.FIELD_BESCHEID_DOCUMENT, bescheidDocumentId)); + mapSendBy(bescheid).ifPresent(sendBy -> result.put(Bescheid.FIELD_SEND_BY, sendBy)); + bescheid.getNachrichtSubject().ifPresent(subject -> result.put(Bescheid.FIELD_NACHRICHT_SUBJECT, subject)); + bescheid.getNachrichtText().ifPresent(text -> result.put(Bescheid.FIELD_NACHRICHT_TEXT, text)); + mapSentInfo(bescheid).ifPresent(sentInfo -> result.put(FIELD_SENT_INFO, sentInfo)); + mapAttachmentIds(bescheid.getAttachments()).ifPresent(attachmentIds -> result.put(FIELD_ATTACHMENTS, attachmentIds)); + return Collections.unmodifiableMap(result); } - @Mapping(target = "mergeFrom", ignore = true) - @Mapping(target = "clearField", ignore = true) - @Mapping(target = "clearOneof", ignore = true) - @Mapping(target = "mergeFeatures", ignore = true) - @Mapping(target = "mergeUnknownFields", ignore = true) - @Mapping(target = "javaVersionBytes", ignore = true) - @Mapping(target = "unknownFields", ignore = true) - @Mapping(target = "versionBytes", ignore = true) - @Mapping(target = "allFields", ignore = true) - GrpcBescheidManagerConfigResponse fromBescheidManagerConfig(BescheidManagerConfig bescheidManagerConfig); + private Optional<String> mapBeschiedenAm(Bescheid bescheid) { + return Optional.ofNullable(bescheid.getBeschiedenAm()).map(LocalDate::toString); + } - @Mapping(target = "mergeFrom", ignore = true) - @Mapping(target = "clearField", ignore = true) - @Mapping(target = "clearOneof", ignore = true) - @Mapping(target = "mergeBescheid", ignore = true) - @Mapping(target = "mergeUnknownFields", ignore = true) - @Mapping(target = "unknownFields", ignore = true) - @Mapping(target = "allFields", ignore = true) - GrpcGetBescheidResponse toGetBescheidResponse(Bescheid bescheid); + private Optional<String> mapStatus(Bescheid bescheid) { + return Optional.ofNullable(bescheid.getStatus()).map(Bescheid.Status::name); + } + + private Optional<String> mapBescheidDocument(Bescheid bescheid) { + return Optional.ofNullable(bescheid.getBescheidDocument()).map(FileId::toString); + } + + private Optional<String> mapSendBy(Bescheid bescheid) { + return Optional.ofNullable(bescheid.getSendBy()).map(Bescheid.SendBy::name); + } + + public Optional<Map<String, Object>> mapSentInfo(Bescheid bescheid) { + return Optional.ofNullable(bescheid.getSentInfo()).map(sentInfoMapper::toMap); + } + + Optional<List<String>> mapAttachmentIds(List<FileId> attachments) { + return attachments.isEmpty() ? Optional.empty() : Optional.of(attachments.stream().map(FileId::toString).toList()); + } - @Mapping(target = "mergeFrom", ignore = true) - @Mapping(target = "clearField", ignore = true) - @Mapping(target = "clearOneof", ignore = true) - @Mapping(target = "mergeBescheid", ignore = true) - @Mapping(target = "mergeUnknownFields", ignore = true) - @Mapping(target = "unknownFields", ignore = true) - @Mapping(target = "allFields", ignore = true) - GrpcGetBescheidDraftResponse toGetBescheidDraftResponse(Bescheid bescheid); } \ No newline at end of file diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java index 372e07eb95400196f7cb1d540716314f5994ef44..cd1d2fc2ccb45a29beedfc74b4d90b7ecc8d559f 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java @@ -1,13 +1,17 @@ package de.ozgcloud.bescheid; +import static java.util.Objects.*; + import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; import jakarta.annotation.PostConstruct; @@ -22,7 +26,9 @@ 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.bescheid.administration.AdministrationService; import de.ozgcloud.bescheid.attributes.ClientAttributeService; +import de.ozgcloud.bescheid.common.freemarker.TemplateHandler; import de.ozgcloud.bescheid.common.user.UserProfileService; import de.ozgcloud.bescheid.vorgang.Vorgang; import de.ozgcloud.bescheid.vorgang.VorgangId; @@ -39,7 +45,11 @@ import lombok.extern.log4j.Log4j2; @Service @Log4j2 @RequiredArgsConstructor -class BescheidService { +public class BescheidService { + + static final String DEFAULT_NACHRICHT_SUBJECT = "Ihr Bescheid zum Antrag"; + public static final String DEFAULT_NACHRICHT_TEMPLATE_FILE = "bescheid.nachrichtTemplate.txt.ftlh"; + public static final String KEY_TEMPLATE_SIGNATURE = "signature"; private static final String ERROR_MESSAGE_NO_SERVICE = "No Bescheid Endpoint is configured."; @@ -60,12 +70,16 @@ class BescheidService { private final UserProfileService userProfileService; @Qualifier(BescheidManagerConfiguration.COMMAND_SERVICE_NAME) private final OzgCloudCommandService commandService; + private final AdministrationService administrationService; + private final CommandMapper commandMapper; private final ClientAttributeService bescheidClientAttributeService; private final BuildProperties buildProperties; private final Optional<BescheidRemoteService> remoteService; private final BescheidMapper mapper; + private final TemplateHandler templateHandler; + @PostConstruct void logStatus() { remoteService.ifPresentOrElse( @@ -74,13 +88,65 @@ class BescheidService { } public Optional<Bescheid> findDraft(String vorgangId) { - return attachedItemService.findBescheidItem(vorgangId).map(mapper::mapFromAttachedItem); + return attachedItemService.findBescheidItem(VorgangId.from(vorgangId)).map(mapper::mapFromAttachedItem); } public Stream<Bescheid> findAll(VorgangId vorgangId) { return attachedItemService.findAllBescheid(vorgangId).stream().map(mapper::mapFromAttachedItem); } + public String createBescheidDraft(Command createBescheidDraftCommand) { + validateBescheidData(createBescheidDraftCommand.getBodyObject()); + return attachedItemService.createBescheidDraft(buildBescheidDraft(createBescheidDraftCommand)); + } + + void validateBescheidData(Map<String, Object> bodyObject) { + validateBescheidField(bodyObject, Bescheid.FIELD_BESCHIEDEN_AM); + validateBescheidField(bodyObject, Bescheid.FIELD_BEWILLIGT); + validateSendBy(MapUtils.getString(bodyObject, Bescheid.FIELD_SEND_BY)); + } + + void validateBescheidField(Map<String, Object> bescheid, String field) { + if (isNull(bescheid.get(field))) { + throw new TechnicalException("Fields '%s' is required for bescheid creation".formatted(field)); + } + } + + void validateSendBy(String sendBy) { + if (isUnknownSendByValue(sendBy)) { + var possibleSendByValues = Arrays.stream(Bescheid.SendBy.values()).map(Bescheid.SendBy::name) + .collect(Collectors.joining(",")); + var message = String.format("Unexpected value for field '%s': %s. Allowed are: %s", Bescheid.FIELD_SEND_BY, sendBy, + possibleSendByValues); + throw new TechnicalException(message); + } + } + + private boolean isUnknownSendByValue(String sendByValue) { + return Arrays.stream(Bescheid.SendBy.values()).noneMatch(sendBy -> sendBy.hasValue(sendByValue)); + } + + Bescheid buildBescheidDraft(Command command) { + var bescheid = mapper.mapFromCommand(command); + var resultBuilder = bescheid.toBuilder().id(null).version(0).status(Bescheid.Status.DRAFT); + if (bescheid.getNachrichtSubject().isEmpty()) { + resultBuilder.nachrichtSubject(Optional.of(DEFAULT_NACHRICHT_SUBJECT)); + } + if (bescheid.getNachrichtText().isEmpty()) { + resultBuilder.nachrichtText(Optional.of(createNachrichtText())); + } + return resultBuilder.build(); + } + + String createNachrichtText() { + return templateHandler.fillTemplate(DEFAULT_NACHRICHT_TEMPLATE_FILE, getTemplateParameters()); + } + + Map<String, Object> getTemplateParameters() { + return administrationService.getNachrichtSignature().map(signature -> Map.<String, Object>of(KEY_TEMPLATE_SIGNATURE, signature)) + .orElseGet(Collections::emptyMap); + } + public BescheidResponse createBescheid(BescheidRequest request) { checkRemoteService(); diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/SentInfoMapper.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/SentInfoMapper.java index a16e4a4aa3a7717c0c74905602962de176537df4..95c5b586e88adc7881815f3331ad7213f5bcb530 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/SentInfoMapper.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/SentInfoMapper.java @@ -1,5 +1,12 @@ package de.ozgcloud.bescheid; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.collections.MapUtils; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -8,6 +15,9 @@ import org.mapstruct.ReportingPolicy; @Mapper(unmappedTargetPolicy = ReportingPolicy.WARN, collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) public interface SentInfoMapper { + String GRPC_DATE_TIME_FORMATTER = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + + @Mapping(target = "defaultInstanceForType", ignore = true) @Mapping(target = "mergeFrom", ignore = true) @Mapping(target = "clearField", ignore = true) @Mapping(target = "clearOneof", ignore = true) @@ -16,6 +26,20 @@ public interface SentInfoMapper { @Mapping(target = "sentByBytes", ignore = true) @Mapping(target = "unknownFields", ignore = true) @Mapping(target = "allFields", ignore = true) - @Mapping(target = "sentAt", source = "sentAt", dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'") + @Mapping(target = "sentAt", source = "sentAt", dateFormat = GRPC_DATE_TIME_FORMATTER) GrpcSentInfo mapTo(SentInfo sentInfo); + + default SentInfo toSentInfo(Map<String, Object> sentInfoMap) { + return SentInfo.builder() + .sentBy(MapUtils.getString(sentInfoMap, SentInfo.FIELD_SENT_BY)) + .sentAt(ZonedDateTime.parse(MapUtils.getString(sentInfoMap, SentInfo.FIELD_SENT_AT), DateTimeFormatter.ISO_DATE_TIME)) + .build(); + } + + default Map<String, Object> toMap(SentInfo sentInfo) { + var result = new HashMap<String, Object>(); + result.put(SentInfo.FIELD_SENT_BY, sentInfo.getSentBy()); + result.put(SentInfo.FIELD_SENT_AT, sentInfo.getSentAt().format(DateTimeFormatter.ISO_DATE_TIME)); + return Collections.unmodifiableMap(result); + } } diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationProperties.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..59f93a0239f649eb4156fb5512494e06749066d9 --- /dev/null +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationProperties.java @@ -0,0 +1,44 @@ +/* + * 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.bescheid.administration; + +import java.util.Optional; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@RefreshScope +@Configuration +@ConfigurationProperties(prefix = "ozgcloud.postfach") +public class AdministrationProperties { + + private Optional<String> signatur = Optional.empty(); + +} diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationService.java new file mode 100644 index 0000000000000000000000000000000000000000..920c5ea67d8285d1646b7840bf6c5fd91fb8c1ab --- /dev/null +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationService.java @@ -0,0 +1,47 @@ +/* + * 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.bescheid.administration; + +import java.util.Optional; + +import org.springframework.cloud.endpoint.RefreshEndpoint; +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AdministrationService { + + private final AdministrationProperties administrationProperties; + private final RefreshEndpoint refreshEndpoint; + + public Optional<String> getNachrichtSignature() { + return administrationProperties.getSignatur(); + } + + public void refreshConfig() { + refreshEndpoint.refresh(); + } +} diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationSyncScheduler.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationSyncScheduler.java new file mode 100644 index 0000000000000000000000000000000000000000..41fde870cc01fe94e9d2089742e77ffffd6a3f4a --- /dev/null +++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/administration/AdministrationSyncScheduler.java @@ -0,0 +1,43 @@ +/* + * 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.bescheid.administration; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@Component +@ConditionalOnProperty(value = "ozgcloud.administration.sync.enabled", havingValue = "true", matchIfMissing = true) +@RequiredArgsConstructor +public class AdministrationSyncScheduler { + + private final AdministrationService service; + + @Scheduled(initialDelayString = "${ozgcloud.administration.sync.delay}", fixedDelayString = "${ozgcloud.administration.sync.delay}") + public void sync() { + service.refreshConfig(); + } +} diff --git a/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemMapper.java b/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemMapper.java index 73d20952c8b05bf3fa0dd93c8d284c7583c319a5..c3431d175ebf43e14f6a7fd15baf34cb7b81a5f6 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemMapper.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemMapper.java @@ -23,13 +23,25 @@ */ package de.ozgcloud.common.attached_item; +import java.util.Map; + import org.mapstruct.Mapper; +import org.mapstruct.NullValueCheckStrategy; import de.ozgcloud.vorgang.common.grpc.GrpcObjectMapper; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem; -@Mapper(uses = { GrpcObjectMapper.class }) +@Mapper(uses = { GrpcObjectMapper.class }, nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) public interface AttachedItemMapper { AttachedItem mapFromVorgangAttachedItem(GrpcVorgangAttachedItem item); + + default Map<String, Object> toMap(AttachedItem attachedItem) { + return Map.of( + AttachedItem.PROPERTY_VORGANG_ID, attachedItem.getVorgangId(), + AttachedItem.PROPERTY_CLIENT, attachedItem.getClient(), + AttachedItem.PROPERTY_ITEM_NAME, attachedItem.getItemName(), + AttachedItem.PROPERTY_ITEM, attachedItem.getItem()); + } + } \ No newline at end of file diff --git a/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemService.java b/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemService.java index 551279332894c5c12395a7a43a2a93de52c180dc..d0ad2ed4e32a2eb9fe424440629f23e0e50e9331 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemService.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/AttachedItemService.java @@ -23,15 +23,11 @@ */ package de.ozgcloud.common.attached_item; -import static java.util.Objects.*; - -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collectors; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -45,7 +41,7 @@ import de.ozgcloud.bescheid.Bescheid; import de.ozgcloud.bescheid.Bescheid.Status; import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor; import de.ozgcloud.bescheid.BescheidManagerConfiguration; -import de.ozgcloud.bescheid.common.freemarker.TemplateHandler; +import de.ozgcloud.bescheid.BescheidMapper; import de.ozgcloud.bescheid.vorgang.VorgangId; import de.ozgcloud.command.Command; import de.ozgcloud.common.errorhandling.TechnicalException; @@ -62,16 +58,15 @@ public class AttachedItemService { static final String UPDATE_ATTACHED_ITEM_ORDER = "UPDATE_ATTACHED_ITEM"; static final String DELETE_ATTACHED_ITEM = "DELETE_ATTACHED_ITEM"; - static final String DEFAULT_SUBJECT = "Ihr Bescheid zum Antrag"; - static final String DEFAULT_TEMPLATE_FILE = "bescheid.nachrichtTemplate.txt.ftlh"; - @Qualifier(BescheidManagerConfiguration.COMMAND_SERVICE_NAME) private final OzgCloudCommandService commandService; private final VorgangAttachedItemRemoteService remoteService; + private final CommandMapper commandMapper; - private final TemplateHandler templateHandler; + private final AttachedItemMapper attachedItemMapper; + private final BescheidMapper bescheidMapper; - public Optional<AttachedItem> findBescheidItem(String vorgangId) { + public Optional<AttachedItem> findBescheidItem(VorgangId vorgangId) { return remoteService.findBescheidDraft(vorgangId); } @@ -79,41 +74,20 @@ public class AttachedItemService { return remoteService.getItem(id); } - public String createBescheidDraft(Command command) { - validateBescheidData(command.getBodyObject()); - return remoteService.findBescheidDraft(command.getVorgangId()) - .map(bescheid -> overrideAttachedItem(bescheid, command)).orElseGet(() -> createAttachedItem(command)); - } - - void validateBescheidData(Map<String, Object> bodyObject) { - validateBescheidField(bodyObject, Bescheid.FIELD_BESCHIEDEN_AM); - validateBescheidField(bodyObject, Bescheid.FIELD_BEWILLIGT); - validateSendBy(getSendBy(bodyObject)); - } - - void validateBescheidField(Map<String, Object> bescheid, String field) { - if (isNull(bescheid.get(field))) { - throw new TechnicalException("Fields '%s' is required for bescheid creation".formatted(field)); - } - } - - void validateSendBy(String sendBy) { - if (isUnknownSendByValue(sendBy)) { - var possibleSendByValues = Arrays.stream(Bescheid.SendBy.values()).map(Bescheid.SendBy::name) - .collect(Collectors.joining(",")); - var message = String.format("Unexpected value for field '%s': %s. Allowed are: %s", Bescheid.FIELD_SEND_BY, sendBy, - possibleSendByValues); - throw new TechnicalException(message); - } + public String createBescheidDraft(Bescheid bescheidDraft) { + return remoteService.findBescheidDraft(bescheidDraft.getVorgangId()) + .map(bescheidItem -> overrideAttachedItem(mergeBescheidDrafts(bescheidItem, bescheidDraft))) + .orElseGet(() -> createAttachedItem(bescheidDraft)); } - private boolean isUnknownSendByValue(String sendByValue) { - return Arrays.stream(Bescheid.SendBy.values()).noneMatch(sendBy -> sendBy.hasValue(sendByValue)); + AttachedItem mergeBescheidDrafts(AttachedItem existingBescheidItem, Bescheid newBescheidDraft) { + return existingBescheidItem.toBuilder() + .item(bescheidMapper.mapToItem(newBescheidDraft)) + .build(); } - String overrideAttachedItem(AttachedItem bescheidItem, Command command) { - var attachedItem = buildAttachedItemAsMap(command, buildItemMapWithAllBescheidFields(command)); - var finishedOzgCloudCommand = commandService.createAndWaitUntilDone(buildPatchAttachedItemCommand(bescheidItem, attachedItem)); + String overrideAttachedItem(AttachedItem bescheidItem) { + var finishedOzgCloudCommand = commandService.createAndWaitUntilDone(buildPatchAttachedItemCommand(bescheidItem, bescheidItem.getItem())); return finishedOzgCloudCommand.getCreatedResource(); } @@ -178,16 +152,17 @@ public class AttachedItemService { .build(); } - String createAttachedItem(Command command) { - return commandService.createAndWaitUntilDone(buildCreateAttachedItemCommand(command)).getCreatedResource(); + String createAttachedItem(Bescheid bescheidDraft) { + var bescheidItem = bescheidMapper.mapFromBescheid(bescheidDraft); + return commandService.createAndWaitUntilDone(buildCreateAttachedItemCommand(bescheidItem)).getCreatedResource(); } - OzgCloudCommand buildCreateAttachedItemCommand(Command command) { + OzgCloudCommand buildCreateAttachedItemCommand(AttachedItem bescheidItem) { return OzgCloudCommand.builder() - .vorgangId(commandMapper.toOzgCloudVorgangId(command.getVorgangId())) - .relationId(commandMapper.mapRelationId(command.getRelationId())) + .vorgangId(commandMapper.toOzgCloudVorgangId(bescheidItem.getVorgangId())) + .relationId(commandMapper.mapRelationId(bescheidItem.getVorgangId())) .order(CREATE_ATTACHED_ITEM_ORDER) - .bodyObject(buildAttachedItemAsMap(command, buildCreateBescheidItemMap(command))).build(); + .bodyObject(attachedItemMapper.toMap(bescheidItem)).build(); } Map<String, Object> buildAttachedItemAsMap(Command command, Map<String, Object> itemMap) { @@ -199,17 +174,6 @@ public class AttachedItemService { return result; } - Map<String, Object> buildCreateBescheidItemMap(Command command) { - var result = buildItemMapWithExistingBescheidFields(command); - if (StringUtils.isEmpty(getNachrichtSubject(command))) { - result.put(Bescheid.FIELD_NACHRICHT_SUBJECT, DEFAULT_SUBJECT); - } - if (StringUtils.isEmpty(getNachrichtText(command))) { - result.put(Bescheid.FIELD_NACHRICHT_TEXT, templateHandler.getRawTemplate(DEFAULT_TEMPLATE_FILE)); - } - return result; - } - Map<String, Object> buildItemMapWithExistingBescheidFields(Command command) { var result = buildItemMap(Bescheid.Status.DRAFT); addValueFromMapIfExists(command.getBodyObject(), Bescheid.FIELD_BESCHIEDEN_AM, result); @@ -222,14 +186,6 @@ public class AttachedItemService { return result; } - private String getNachrichtSubject(Command command) { - return MapUtils.getString(command.getBodyObject(), Bescheid.FIELD_NACHRICHT_SUBJECT); - } - - private String getNachrichtText(Command command) { - return MapUtils.getString(command.getBodyObject(), Bescheid.FIELD_NACHRICHT_TEXT); - } - void addValueFromMapIfExists(Map<String, Object> sourceMap, String key, Map<String, Object> targetMap) { if (sourceMap.containsKey(key)) { targetMap.put(key, sourceMap.get(key)); diff --git a/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteService.java b/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteService.java index 6bc59454c9bd380608d7594e82a4df4f48174101..1d8756a0c968d0463e6f94391afb91fad9143c04 100644 --- a/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteService.java +++ b/bescheid-manager/src/main/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteService.java @@ -62,8 +62,8 @@ class VorgangAttachedItemRemoteService { @Autowired private AttachedItemMapper attachedItemMapper; - public Optional<AttachedItem> findBescheidDraft(String vorgangId) { - return findBescheidDraft(buildFindRequest(vorgangId)); + public Optional<AttachedItem> findBescheidDraft(VorgangId vorgangId) { + return findBescheidDraft(buildFindRequest(vorgangId.toString())); } public List<AttachedItem> findAllBescheid(VorgangId vorgangId) { diff --git a/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh b/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh index 368804ed6ea51f622c32a2e90a21d5f1dd00763f..a16717f3fed5f7943af7f6cb701e085bdebeebb9 100644 --- a/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh +++ b/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh @@ -2,6 +2,6 @@ Sehr geehrte/r Antragsteller/in, im Folgenden erhalten Sie Ihren Bescheid. -Mit freundlichen Grüßen +${(signature)!"Mit freundlichen Grüßen -Ihre Verwaltung \ No newline at end of file +Ihre Verwaltung"} \ No newline at end of file diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java index 2700586f2f8dd27bd9940ad790f6d2cc395370df..66403e2e7b83b2ac4ce30cb2b532cbdca881da64 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java @@ -64,7 +64,7 @@ class BescheidEventListenerITCase { void shouldCallService() { publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(command)); - verify(attachedItemService).createBescheidDraft(command); + verify(service).createBescheidDraft(command); } @Test diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java index 5d2d0689225962c1127644fe1f38063cb1e13c01..a3734e17d99a07d77410d213ebbe30415424cb1f 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java @@ -106,14 +106,14 @@ class BescheidEventListenerTest { void shouldCallCreateBescheidDraft() { listener.doCreateBescheid(COMMAND); - verify(attachedItemService).createBescheidDraft(COMMAND); + verify(service).createBescheidDraft(COMMAND); } @Test @DisplayName("should publish BescheidCreatedEvent after creating BescheidDraft") void shouldPublishBescheidCreatedEventWithCommand() { var createdResource = "item-id"; - when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource); + when(service.createBescheidDraft(any())).thenReturn(createdResource); listener.doCreateBescheid(COMMAND); @@ -125,7 +125,7 @@ class BescheidEventListenerTest { @DisplayName("should publish BescheidCreatedEvent with created resource") void shouldPublishBescheidCreatedEventWithCreatedResource() { var createdResource = "item-id"; - when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource); + when(service.createBescheidDraft(any())).thenReturn(createdResource); listener.doCreateBescheid(COMMAND); @@ -497,7 +497,7 @@ class BescheidEventListenerTest { private static final Command COMMAND = CommandTestFactory.createBuilder().relationId(AttachedItemTestFactory.ID) .relationVersion(AttachedItemTestFactory.VERSION).bodyObject(AttachedItemTestFactory.createBescheidItem()).build(); - private AttachedItem bescheidItem = createManuallyBescheidItem(); + private final AttachedItem bescheidItem = createManuallyBescheidItem(); private AttachedItem createManuallyBescheidItem() { var attachedItem = AttachedItemTestFactory.createBescheid(); diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidMapperTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidMapperTest.java index 8feda3dfe1ac673133247f758d71d3a413fa4a52..4e867c490dcc6bdcecd99e3b26cbc221caf686be 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidMapperTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidMapperTest.java @@ -6,6 +6,7 @@ import static org.mockito.Mockito.*; import java.util.Collections; import java.util.List; +import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; @@ -17,10 +18,14 @@ import org.mockito.InjectMocks; import org.mockito.Spy; import de.ozgcloud.bescheid.vorgang.VorgangTestFactory; +import de.ozgcloud.command.CommandTestFactory; +import de.ozgcloud.common.attached_item.AttachedItemService; import de.ozgcloud.common.attached_item.AttachedItemTestFactory; +import de.ozgcloud.document.DocumentTestFactory; class BescheidMapperTest { + @Spy @InjectMocks private final BescheidMapper mapper = Mappers.getMapper(BescheidMapper.class); @Spy @@ -45,9 +50,7 @@ class BescheidMapperTest { void shouldMapAllFields() { var result = mapper.toBescheid(BescheidTestFactory.create()); - assertThat(result).usingRecursiveComparison() - .ignoringFields("memoizedHashCode", "sentInfo_") - .isEqualTo(GrpcBescheidWithoutDocumentTestFactory.create()); + assertThat(result).usingRecursiveComparison().isEqualTo(GrpcBescheidWithoutDocumentTestFactory.create()); } } @@ -120,4 +123,139 @@ class BescheidMapperTest { assertThat(response).usingRecursiveComparison().isEqualTo(GrpcGetBescheidDraftResponseTestFactory.create()); } } + + @DisplayName("Map from command") + @Nested + class TestMapFromCommand { + + @Test + void shouldMap() { + var command = CommandTestFactory.createBuilder().bodyObject(AttachedItemTestFactory.createBescheidItem()) + .vorgangId(VorgangTestFactory.ID_STR).build(); + + var result = mapper.mapFromCommand(command); + + assertThat(result).usingRecursiveComparison().ignoringFields("id", "version").isEqualTo(BescheidTestFactory.create()); + } + } + + @Nested + class TestMapFromBescheid { + + @Test + void shouldSetClient() { + var result = mapper.mapFromBescheid(BescheidTestFactory.create()); + + assertThat(result.getClient()).isEqualTo(BescheidCallContextAttachingInterceptor.BESCHEID_MANAGER_CLIENT_NAME); + } + + @Test + void shouldSetItemName() { + var result = mapper.mapFromBescheid(BescheidTestFactory.create()); + + assertThat(result.getItemName()).isEqualTo(AttachedItemService.BESCHEID_ITEM_NAME); + } + + @Test + void shouldCallMapBescheidToItem() { + var bescheid = BescheidTestFactory.create(); + + mapper.mapFromBescheid(bescheid); + + verify(mapper).mapToItem(bescheid); + } + + @Test + void shouldSetItem() { + var itemMap = Map.<String, Object>of("key", "value"); + doReturn(itemMap).when(mapper).mapToItem(any()); + + var result = mapper.mapFromBescheid(BescheidTestFactory.create()); + + assertThat(result.getItem()).isEqualTo(itemMap); + } + } + + @Nested + class TestMapBescheidToItem { + + @Test + void shouldSetBewilligt() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_BEWILLIGT, BescheidTestFactory.BEWILLIGT); + } + + @Test + void shouldSetBeschiedenAm() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_BESCHIEDEN_AM, BescheidTestFactory.BESCHIEDEN_AM_STR); + } + + @Test + void shouldSetStatus() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_STATUS, BescheidTestFactory.STATUS.name()); + } + + @Test + void shouldSetBescheidDocument() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result.get(Bescheid.FIELD_BESCHEID_DOCUMENT)).hasToString(DocumentTestFactory.ID); + } + + @Test + void shouldSetSendBy() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_SEND_BY, BescheidTestFactory.SEND_BY.name()); + } + + @Test + void shouldSetNachrichtSubject() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_NACHRICHT_SUBJECT, BescheidTestFactory.NACHRICHT_SUBJECT); + } + + @Test + void shouldSetNachrichtText() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_NACHRICHT_TEXT, BescheidTestFactory.NACHRICHT_TEXT); + } + + @Test + void shouldCallSentInfoMapper() { + mapper.mapToItem(BescheidTestFactory.create()); + + verify(sentInfoMapper).toMap(BescheidTestFactory.SENT_INFO); + } + + @Test + void shouldSetSentInfo() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_SENT_INFO, SentInfoTestFactory.asMap()); + } + + @Test + void shouldSetAttachments() { + var result = mapper.mapToItem(BescheidTestFactory.create()); + + assertThat(result).containsEntry(Bescheid.FIELD_ATTACHMENTS, + List.of(BescheidTestFactory.ATTACHMENT_STR, BescheidTestFactory.ATTACHMENT_STR)); + } + + @Test + void shouldNotAddEmptyEntries() { + var result = mapper.mapToItem(Bescheid.builder().build()); + + assertThat(result).containsOnlyKeys(Bescheid.FIELD_BEWILLIGT); + } + } + } \ No newline at end of file diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java index 1bfa29f025365178aa5a66816db937b5670b2536..e593e429c550d90454013369ab01640091b5afef 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java @@ -1,7 +1,6 @@ package de.ozgcloud.bescheid; 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.*; @@ -41,7 +40,9 @@ import de.ozgcloud.apilib.common.datatypes.GenericId; import de.ozgcloud.apilib.user.OzgCloudUserId; import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId; import de.ozgcloud.bescheid.Bescheid.SendBy; +import de.ozgcloud.bescheid.administration.AdministrationService; import de.ozgcloud.bescheid.attributes.ClientAttributeService; +import de.ozgcloud.bescheid.common.freemarker.TemplateHandler; import de.ozgcloud.bescheid.common.user.UserProfile; import de.ozgcloud.bescheid.common.user.UserProfileService; import de.ozgcloud.bescheid.common.user.UserProfileTestFactory; @@ -85,6 +86,10 @@ class BescheidServiceTest { private BescheidRemoteService remoteService; @Mock private BescheidMapper mapper; + @Mock + private AdministrationService administrationService; + @Mock + private TemplateHandler templateHandler; @BeforeEach void init() { @@ -108,7 +113,7 @@ class BescheidServiceTest { void shouldCallVorgangAttachedItemRemoteService() { service.findDraft(VorgangTestFactory.ID_STR); - verify(attachedItemService).findBescheidItem(VorgangTestFactory.ID_STR); + verify(attachedItemService).findBescheidItem(VorgangTestFactory.ID); } @Test @@ -165,6 +170,254 @@ class BescheidServiceTest { } } + @Nested + class TestCreateBescheidDraft { + + private static final Map<String, Object> COMMAND_BODY = Map.of("key", "value"); + private static final Command COMMAND = CommandTestFactory.createBuilder().bodyObject(COMMAND_BODY).build(); + private static final Bescheid BESCHEID_DRAFT = BescheidTestFactory.create(); + + @BeforeEach + void init() { + doNothing().when(service).validateBescheidData(any()); + doReturn(BESCHEID_DRAFT).when(service).buildBescheidDraft(any()); + } + + @Test + void shouldCallValidateBescheidData() { + service.createBescheidDraft(COMMAND); + + verify(service).validateBescheidData(COMMAND_BODY); + } + + @Test + void shouldCallAttachedItemService() { + service.createBescheidDraft(COMMAND); + + verify(attachedItemService).createBescheidDraft(BESCHEID_DRAFT); + } + + @Test + void shouldReturnResult() { + var createdBescheidId = "created-bescheid-id"; + when(attachedItemService.createBescheidDraft(any(Bescheid.class))).thenReturn(createdBescheidId); + + var result = service.createBescheidDraft(COMMAND); + + assertThat(result).isEqualTo(createdBescheidId); + } + } + + @Nested + class TestValidateBescheidData { + + private static final Command CREATE_BESCHEID_DRAFT_COMMAND = CommandTestFactory.createBuilder() + .bodyObject(AttachedItemTestFactory.createBescheidItem()).build(); + + @Test + void shouldValidate() { + assertDoesNotThrow(() -> service.validateBescheidData(CREATE_BESCHEID_DRAFT_COMMAND.getBodyObject())); + } + + @DisplayName("should fail if bescheidAm is missing") + @Test + void shouldThrowExceptionByBescheidAm() { + var map = Map.<String, Object>of(Bescheid.FIELD_BEWILLIGT, true); + + assertThrows(TechnicalException.class, () -> service.validateBescheidData(map)); + } + + @DisplayName("should fail if bewilligt is missing") + @Test + void shouldThrowExceptionByBewilligt() { + var map = Map.<String, Object>of(Bescheid.FIELD_BESCHIEDEN_AM, "2021-01-01"); + + assertThrows(TechnicalException.class, () -> service.validateBescheidData(map)); + } + + @Test + void shouldValidateSendBy() { + var bodyObject = Map.<String, Object>of(Bescheid.FIELD_SEND_BY, SendBy.MANUAL.name()); + doNothing().when(service).validateBescheidField(any(), any()); + + service.validateBescheidData(bodyObject); + + verify(service).validateSendBy(SendBy.MANUAL.name()); + } + + @DisplayName("validate sendBy") + @Nested + class TestValidateSendBy { + + @ValueSource(strings = { "not-exist", "" }) + @ParameterizedTest + void shouldThrowExceptionOnNonExistingSendByValue(String sendBy) { + assertThrows(TechnicalException.class, () -> service.validateSendBy(sendBy)); + } + + @EnumSource(names = { "NACHRICHT", "MANUAL" }) + @ParameterizedTest + void shouldNotThrowAnyExceptionOnExistingSendByValue(SendBy sendBy) { + assertDoesNotThrow(() -> service.validateSendBy(sendBy.name())); + } + } + } + + @Nested + class TestBuildBescheidDraft { + + private static final Command CREATE_BESCHEID_DRAFT_COMMAND = CommandTestFactory.createBuilder() + .bodyObject(AttachedItemTestFactory.createBescheidItem()).build(); + + private final Bescheid bescheid = BescheidTestFactory.createBuilder().status(Bescheid.Status.SENT).build(); + + @BeforeEach + void init() { + when(mapper.mapFromCommand(any())).thenReturn(bescheid); + } + + @Test + void shouldCallMapFromCommand() { + buildBescheidDraft(); + + verify(mapper).mapFromCommand(CREATE_BESCHEID_DRAFT_COMMAND); + } + + @Test + void shouldResetId() { + var result = buildBescheidDraft(); + + assertThat(result.getId()).isNull(); + } + + @Test + void shouldResetVersion() { + var result = buildBescheidDraft(); + + assertThat(result.getVersion()).isZero(); + } + + @Test + void shouldSetStatus() { + var result = buildBescheidDraft(); + + assertThat(result.getStatus()).isEqualTo(Bescheid.Status.DRAFT); + } + + @Test + void shouldNotOverrideNachrichtSubject() { + var result = buildBescheidDraft(); + + assertThat(result.getNachrichtSubject()).contains(BescheidTestFactory.NACHRICHT_SUBJECT); + } + + @Test + void shouldSetNachrichtSubject() { + var bescheid = BescheidTestFactory.createBuilder().nachrichtSubject(Optional.empty()).build(); + when(mapper.mapFromCommand(any())).thenReturn(bescheid); + + var result = buildBescheidDraft(); + + assertThat(result.getNachrichtSubject()).contains(BescheidService.SUBJECT); + } + + @Test + void shouldNotOverrideNachrichtText() { + var result = buildBescheidDraft(); + + assertThat(result.getNachrichtText()).contains(BescheidTestFactory.NACHRICHT_TEXT); + } + + @Test + void shouldCallCreateNachrichtText() { + var createdText = "created text"; + doReturn(createdText).when(service).createNachrichtText(); + var bescheid = BescheidTestFactory.createBuilder().nachrichtText(Optional.empty()).build(); + when(mapper.mapFromCommand(any())).thenReturn(bescheid); + + buildBescheidDraft(); + + verify(service).createNachrichtText(); + } + + @Test + void shouldSetNachrichtText() { + var createdText = "created text"; + doReturn(createdText).when(service).createNachrichtText(); + var bescheid = BescheidTestFactory.createBuilder().nachrichtText(Optional.empty()).build(); + when(mapper.mapFromCommand(any())).thenReturn(bescheid); + + var result = buildBescheidDraft(); + + assertThat(result.getNachrichtText()).contains(createdText); + } + + private Bescheid buildBescheidDraft() { + return service.buildBescheidDraft(CREATE_BESCHEID_DRAFT_COMMAND); + } + } + + @Nested + class TestCreateNachrichtText { + + @Captor + private ArgumentCaptor<Map<String, Object>> signatureCaptor; + + @Test + void shouldCallGetTemplateParameters() { + service.createNachrichtText(); + + verify(service).getTemplateParameters(); + } + + @Test + void shouldCallFillTemplate() { + var parameterMap = Map.<String, Object>of("key", "value"); + doReturn(parameterMap).when(service).getTemplateParameters(); + + service.createNachrichtText(); + + verify(templateHandler).fillTemplate(BescheidService.DEFAULT_NACHRICHT_TEMPLATE_FILE, parameterMap); + } + + @Test + void shouldReturnNachricht() { + when(templateHandler.fillTemplate(any(), any())).thenReturn(BescheidTestFactory.NACHRICHT_TEXT); + + var result = service.createNachrichtText(); + + assertThat(result).isEqualTo(BescheidTestFactory.NACHRICHT_TEXT); + } + } + + @Nested + class TestGetTemplateParameters { + + @Test + void shouldCallAdministrationService() { + service.createNachrichtText(); + + verify(administrationService).getNachrichtSignature(); + } + + @Test + void shouldReturnParameters() { + var signature = "signature"; + when(administrationService.getNachrichtSignature()).thenReturn(Optional.of(signature)); + + var result = service.getTemplateParameters(); + + assertThat(result).containsEntry(BescheidService.KEY_TEMPLATE_SIGNATURE, signature); + } + + @Test + void shouldReturnEmptyMap() { + var result = service.getTemplateParameters(); + + assertThat(result).isEmpty(); + } + } + @Nested class TestCreateBescheid { diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java index 9bbaa5728dc689fe6d70fe510af8ae909b65ae7f..b04cada3828d9fae6a85c5217c97df420972f353 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java @@ -3,6 +3,7 @@ package de.ozgcloud.bescheid; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.cloud.endpoint.RefreshEndpoint; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.security.authentication.AuthenticationTrustResolver; @@ -14,6 +15,8 @@ public class BescheidTestApplication { @MockBean private BuildProperties buildProperties; + @MockBean + private RefreshEndpoint refreshEndpoint; @Bean AuthenticationTrustResolver trustResolver() { diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java index 326882334bbe54cd6987bf3eb812f1e086639642..7b90a2215cbddb56900ea293d7bbfd5cb9f44363 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java @@ -19,6 +19,7 @@ public class BescheidTestFactory { public final static boolean BEWILLIGT = true; + public final static BescheidId ID = BescheidId.from(AttachedItemTestFactory.ID); public final static Status STATUS = Status.DRAFT; public final static String BESCHIEDEN_AM_STR = "2021-01-10"; public final static LocalDate BESCHIEDEN_AM = LocalDate.parse(BESCHIEDEN_AM_STR); @@ -39,7 +40,7 @@ public class BescheidTestFactory { public static Bescheid.BescheidBuilder createBuilder() { return Bescheid.builder() - .id(BescheidId.from(AttachedItemTestFactory.ID)) + .id(ID) .version(AttachedItemTestFactory.VERSION) .vorgangId(VorgangTestFactory.ID) .createdBy(UserProfileTestFactory.ID) diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/SentInfoMapperTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/SentInfoMapperTest.java index 2fa8f14b830b3c980e207d41ef1af3cafe69d00b..c3f9eea19a4f802f8214371b024f5bc3b7e08453 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/SentInfoMapperTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/SentInfoMapperTest.java @@ -9,7 +9,7 @@ import org.mapstruct.factory.Mappers; class SentInfoMapperTest { - private SentInfoMapper mapper = Mappers.getMapper(SentInfoMapper.class); + private final SentInfoMapper mapper = Mappers.getMapper(SentInfoMapper.class); @DisplayName("Map to") @Nested @@ -22,4 +22,28 @@ class SentInfoMapperTest { assertThat(mappedSentInfo).usingRecursiveComparison().isEqualTo(GrpcSentInfoTestFactory.create()); } } + + @DisplayName("Map to SentInfo") + @Nested + class TestToSentInfo { + + @Test + void shouldMap() { + var mappedSentInfo = mapper.toSentInfo(SentInfoTestFactory.asMap()); + + assertThat(mappedSentInfo).usingRecursiveComparison().isEqualTo(SentInfoTestFactory.create()); + } + } + + @DisplayName("As map") + @Nested + class TestAsMap { + + @Test + void shouldMap() { + var mappedSentInfo = mapper.toMap(SentInfoTestFactory.create()); + + assertThat(mappedSentInfo).isEqualTo(SentInfoTestFactory.asMap()); + } + } } diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/administration/AdministrationServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/administration/AdministrationServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..13e64879f85860b95b1e2a71154e56dced290343 --- /dev/null +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/administration/AdministrationServiceTest.java @@ -0,0 +1,78 @@ +/* + * 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.bescheid.administration; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.cloud.endpoint.RefreshEndpoint; + +class AdministrationServiceTest { + + @InjectMocks + private AdministrationService service; + + @Mock + private AdministrationProperties properties; + @Mock + private RefreshEndpoint refreshEndpoint; + + @Nested + class GetNachrichtSignature { + + @Test + void shouldCallGetSignature() { + service.getNachrichtSignature(); + + verify(properties).getSignatur(); + } + + @Test + void shouldReturnSignature() { + var signature = "signature"; + when(properties.getSignatur()).thenReturn(Optional.of(signature)); + + var result = service.getNachrichtSignature(); + + assertThat(result).contains(signature); + } + } + + @Nested + class TestRefreshConfig { + + @Test + void shouldCallRefresh() { + service.refreshConfig(); + + verify(refreshEndpoint).refresh(); + } + } +} \ No newline at end of file diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java index 071cb7d7ee00b57de1a217ccef7e4522df18a4c9..eeca8c0c770782be6364a6f9ae130e440a1168d7 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java @@ -2,6 +2,9 @@ package de.ozgcloud.bescheid.common.freemarker; import static org.assertj.core.api.Assertions.*; +import java.util.Collections; +import java.util.Map; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -10,6 +13,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import de.ozgcloud.apilib.common.command.OzgCloudCommandService; import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.bescheid.BescheidService; import de.ozgcloud.common.test.ITCase; @ITCase @@ -39,4 +43,32 @@ class TemplateHandlerITCase { .contains("Mit freundlichen Grüßen"); } } + + @DisplayName("Fill template") + @Nested + class TestFillTemplate { + + @Test + void shouldReturnFilledTemplate() { + var signatur = "ganz andere Signatur"; + var content = handler.fillTemplate(BescheidService.DEFAULT_NACHRICHT_TEMPLATE_FILE, + Map.of(BescheidService.KEY_TEMPLATE_SIGNATURE, signatur)); + + assertThat(content) + .contains("Sehr geehrte/r Antragsteller/in") + .contains("im Folgenden erhalten Sie Ihren Bescheid.") + .contains(signatur); + } + + @Test + void shouldReturnWithDefaultValue() { + var content = handler.fillTemplate(BescheidService.DEFAULT_NACHRICHT_TEMPLATE_FILE, Collections.emptyMap()); + + assertThat(content) + .contains("Sehr geehrte/r Antragsteller/in") + .contains("im Folgenden erhalten Sie Ihren Bescheid.") + .contains("Mit freundlichen Grüßen") + .contains("Ihre Verwaltung"); + } + } } diff --git a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemMapperTest.java b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemMapperTest.java index 986f208f2f4ab75effbf1a4c42744624a2f8f202..25998524cc118900d7f705f2ff8c7268e2007b7b 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemMapperTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemMapperTest.java @@ -27,6 +27,8 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Map; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -35,6 +37,8 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; +import de.ozgcloud.bescheid.SentInfoMapper; +import de.ozgcloud.command.CommandTestFactory; import de.ozgcloud.document.DocumentService; import de.ozgcloud.vorgang.common.grpc.GrpcObjectMapper; @@ -46,6 +50,8 @@ class AttachedItemMapperTest { @Mock private GrpcObjectMapper grpcObjectMapper; + @Mock + private SentInfoMapper sentInfoMapper; @Nested class TestMapFromVorgangAttachedItem { @@ -64,4 +70,39 @@ class AttachedItemMapperTest { assertThat(result).usingRecursiveComparison().isEqualTo(AttachedItemTestFactory.createDocument()); } } + + @Nested + class TestAsMap { + + @Test + void shouldSetVorgangId() { + var result = mapper.toMap(AttachedItemTestFactory.createBescheid()); + + assertThat(result).containsEntry(AttachedItem.PROPERTY_VORGANG_ID, CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldSetClient() { + var result = mapper.toMap(AttachedItemTestFactory.createBescheid()); + + assertThat(result).containsEntry(AttachedItem.PROPERTY_CLIENT, AttachedItemTestFactory.CLIENT); + } + + @Test + void shouldSetItemName() { + var result = mapper.toMap(AttachedItemTestFactory.createBescheid()); + + assertThat(result).containsEntry(AttachedItem.PROPERTY_ITEM_NAME, AttachedItemService.BESCHEID_ITEM_NAME); + } + + @Test + void shouldSetItem() { + var item = Map.<String, Object>of("key", "value"); + var attachedItem = AttachedItemTestFactory.createBescheidBuilder().clearItem().item(item).build(); + + var result = mapper.toMap(attachedItem); + + assertThat(result).containsEntry(AttachedItem.PROPERTY_ITEM, item); + } + } } \ No newline at end of file diff --git a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemServiceTest.java index 1c2e8557104da84c83ebc6d37565bc357c5461e9..aaa9b15a805e2c989b97f0d77577c2499ec18a56 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemServiceTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemServiceTest.java @@ -34,32 +34,23 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; 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.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; -import com.thedeanda.lorem.LoremIpsum; - import de.ozgcloud.apilib.common.command.OzgCloudCommand; import de.ozgcloud.apilib.common.command.OzgCloudCommandService; import de.ozgcloud.apilib.common.command.grpc.CommandMapper; import de.ozgcloud.apilib.common.datatypes.GenericId; import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId; import de.ozgcloud.bescheid.Bescheid; -import de.ozgcloud.bescheid.Bescheid.SendBy; import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor; +import de.ozgcloud.bescheid.BescheidMapper; import de.ozgcloud.bescheid.BescheidTestFactory; -import de.ozgcloud.bescheid.common.freemarker.TemplateHandler; import de.ozgcloud.bescheid.vorgang.VorgangId; import de.ozgcloud.bescheid.vorgang.VorgangTestFactory; import de.ozgcloud.command.Command; @@ -84,25 +75,24 @@ class AttachedItemServiceTest { @Mock private CommandMapper commandMapper; @Mock - - private TemplateHandler templateHandler; + private BescheidMapper bescheidMapper; @Nested class TestFindBescheidItem { @Test void shouldCallGetBescheidDraft() { - service.findBescheidItem(CommandTestFactory.VORGANG_ID); + service.findBescheidItem(VorgangTestFactory.ID); - verify(remoteService).findBescheidDraft(CommandTestFactory.VORGANG_ID); + verify(remoteService).findBescheidDraft(VorgangTestFactory.ID); } @Test void shouldReturnBescheidItem() { var expected = AttachedItemTestFactory.createBescheid(); - when(remoteService.findBescheidDraft(anyString())).thenReturn(Optional.of(expected)); + when(remoteService.findBescheidDraft(any(VorgangId.class))).thenReturn(Optional.of(expected)); - var actual = service.findBescheidItem(CommandTestFactory.VORGANG_ID); + var actual = service.findBescheidItem(VorgangTestFactory.ID); assertThat(actual).contains(expected); } @@ -112,286 +102,170 @@ class AttachedItemServiceTest { class TestCreateBescheidDraft { private static final String CREATED_ATTACHED_ITEM_ID = "attached-item-id"; + private static final Bescheid BESCHEID = BescheidTestFactory.create(); private final AttachedItem bescheidItem = AttachedItemTestFactory.createBescheid(); - private Command command = CommandTestFactory.createBuilder().bodyObject(AttachedItemTestFactory.createBescheidItem()).build(); @Mock - private OzgCloudCommand ozgCloudCommand; - @Captor - private ArgumentCaptor<AttachedItem> bescheidItemCaptor; + private AttachedItem updatedBescheidItem; @Test - void shouldCallValidateData() { + void shouldCallGetBescheidDraft() { doReturn(CREATED_ATTACHED_ITEM_ID).when(service).createAttachedItem(any()); - service.createBescheidDraft(command); + service.createBescheidDraft(BESCHEID); - verify(service).validateBescheidData(command.getBodyObject()); + verify(remoteService).findBescheidDraft(VorgangTestFactory.ID); } @Test - void shouldCallGetBescheidDraft() { - doReturn(CREATED_ATTACHED_ITEM_ID).when(service).createAttachedItem(any()); + void shouldCallMergeBescheidDrafts() { + doReturn(CREATED_ATTACHED_ITEM_ID).when(service).overrideAttachedItem(any()); + when(remoteService.findBescheidDraft(any(VorgangId.class))).thenReturn(Optional.of(bescheidItem)); - service.createBescheidDraft(command); + service.createBescheidDraft(BESCHEID); - verify(remoteService).findBescheidDraft(CommandTestFactory.VORGANG_ID); + verify(service).mergeBescheidDrafts(bescheidItem, BESCHEID); } @Test - void shouldCallUpdateBescheidDraft() { - doReturn(CREATED_ATTACHED_ITEM_ID).when(service).overrideAttachedItem(any(), any()); - when(remoteService.findBescheidDraft(anyString())).thenReturn(Optional.of(bescheidItem)); + void shouldCallOverrideAttachedItem() { + doReturn(CREATED_ATTACHED_ITEM_ID).when(service).overrideAttachedItem(any()); + when(remoteService.findBescheidDraft(any(VorgangId.class))).thenReturn(Optional.of(bescheidItem)); + doReturn(updatedBescheidItem).when(service).mergeBescheidDrafts(any(), any()); - service.createBescheidDraft(command); + service.createBescheidDraft(BESCHEID); - verify(service).overrideAttachedItem(bescheidItemCaptor.capture(), eq(command)); - assertThat(bescheidItemCaptor.getValue()).isEqualTo(bescheidItem); + verify(service).overrideAttachedItem(updatedBescheidItem); } @Test void shouldCallCreateBescheidDraft() { doReturn(CREATED_ATTACHED_ITEM_ID).when(service).createAttachedItem(any()); - service.createBescheidDraft(command); + service.createBescheidDraft(BESCHEID); - verify(service).createBescheidDraft(command); + verify(service).createBescheidDraft(BESCHEID); } - @Nested - class TestCreateAttachedItem { - - @Mock - private OzgCloudCommand createAttachedItemCommand; - - @BeforeEach - void init() { - when(commandService.createAndWaitUntilDone(any())).thenReturn(ozgCloudCommand); - } - - @Test - void shouldCallBuildCreateAttachedItemCommand() { - createAttachedItem(); - - verify(service).buildCreateAttachedItemCommand(command); - } + } - @Test - void shouldCallCommandService() { - doReturn(createAttachedItemCommand).when(service).buildCreateAttachedItemCommand(any()); + @Nested + class TestCreateAttachedItem { - createAttachedItem(); + private static final Bescheid BESCHEID = BescheidTestFactory.create(); + private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid(); - verify(commandService).createAndWaitUntilDone(createAttachedItemCommand); - } + @Mock + private OzgCloudCommand createAttachedItemCommand; + @Mock + private OzgCloudCommand finishedOzgCloudCommand; - private void createAttachedItem() { - service.createAttachedItem(command); - } + @BeforeEach + void init() { + when(commandService.createAndWaitUntilDone(any())).thenReturn(finishedOzgCloudCommand); + when(finishedOzgCloudCommand.getCreatedResource()).thenReturn(AttachedItemTestFactory.ID); + when(bescheidMapper.mapFromBescheid(any())).thenReturn(BESCHEID_ITEM); } - @Nested - class TestBuildCreateAttachedItemCommand { - - @Test - void shouldCallVorgangIdMapper() { - service.buildCreateAttachedItemCommand(command); - - verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID); - } - - @Test - void shouldSetVorgangId() { - var expectedVorgangId = OzgCloudVorgangId.from(CommandTestFactory.VORGANG_ID); - when(commandMapper.toOzgCloudVorgangId(any())).thenReturn(expectedVorgangId); - - var result = service.buildCreateAttachedItemCommand(command); - - assertThat(result.getVorgangId()).isEqualTo(expectedVorgangId); - } - - @Test - void shouldCallRelationIdMapper() { - var expectedRelationId = "relationId"; - command = CommandTestFactory.createBuilder().relationId(expectedRelationId).build(); - when(commandMapper.mapRelationId(any())).thenReturn(GenericId.from(command.getRelationId())); - - service.buildCreateAttachedItemCommand(command); - - verify(commandMapper).mapRelationId(expectedRelationId); - } - - @Test - void shouldSetRelationId() { - var expectedRelationId = "relationId"; - command = CommandTestFactory.createBuilder().relationId(expectedRelationId).build(); - when(commandMapper.mapRelationId(any())).thenReturn(GenericId.from(command.getRelationId())); - - var result = service.buildCreateAttachedItemCommand(command); - - assertThat(result.getRelationId()).hasToString(command.getRelationId()); - } - - @Test - void shouldCallBuildAttachedItemAsMap() { - var expectedItemMap = Map.<String, Object>of("key", "value"); - doReturn(expectedItemMap).when(service).buildCreateBescheidItemMap(any()); - - service.buildCreateAttachedItemCommand(command); - - verify(service).buildAttachedItemAsMap(command, expectedItemMap); - } - - @Test - void shouldSetBodyObject() { - var expectedBodyObject = Map.<String, Object>of("key", "value"); - doReturn(expectedBodyObject).when(service).buildAttachedItemAsMap(any(), any()); - - var result = service.buildCreateAttachedItemCommand(command); - - assertThat(result.getBodyObject()).containsAllEntriesOf(expectedBodyObject); - } - - @Test - void shouldSetOrder() { - var result = service.buildCreateAttachedItemCommand(command); + @Test + void shouldCallMapFromBescheid() { + createAttachedItem(); - assertThat(result.getOrder()).isEqualTo(AttachedItemService.CREATE_ATTACHED_ITEM_ORDER); - } + verify(bescheidMapper).mapFromBescheid(BESCHEID); } - @DisplayName("Build create bescheid itemMap") - @Nested - class TestBuildCreateBescheidItemMap { - - private static final String TEMPLATE_CONTENT_AS_STRING = LoremIpsum.getInstance().getParagraphs(5, 20); - - @DisplayName("on empty nachricht") - @Nested - class TestOnEmptyNachricht { - - @Test - void shouldHaveDefaultNachrichtSubjectInBodyIfMissing() { - var bodyObject = service.buildCreateBescheidItemMap(createCommandWithoutNachricht()); - - assertThat(bodyObject).containsEntry(Bescheid.FIELD_NACHRICHT_SUBJECT, AttachedItemService.DEFAULT_SUBJECT); - } - - @Test - void shouldCallTemplateHandler() { - when(templateHandler.getRawTemplate(any())).thenReturn(TEMPLATE_CONTENT_AS_STRING); - - service.buildCreateBescheidItemMap(createCommandWithoutNachricht()); + @Test + void shouldCallBuildCreateAttachedItemCommand() { + doReturn(createAttachedItemCommand).when(service).buildCreateAttachedItemCommand(any()); - verify(templateHandler).getRawTemplate(AttachedItemService.DEFAULT_TEMPLATE_FILE); - } + createAttachedItem(); - @Test - void shouldHaveDefaultNachrichtTextInBodyIfMissing() { - when(templateHandler.getRawTemplate(any())).thenReturn(TEMPLATE_CONTENT_AS_STRING); + verify(service).buildCreateAttachedItemCommand(BESCHEID_ITEM); + } - var bodyObject = service.buildCreateBescheidItemMap(createCommandWithoutNachricht()); + @Test + void shouldCallCommandService() { + doReturn(createAttachedItemCommand).when(service).buildCreateAttachedItemCommand(any()); - assertThat(bodyObject).containsEntry(Bescheid.FIELD_NACHRICHT_TEXT, TEMPLATE_CONTENT_AS_STRING); - } + createAttachedItem(); - private Command createCommandWithoutNachricht() { - var bescheidItemMap = AttachedItemTestFactory.createBescheidItem(); - bescheidItemMap.put(Bescheid.FIELD_NACHRICHT_SUBJECT, StringUtils.EMPTY); - bescheidItemMap.put(Bescheid.FIELD_NACHRICHT_TEXT, StringUtils.EMPTY); - return CommandTestFactory.createBuilder().bodyObject(bescheidItemMap).build(); - } - } + verify(commandService).createAndWaitUntilDone(createAttachedItemCommand); + } - @DisplayName("on non existing nachricht") - @Nested - class TestNonExistingNachricht { + @Test + void shouldReturnCreatedResource() { + var result = createAttachedItem(); - @Test - void shouldHaveDefaultNachrichtSubjectInBodyIfMissing() { - var bodyObject = service.buildCreateBescheidItemMap(createCommandWithoutNachricht()); + assertThat(result).isEqualTo(AttachedItemTestFactory.ID); + } - assertThat(bodyObject).containsEntry(Bescheid.FIELD_NACHRICHT_SUBJECT, AttachedItemService.DEFAULT_SUBJECT); - } + private String createAttachedItem() { + return service.createAttachedItem(BESCHEID); + } + } - @Test - void shouldCallTemplateHandler() { - when(templateHandler.getRawTemplate(any())).thenReturn(TEMPLATE_CONTENT_AS_STRING); + @Nested + class TestBuildCreateAttachedItemCommand { - service.buildCreateBescheidItemMap(createCommandWithoutNachricht()); + private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid(); - verify(templateHandler).getRawTemplate(AttachedItemService.DEFAULT_TEMPLATE_FILE); - } + @Test + void shouldCallVorgangIdMapper() { + service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - @Test - void shouldHaveDefaultNachrichtTextInBodyIfMissing() { - when(templateHandler.getRawTemplate(any())).thenReturn(TEMPLATE_CONTENT_AS_STRING); + verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID); + } - var bodyObject = service.buildCreateBescheidItemMap(createCommandWithoutNachricht()); + @Test + void shouldSetVorgangId() { + var expectedVorgangId = OzgCloudVorgangId.from(CommandTestFactory.VORGANG_ID); + when(commandMapper.toOzgCloudVorgangId(any())).thenReturn(expectedVorgangId); - assertThat(bodyObject).containsEntry(Bescheid.FIELD_NACHRICHT_TEXT, TEMPLATE_CONTENT_AS_STRING); - } + var result = service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - private Command createCommandWithoutNachricht() { - var bescheidItemMap = AttachedItemTestFactory.createBescheidItem(); - bescheidItemMap.remove(Bescheid.FIELD_NACHRICHT_SUBJECT); - bescheidItemMap.remove(Bescheid.FIELD_NACHRICHT_TEXT); - return CommandTestFactory.createBuilder().bodyObject(bescheidItemMap).build(); - } - } + assertThat(result.getVorgangId()).isEqualTo(expectedVorgangId); } - @Nested - class TestValidateBescheidData { + @Test + void shouldCallRelationIdMapper() { + service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - @Test - void shouldValidate() { - assertDoesNotThrow(() -> service.validateBescheidData(command.getBodyObject())); - } + verify(commandMapper).mapRelationId(CommandTestFactory.VORGANG_ID); + } - @DisplayName(value = "should fail if bescheidAm is missing") - @Test - void shouldThrowExceptionByBescheidAm() { - var map = Map.<String, Object>of(Bescheid.FIELD_BEWILLIGT, true); + @Test + void shouldSetRelationId() { + var expectedRelationId = "relationId"; + when(commandMapper.mapRelationId(any())).thenReturn(GenericId.from(expectedRelationId)); - assertThrows(TechnicalException.class, () -> service.validateBescheidData(map)); - } + var result = service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - @DisplayName(value = "should fail if bewilligt is missing") - @Test - void shouldThrowExceptionByBewilligt() { - var map = Map.<String, Object>of(Bescheid.FIELD_BESCHIEDEN_AM, "2021-01-01"); + assertThat(result.getRelationId()).hasToString(expectedRelationId); + } - assertThrows(TechnicalException.class, () -> service.validateBescheidData(map)); - } + @Test + void shouldSetOrder() { + var result = service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - @Test - void shouldValidateSendBy() { - var bodyObject = Map.<String, Object>of(Bescheid.FIELD_SEND_BY, SendBy.MANUAL.name()); - doNothing().when(service).validateBescheidField(any(), any()); + assertThat(result.getOrder()).isEqualTo(AttachedItemService.CREATE_ATTACHED_ITEM_ORDER); + } - service.validateBescheidData(bodyObject); + @Test + void shouldCallAttachedItemMapper() { + service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - verify(service).validateSendBy(SendBy.MANUAL.name()); - } + verify(mapper).toMap(BESCHEID_ITEM); + } - @DisplayName("validate sendBy") - @Nested - class TestValidateSendBy { + @Test + void shouldSetBodyObject() { + var itemMap = Map.<String, Object>of("key", "value"); + when(mapper.toMap(any())).thenReturn(itemMap); - @ValueSource(strings = { "not-exist", "" }) - @ParameterizedTest - void shouldThrowExceptionOnNonExistingSendByValue(String sendBy) { - assertThrows(TechnicalException.class, () -> service.validateSendBy(sendBy)); - } + var result = service.buildCreateAttachedItemCommand(BESCHEID_ITEM); - @EnumSource(names = { "NACHRICHT", "MANUAL" }) - @ParameterizedTest - void shouldNotThrowAnyExceptionOnExistingSendByValue(SendBy sendBy) { - assertDoesNotThrow(() -> service.validateSendBy(sendBy.name())); - } - } + assertThat(result.getBodyObject()).containsAllEntriesOf(itemMap); } } @@ -633,41 +507,22 @@ class AttachedItemServiceTest { class TestOverrideAttachedItem { private static final String CREATED_RESOURCE = "created-resource"; + @Mock private OzgCloudCommand updateItemCommand; - private final Command command = CommandTestFactory.createBuilder().bodyObject(AttachedItemTestFactory.createBescheidItem()).build(); - @BeforeEach void init() { when(commandService.createAndWaitUntilDone(any())).thenReturn(updateItemCommand); when(updateItemCommand.getCreatedResource()).thenReturn(CREATED_RESOURCE); } - @Test - void shouldCallBuildItemMapWithAllBescheidFields() { - service.overrideAttachedItem(AttachedItemTestFactory.createBescheid(), command); - - verify(service).buildItemMapWithAllBescheidFields(command); - } - - @Test - void shouldCallBuildAttachedItemAsMap() { - var itemMap = Map.<String, Object>of("key", "value"); - doReturn(itemMap).when(service).buildItemMapWithAllBescheidFields(any()); - - service.overrideAttachedItem(AttachedItemTestFactory.createBescheid(), command); - - verify(service).buildAttachedItemAsMap(command, itemMap); - } - @Test void shouldCallBuildUpdateAttachedItemCommand() { var bodyObject = Map.<String, Object>of("key", "value"); - doReturn(bodyObject).when(service).buildAttachedItemAsMap(any(), any()); - var bescheidItem = AttachedItemTestFactory.createBescheid(); + var bescheidItem = AttachedItemTestFactory.createBescheidBuilder().clearItem().item(bodyObject).build(); - service.overrideAttachedItem(bescheidItem, command); + service.overrideAttachedItem(bescheidItem); verify(service).buildPatchAttachedItemCommand(bescheidItem, bodyObject); } @@ -676,14 +531,14 @@ class AttachedItemServiceTest { void shouldCallCommandService() { doReturn(updateItemCommand).when(service).buildPatchAttachedItemCommand(any(), any()); - service.overrideAttachedItem(AttachedItemTestFactory.createBescheid(), command); + service.overrideAttachedItem(AttachedItemTestFactory.createBescheid()); verify(commandService).createAndWaitUntilDone(updateItemCommand); } @Test void shouldReturnCreatedResource() { - var result = service.overrideAttachedItem(AttachedItemTestFactory.createBescheid(), command); + var result = service.overrideAttachedItem(AttachedItemTestFactory.createBescheid()); assertThat(result).isEqualTo(CREATED_RESOURCE); } diff --git a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemTestFactory.java b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemTestFactory.java index 6f95bc5930e980d4818394d9cf83cafcae4ab65f..9b3ac12ebfa3c1f1385bedaab9d8383c25c750a8 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemTestFactory.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/AttachedItemTestFactory.java @@ -33,6 +33,7 @@ import java.util.Map; import de.ozgcloud.bescheid.Bescheid; import de.ozgcloud.bescheid.BescheidTestFactory; import de.ozgcloud.bescheid.SentInfo; +import de.ozgcloud.bescheid.SentInfoTestFactory; import de.ozgcloud.bescheid.common.user.UserProfileTestFactory; import de.ozgcloud.bescheid.vorgang.VorgangTestFactory; import de.ozgcloud.command.CommandTestFactory; @@ -47,6 +48,7 @@ public class AttachedItemTestFactory { public static final String ID = "bescheid-item-id"; public static final long VERSION = 10L; public static final String CLIENT = "client"; + public static final Map<String, Object> SENT_INFO = SentInfoTestFactory.asMap(); public static AttachedItem create() { return createBuilder().build(); @@ -64,7 +66,6 @@ public class AttachedItemTestFactory { public static Map<String, Object> createBescheidItem() { var item = new HashMap<String, Object>(); - item.put(AttachedItem.PROPERTY_VORGANG_ID, VorgangTestFactory.ID); item.put(Bescheid.FIELD_STATUS, BescheidTestFactory.STATUS.name()); item.put(Bescheid.FIELD_BESCHIEDEN_AM, BescheidTestFactory.BESCHIEDEN_AM_STR); item.put(Bescheid.FIELD_BEWILLIGT, BescheidTestFactory.BEWILLIGT); @@ -73,9 +74,8 @@ public class AttachedItemTestFactory { item.put(Bescheid.FIELD_SEND_BY, BescheidTestFactory.SEND_BY.name()); item.put(Bescheid.FIELD_NACHRICHT_TEXT, BescheidTestFactory.NACHRICHT_TEXT); item.put(Bescheid.FIELD_NACHRICHT_SUBJECT, BescheidTestFactory.NACHRICHT_SUBJECT); - item.put(Bescheid.FIELD_SENT_INFO, Map.of( - SentInfo.FIELD_SENT_BY, SENT_BY, - SentInfo.FIELD_SENT_AT, SENT_AT_STR)); + item.put(Bescheid.FIELD_CREATED_BY, UserProfileTestFactory.ID_STR); + item.put(Bescheid.FIELD_SENT_INFO, SENT_INFO); return item; } diff --git a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteServiceTest.java index 7e1a5140b048e87f07aa2c005f6595234a5ea669..104ace168b6b7486c39adf39df9657a825b8d577 100644 --- a/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteServiceTest.java +++ b/bescheid-manager/src/test/java/de/ozgcloud/common/attached_item/VorgangAttachedItemRemoteServiceTest.java @@ -58,8 +58,6 @@ import io.grpc.ClientInterceptor; class VorgangAttachedItemRemoteServiceTest { - private static final String VORGANG_ID = "vorgang-id"; - @Spy @InjectMocks private VorgangAttachedItemRemoteService service; @@ -78,8 +76,7 @@ class VorgangAttachedItemRemoteServiceTest { private GrpcFindVorgangAttachedItemRequest request; @Nested - @DisplayName("by vorgangId") - class TestGetByVorgangId { + class TestFindByVorgangId { private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid(); @@ -91,21 +88,21 @@ class VorgangAttachedItemRemoteServiceTest { @Test void shouldCallCreateFindRequestBuilder() { - service.findBescheidDraft(VORGANG_ID); + service.findBescheidDraft(VorgangTestFactory.ID); - verify(service).buildFindRequest(VORGANG_ID); + verify(service).buildFindRequest(VorgangTestFactory.ID_STR); } @Test void shouldCallGetBescheidDraft() { - service.findBescheidDraft(VORGANG_ID); + service.findBescheidDraft(VorgangTestFactory.ID); verify(service).findBescheidDraft(request); } @Test void shouldReturnResult() { - var result = service.findBescheidDraft(VORGANG_ID); + var result = service.findBescheidDraft(VorgangTestFactory.ID); assertThat(result).contains(BESCHEID_ITEM); } diff --git a/bescheid-manager/src/test/resources/application-itcase.yml b/bescheid-manager/src/test/resources/application-itcase.yml index 8157581c058ea205d2708730f584327d24121e24..72e5c1342fce4a554381a3cc7d09cd4a09af48f7 100644 --- a/bescheid-manager/src/test/resources/application-itcase.yml +++ b/bescheid-manager/src/test/resources/application-itcase.yml @@ -6,6 +6,9 @@ logging: config: classpath:log4j2-local.xml ozgcloud: + admin: + sync: + enabled: false bescheid: smart-documents: url: https://demo-de.smartdocuments.com/wsxmldeposit/deposit/unattended @@ -14,3 +17,7 @@ ozgcloud: password: MGM templateGroup: Kiel template: Halteverbot +spring: + cloud: + config: + enabled: false diff --git a/pom.xml b/pom.xml index a4440748e7de59956874614bee775082340b163d..f27c49331eda7a4c8073d28ce417fb5b8ad22162 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.14.1</version> + <version>2.15.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager</name> <packaging>pom</packaging> diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl index 9b9f1b39f8a671442b454742b293219a6bd0119d..d3319d470a404cdc82ea1f46d66de742c7b4662b 100644 --- a/src/main/helm/templates/_helpers.tpl +++ b/src/main/helm/templates/_helpers.tpl @@ -73,6 +73,10 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }} {{ printf "dns:///%s.%s:9090" .Values.vorgangmanagerName .Release.Namespace }} {{- end -}} +{{- define "app.ozgcloud_administration_address" -}} +{{ printf "http://%s.%s:8080" .Values.administrationName .Release.Namespace }} +{{- end -}} + {{- define "app.databaseSecretName" -}} {{- if (.Values.database).secretName -}} {{ .Values.database.secretName }} diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml index 329fb56867a302145ce93e6d1d11e8384d795713..ba379a93e17e623cf46bbc3f6e05aa8750eacff8 100644 --- a/src/main/helm/templates/deployment.yaml +++ b/src/main/helm/templates/deployment.yaml @@ -63,6 +63,8 @@ spec: value: "/bindings" - name: spring_profiles_active value: {{ include "app.envSpringProfiles" . }} + - name: ozgcloud_application_address + value: {{ include "app.ozgcloud_vorgangmanager_address" . }} - name: ozgcloud_nachrichten-manager_address value: {{ include "app.ozgcloud_vorgangmanager_address" . }} {{- if .Values.env.ozgcloudAktenzeichen.enabled }} @@ -154,7 +156,11 @@ spec: - name: ozgcloud_user-manager_url value: {{ include "app.ozgcloud_migration_user-manager_address" . }} - name: ozgcloud_zufi-manager_address - value: {{ .Values.zufiManager.address }} + value: {{ (.Values.zufiManager).address }} + - name: grpc_client_zufi-manager_address + value: {{ (.Values.zufiManager).address }} + - name: grpc_client_zufi-manager_negotiationType + value: {{ (.Values.zufiManager).grpcClientNegotiationType }} {{- if not (.Values.database).useExternal }} - name: spring_data_mongodb_uri valueFrom: @@ -203,8 +209,9 @@ spec: key: login optional: false {{- end }} - + - name: ozgcloud_administration_address + value: {{ include "app.ozgcloud_administration_address" . }} {{- if ((.Values.ozgcloud).antragraum).enabled }} @@ -229,6 +236,10 @@ spec: - name: ozgcloud_feature_bescheid_kielHackathonRoute value: {{ quote (((.Values.ozgcloud).feature).bescheid).kielHackathonRoute }} {{- end }} + {{- if (((.Values.ozgcloud).notification).eingangsbestaetigung).replyAllowed }} + - name: ozgcloud_notification_eingangsbestaetigung_replyAllowed + value: {{ quote (((.Values.ozgcloud).notification).eingangsbestaetigung).replyAllowed }} + {{- end }} {{- if (.Values.ozgcloud).processors}} {{- range $processor_index, $processor := (.Values.ozgcloud).processors }} diff --git a/src/main/helm/values.yaml b/src/main/helm/values.yaml index 7bad7a05a7dec07c8efafa98bf72f061afcde748..6a380e033dcf8986792b1e8b8ca9f92a4ab81a0c 100644 --- a/src/main/helm/values.yaml +++ b/src/main/helm/values.yaml @@ -57,8 +57,10 @@ vorgangmanagerName: vorgang-manager usermanagerName: user-manager +administrationName: administration + zufiManager: - address: dns:///zufi-manager.zufi:9090 + address: dns:///zufi-server.zufi:9090 elasticsearch: certificateSecretName: elasticsearch-certificate diff --git a/src/test/helm/deployment_administration_address_env_test.yaml b/src/test/helm/deployment_administration_address_env_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b2bf2db3eed725512711a2f11cf87727c94e78bd --- /dev/null +++ b/src/test/helm/deployment_administration_address_env_test.yaml @@ -0,0 +1,44 @@ +# +# 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. +# + +suite: deployment administration address env +release: + name: vorgang-manager + namespace: by-helm-test +templates: + - templates/deployment.yaml +set: + ozgcloud: + environment: dev + imagePullSecret: image-pull-secret +tests: + - it: should have set administration server address + set: + administrationName: custom_admin_name + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_administration_address + value: http://custom_admin_name.by-helm-test:8080 diff --git a/src/test/helm/deployment_env_test.yaml b/src/test/helm/deployment_env_test.yaml index 573afcbdd936a8c2721f1706297fa5fca68f5d16..4d71e36a71fcb5da19e5c6b55afd44ad528bcbd8 100644 --- a/src/test/helm/deployment_env_test.yaml +++ b/src/test/helm/deployment_env_test.yaml @@ -140,4 +140,16 @@ tests: path: spec.template.spec.containers[0].env content: name: ozgcloud_processors_1_forms_0_formEngineName - value: FormSolutions \ No newline at end of file + value: FormSolutions + - it: should have notification properties + set: + ozgcloud: + notification: + eingangsbestaetigung: + replyAllowed: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_notification_eingangsbestaetigung_replyAllowed + value: "true" \ No newline at end of file diff --git a/src/test/helm/deployment_vorgang_manager_env_test.yaml b/src/test/helm/deployment_vorgang_manager_env_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4626fa9296378d85086ac3e15513241aa785e23d --- /dev/null +++ b/src/test/helm/deployment_vorgang_manager_env_test.yaml @@ -0,0 +1,42 @@ +# +# 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. +# + +suite: deployment vorgang manager environment +release: + name: vorgang-manager + namespace: by-helm-test +templates: + - templates/deployment.yaml +set: + ozgcloud: + environment: dev + imagePullSecret: test-image-pull-secret +tests: + - it: check if application address is set + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_application_address + value: dns:///vorgang-manager.by-helm-test:9090 \ No newline at end of file diff --git a/src/test/helm/deployment_zufimanager_address_env_test.yaml b/src/test/helm/deployment_zufimanager_address_env_test.yaml index 687a53ee8d0193969eeb7bb8471bd2f33deec6de..d73c2e5b39e192cfe0f30908ccaa4c2d5d22fe1c 100644 --- a/src/test/helm/deployment_zufimanager_address_env_test.yaml +++ b/src/test/helm/deployment_zufimanager_address_env_test.yaml @@ -22,10 +22,10 @@ # unter der Lizenz sind dem Lizenztext zu entnehmen. # -suite: test environments +suite: deployment zufi-manager address environment release: name: vorgang-manager - namespace: sh-helm-test + namespace: by-helm-test templates: - templates/deployment.yaml set: @@ -33,10 +33,51 @@ set: environment: dev imagePullSecret: test-image-pull-secret tests: - - it: check if zufi-manager address is correct + - it: check default zufi-manager address asserts: - contains: path: spec.template.spec.containers[0].env content: name: ozgcloud_zufi-manager_address - value: dns:///zufi-manager.zufi:9090 + value: dns:///zufi-server.zufi:9090 + + - it: should set custom zufi-manager address + set: + zufiManager: + address: dns://other.zufi:9090 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_zufi-manager_address + value: dns://other.zufi:9090 + + - it: check default zufi-manager grpc client address + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_zufi-manager_address + value: dns:///zufi-server.zufi:9090 + + - it: should set custom zufi-manager grpc client address + set: + zufiManager: + address: dns://other.zufi:9090 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_zufi-manager_address + value: dns://other.zufi:9090 + + - it: check if zufi-manager negotiationType is set + set: + zufiManager: + grpcClientNegotiationType: NOT_DEFAULT + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_zufi-manager_negotiationType + value: NOT_DEFAULT diff --git a/vorgang-manager-base/pom.xml b/vorgang-manager-base/pom.xml index c46f9728c9675fed6cfbd1262232612d9db7092d..3330f384b382b6d0c1d4570dc8503d1ba745363c 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.14.1</version> + <version>2.15.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager Base</name> diff --git a/vorgang-manager-command/pom.xml b/vorgang-manager-command/pom.xml index 74645f55411e2dc996098d5151a226f3b9d4a2ee..90c93b9f28cbac4fc1a4b84c72ee49b9e56c99b1 100644 --- a/vorgang-manager-command/pom.xml +++ b/vorgang-manager-command/pom.xml @@ -10,7 +10,7 @@ <groupId>de.ozgcloud.command</groupId> <artifactId>command-manager</artifactId> - <version>2.14.1</version> + <version>2.15.0-SNAPSHOT</version> <name>OZG-Cloud Command Manager</name> <properties> diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/PostfachNachrichtReceivedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/PostfachNachrichtReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..3ed40fd7a5f9a371792f4971920a78e183211f53 --- /dev/null +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/PostfachNachrichtReceivedEvent.java @@ -0,0 +1,50 @@ +/* + * 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; + +import java.io.Serial; + +import org.springframework.context.ApplicationEvent; + +import lombok.Getter; + +@Getter +public class PostfachNachrichtReceivedEvent extends ApplicationEvent { + + @Serial + private static final long serialVersionUID = 1L; + + private final String nachrichtId; + + public PostfachNachrichtReceivedEvent(Command command, String nachrichtId) { + super(command); + this.nachrichtId = nachrichtId; + } + + @Override + public Command getSource() { + return (Command) super.getSource(); + } + +} diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangAssignedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangAssignedEvent.java similarity index 74% rename from vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangAssignedEvent.java rename to vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangAssignedEvent.java index 7847c2522279ff910b9d0f0aec2c3e3d79eaa1b6..7515a5e69b0002b4c8ef91bcd0eb7c653ca6499d 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangAssignedEvent.java +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangAssignedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * 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 @@ -21,20 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.vorgang.vorgang; +package de.ozgcloud.command; -import de.ozgcloud.command.Command; -import de.ozgcloud.command.CommandExecutedEvent; -import lombok.Getter; - -@Getter public class VorgangAssignedEvent extends CommandExecutedEvent { - private transient Command command; private static final long serialVersionUID = 1L; - protected VorgangAssignedEvent(Command command) { - super(command.getId()); - this.command = command; + public VorgangAssignedEvent(Command command) { + super(command); } } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCreatedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangAttachedItemCreatedEvent.java similarity index 78% rename from vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCreatedEvent.java rename to vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangAttachedItemCreatedEvent.java index baa5b5817df7e9130c043f8344d455e2f32fccb4..6ffbefae323b3cf0a6b9d3342a03a1ca6488eb00 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCreatedEvent.java +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangAttachedItemCreatedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * 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 @@ -21,16 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.vorgang.attached_item; - -import de.ozgcloud.command.CommandExecutedEvent; +package de.ozgcloud.command; public class VorgangAttachedItemCreatedEvent extends CommandExecutedEvent { private static final long serialVersionUID = 1L; - protected VorgangAttachedItemCreatedEvent(String commandId, String createdResource) { - super(commandId, createdResource); + public VorgangAttachedItemCreatedEvent(Command command, String createdResource) { + super(command, createdResource); } - } diff --git a/vorgang-manager-interface/pom.xml b/vorgang-manager-interface/pom.xml index 251378df84aec87d601c1162ba614828989e07df..2057978d5dba01316f9982e85efd173257f477b2 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.14.1</version> + <version>2.15.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 298fc329846b00f946bb8806398cd065fee0b123..6d3d42023647d383ba6f715c65cba0a629914ee3 100644 --- a/vorgang-manager-server/pom.xml +++ b/vorgang-manager-server/pom.xml @@ -38,7 +38,7 @@ <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-server</artifactId> - <version>2.14.1</version> + <version>2.15.0-SNAPSHOT</version> <name>OZG-Cloud Vorgang Manager Server</name> <description>Server Implementierung des VorgangManagers</description> @@ -50,15 +50,15 @@ <spring-boot.build-image.imageName>docker.ozg-sh.de/vorgang-manager:build-latest</spring-boot.build-image.imageName> <ozgcloud.license.version>1.3.0</ozgcloud.license.version> - <zufi-manager-interface.version>1.0.0</zufi-manager-interface.version> + <zufi-manager-interface.version>1.4.0-SNAPSHOT</zufi-manager-interface.version> - <user-manager-interface.version>2.1.0</user-manager-interface.version> - <bescheid-manager.version>1.17.0</bescheid-manager.version> + <user-manager-interface.version>2.9.0-SNAPSHOT</user-manager-interface.version> + <bescheid-manager.version>1.18.0-SNAPSHOT</bescheid-manager.version> <processor-manager.version>0.4.1</processor-manager.version> - <nachrichten-manager.version>2.11.0</nachrichten-manager.version> - <ozgcloud-starter.version>0.10.0</ozgcloud-starter.version> - <notification-manager.version>2.10.0</notification-manager.version> - <collaboration-manager.version>0.2.0</collaboration-manager.version> + <nachrichten-manager.version>2.12.0-SNAPSHOT</nachrichten-manager.version> + <ozgcloud-starter.version>0.12.0</ozgcloud-starter.version> + <notification-manager.version>2.11.0-SNAPSHOT</notification-manager.version> + <collaboration-manager.version>0.3.0-SNAPSHOT</collaboration-manager.version> <zip.version>2.11.1</zip.version> <jsoup.version>1.15.3</jsoup.version> diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerProperties.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..a17f844828bc8983610fab48bced19bbe373363d --- /dev/null +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerProperties.java @@ -0,0 +1,45 @@ +/* + * 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.vorgang; + +import jakarta.validation.constraints.NotBlank; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Validated +@Configuration +@ConfigurationProperties(prefix = "ozgcloud.application") +public class VorgangManagerProperties { + + @NotBlank + private String address; + +} diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java index cf991372cac1e53ef918bf360128a4939f9ccb6c..cc8905ccdc227a1c78533d54c0b26dea0fa71022 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java @@ -75,7 +75,7 @@ class VorgangAttachedItemEventListener { validateCreateCommand(command); var item = mapper.fill(command.getBodyObject()).toBuilder().id(null).version(0).build(); - service.create(command.getId(), item); + service.create(command, item); } void validateCreateCommand(Command command) { diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java index 06aafc83380e42ac5d8ab5bdbd82ac5ff5f9914f..ef0d12da9202197c9c16570fe7005f8052f7a178 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java @@ -31,6 +31,7 @@ import java.util.stream.Stream; import jakarta.validation.Valid; +import org.apache.commons.collections.MapUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -38,6 +39,9 @@ import org.springframework.validation.annotation.Validated; import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandRevokeFailedEvent; import de.ozgcloud.command.CommandRevokedEvent; +import de.ozgcloud.command.VorgangAttachedItemCreatedEvent; +import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.vorgang.command.PersistedCommand; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -54,10 +58,10 @@ public class VorgangAttachedItemService { private final VorgangAttachedItemRepository repository; private final ApplicationEventPublisher publisher; - public VorgangAttachedItem create(@NonNull String commandId, @Valid VorgangAttachedItem item) { + public VorgangAttachedItem create(@NonNull Command command, @Valid VorgangAttachedItem item) { var saved = repository.save(prepareForCreation(item)); - publisher.publishEvent(new VorgangAttachedItemCreatedEvent(commandId, saved.getId())); + publisher.publishEvent(new VorgangAttachedItemCreatedEvent(buildExecutedCommand(command, saved), saved.getId())); return saved; } @@ -71,11 +75,34 @@ public class VorgangAttachedItemService { } private Map<String, Object> removeId(@NonNull Map<String, Object> item) { - var map = new HashMap<String, Object>(item); + var map = new HashMap<>(item); map.remove(VorgangAttachedItem.FIELDNAME_ID); return Collections.unmodifiableMap(map); } + Command buildExecutedCommand(Command command, VorgangAttachedItem item) { + return PersistedCommand.builder() + .id(command.getId()) + .vorgangId(command.getVorgangId()) + .relationId(command.getRelationId()) + .relationVersion(command.getRelationVersion()) + .order(command.getOrder()) + .createdAt(command.getCreatedAt()) + .createdBy(command.getCreatedBy()) + .status(command.getStatus()) + .createdResource(item.getId()) + .bodyObject(buildBodyObject(item)) + .build(); + } + + Map<String, Object> buildBodyObject(VorgangAttachedItem item) { + var map = new HashMap<String, Object>(); + map.put(VorgangAttachedItem.FIELDNAME_ITEM_NAME, item.getItemName()); + Optional.ofNullable(MapUtils.getString(item.getItem(), PostfachNachricht.FIELD_DIRECTION)) + .ifPresent(direction -> map.put(PostfachNachricht.FIELD_DIRECTION, direction)); + return Collections.unmodifiableMap(map); + } + public void update(String commandId, VorgangAttachedItem item) { doUpdate(item.getId(), item.getVersion(), item.getItem()); @@ -160,7 +187,7 @@ public class VorgangAttachedItemService { } public void revokeCreate(Command command) { - handleRevoke(command, () -> delete(command.getRelationId(), command.getRelationVersion())); + handleRevoke(command, () -> delete(command.getCreatedResource(), command.getRelationVersion() + 1)); } void delete(String id, long version) { diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandEventListener.java index 9a6ebc1d3d61375724355556991d5af587a2d09b..5a4671ad54436d0e9657a7c62b323dbcaa25d0df 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandEventListener.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandEventListener.java @@ -31,8 +31,10 @@ import de.ozgcloud.command.CommandExecutedEvent; import de.ozgcloud.command.CommandFailedEvent; import de.ozgcloud.command.CommandRevokeFailedEvent; import de.ozgcloud.command.CommandRevokedEvent; +import lombok.extern.log4j.Log4j2; @Component +@Log4j2 public class CommandEventListener { @Autowired diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java index a9f57bac1d65ca9aba3af9671ab6d2efb2948558..dce3ec92f0c506bcabce138f6104003737adff39 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java @@ -36,11 +36,13 @@ import java.util.stream.Stream; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.ComparisonOperators.Eq; +import org.springframework.data.mongodb.core.aggregation.ConditionalOperators; import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch; import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch.CaseOperator; import org.springframework.data.mongodb.core.aggregation.SetOperation; @@ -261,17 +263,30 @@ class CommandRepository { return query; } - public Command setRevokeStatus(String id) { - return mongoOperations.findAndModify(queryById(id), buildUpdateStatusRevoke(), FindAndModifyOptions.options().returnNew(true), Command.class); + public Command setRevokeStatus(String id, String createdResource) { + return mongoOperations.findAndModify(queryById(id), buildUpdateStatusRevoke(createdResource), FindAndModifyOptions.options().returnNew(true), + Command.class); } - private UpdateDefinition buildUpdateStatusRevoke() { - var switchOperation = Switch.switchCases( - CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.NEW)).then(CommandStatus.CANCELED), - CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.PENDING)).then(CommandStatus.REVOKE_PENDING), - CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.FINISHED)).then(CommandStatus.REVOKE_PENDING)) + private UpdateDefinition buildUpdateStatusRevoke(String createdResource) { + var setOperation = SetOperation.set(MONGODB_STATUS).toValue(buildSetStatusCondition()); + if (StringUtils.isNotBlank(createdResource)) { + setOperation = setOperation.and().set(MONGODB_CREATED_RESOURCE).toValue(buildSetCreatedResourceCondition(createdResource)); + } + return Aggregation.newUpdate(setOperation); + } + + private Switch buildSetStatusCondition() { + return Switch.switchCases( + CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.NEW)).then(CommandStatus.CANCELED), + CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.PENDING)).then(CommandStatus.REVOKE_PENDING), + CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.FINISHED)).then(CommandStatus.REVOKE_PENDING)) .defaultTo(MONGODB_REFERENCE_STATUS); - return Aggregation.newUpdate(SetOperation.set(MONGODB_STATUS).toValue(switchOperation)); + } + + private ConditionalOperators.Cond buildSetCreatedResourceCondition(String createdResource) { + return ConditionalOperators.Cond.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.PENDING)).then(createdResource) + .otherwiseValueOf(MONGODB_CREATED_RESOURCE); } public Optional<Command> setRevokeStatusIfNotPending(String id) { 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 2f661a37b47f0da8143fdd5332e8385da4ecb1e5..ff7653e640230c195b26595b3b50c0589f305303 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 @@ -117,7 +117,7 @@ public class CommandService { public void setCommandFinished(String commandId, String createdResource) { var command = getById(commandId); if (shouldRevoke(command)) { - repository.setRevokeStatus(commandId); + command = repository.setRevokeStatus(commandId, createdResource); publishRevokeCommandEvent(command); return; } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M012_UpdateBayernIdPostfachType.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M012_UpdateBayernIdPostfachType.java new file mode 100644 index 0000000000000000000000000000000000000000..2b89cdfa416e725bbe8f5539579a05dfe3adab70 --- /dev/null +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M012_UpdateBayernIdPostfachType.java @@ -0,0 +1,50 @@ +package de.ozgcloud.vorgang.common.migration; + +import java.util.Set; + +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; + +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; +import io.mongock.api.annotations.RollbackExecution; + +@ChangeUnit(id = "2024-09-14 15:00:00 OZG-6641", order = "M012", author = "ebardin", runAlways = true) +public class M012_UpdateBayernIdPostfachType { // NOSONAR + + static final String KEY_HEADER_SERVICE_KONTO_TYPE = "header.serviceKonto.type"; + static final String KEY_EINGANG_SERVICE_KONTO_TYPE = "eingangs." + KEY_HEADER_SERVICE_KONTO_TYPE; + static final Set<String> POSSIBLE_BAYERN_ID_TYPE = Set.of("BayernId", "BayernID"); + static final String BAYERN_ID_TYPE_NEW = "BAYERN_ID"; + private static final String VORGANG_COLLECTION = "vorgang"; + + @Execution + public void doMigration(MongoTemplate template) { + updateVorgangHeader(template); + updateEingangsHeader(template); + } + + private void updateVorgangHeader(MongoTemplate template) { + template.updateMulti(createFilterQuery(KEY_HEADER_SERVICE_KONTO_TYPE), createUpdate(KEY_HEADER_SERVICE_KONTO_TYPE), VORGANG_COLLECTION); + } + + private void updateEingangsHeader(MongoTemplate template) { + template.updateMulti(createFilterQuery(KEY_EINGANG_SERVICE_KONTO_TYPE), createUpdate("eingangs.$[]." + KEY_HEADER_SERVICE_KONTO_TYPE), + VORGANG_COLLECTION); + } + + private Query createFilterQuery(String key) { + return new Query(Criteria.where(key).in(POSSIBLE_BAYERN_ID_TYPE)); + } + + private Update createUpdate(String key) { + return new Update().set(key, BAYERN_ID_TYPE_NEW); + } + + @RollbackExecution + public void rollback() { + // kein rollback implementiert + } +} \ No newline at end of file diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java index c844c3f36cc550abab150590103780d6b28bdc84..3e15c4de420cec0b23cf9338e795816acd9fc705 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java @@ -24,8 +24,6 @@ package de.ozgcloud.vorgang.common.search; import java.text.MessageFormat; -import java.util.Collections; -import java.util.HashMap; import org.apache.commons.collections.MapUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -34,11 +32,11 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import de.ozgcloud.command.Command; +import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; import de.ozgcloud.vorgang.command.CommandService; import de.ozgcloud.vorgang.status.StatusChangedEvent; import de.ozgcloud.vorgang.vorgang.SetAktenzeichenCompletedEvent; -import de.ozgcloud.vorgang.vorgang.VorgangAssignedEvent; import de.ozgcloud.vorgang.vorgang.VorgangDeletedEvent; import de.ozgcloud.vorgang.vorgang.VorgangService; import lombok.extern.log4j.Log4j2; diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/userconfig/UserConfigService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/userconfig/UserConfigService.java index b7e0a3b89913ecac2c47e1a9cc9e20649743b46a..8a32bc95d96fa69088182ce7e9627059d3609767 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/userconfig/UserConfigService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/userconfig/UserConfigService.java @@ -2,11 +2,15 @@ package de.ozgcloud.vorgang.common.userconfig; import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor public class UserConfigService { - @Autowired - private UserConfigRemoteService userConfigRemoteService; + + private final UserConfigRemoteService userConfigRemoteService; public List<String> getSupportedOrganisationsEinheiten() { return userConfigRemoteService.getSupportedOrganisationsEinheiten(); diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryScheduler.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryScheduler.java index 171439dbfbd3f234b2b5801b322cb963379f7972..778f33bf0339e0bf0e0d08b9a2c5806498a37e33 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryScheduler.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryScheduler.java @@ -25,29 +25,34 @@ package de.ozgcloud.vorgang.registry; import java.util.concurrent.TimeUnit; -import org.springframework.beans.factory.annotation.Autowired; +import jakarta.annotation.PostConstruct; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import de.ozgcloud.vorgang.common.userconfig.UserConfigService; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; -@Profile("!itcase") @Component -@ConditionalOnProperty(prefix = "ozgcloud.vorgang-manager", name = { "address" }) +@ConditionalOnProperty(prefix = "ozgcloud.zufi-manager", name = { "address" }) @Log4j2 +@RequiredArgsConstructor class RegistryScheduler { - @Autowired - private RegistryService registryService; - @Autowired - private UserConfigService userConfigService; + private final RegistryService registryService; + + private final UserConfigService userConfigService; + + @PostConstruct + void logInitialization() { + LOG.info("Starting ZuFi registry scheduler"); + } - @Scheduled(fixedDelayString = "${ozgcloud.vorgang-manager.registry.scheduler.fixedDelay:5}", // - initialDelayString = "${ozgcloud.vorgang-manager.registry.scheduler.initialDelay:5}", // + @Scheduled(fixedDelayString = "${ozgcloud.registry.scheduler.fixedDelayMinutes}", + initialDelayString = "${ozgcloud.registry.scheduler.initialDelayMinutes}", timeUnit = TimeUnit.MINUTES) @SchedulerLock(name = "RegistryScheduler") void register() { diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryService.java index e2e8475bf30d833e339a9f688503611b2569ff98..028946325fe06593c20f604a94abc1679a2a8d66 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/RegistryService.java @@ -1,43 +1,28 @@ package de.ozgcloud.vorgang.registry; import java.util.List; -import java.util.Optional; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; +import de.ozgcloud.vorgang.VorgangManagerProperties; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Service @Log4j2 +@RequiredArgsConstructor +@ConditionalOnProperty(prefix = "ozgcloud.zufi-manager", name = { "address" }) class RegistryService { - @Value(value = "${ozgcloud.vorgang-manager.address:#{null}}") - private Optional<String> vorgangManagerAddress; - @Autowired - private ZufiRemoteService zufiRemoteService; + private final VorgangManagerProperties vorgangManagerProperties; + private final ZufiRemoteService zufiRemoteService; public void registerVorgangManager(List<String> supportedOrganisationsEinheiten) { - try { - register(supportedOrganisationsEinheiten); - } catch (Exception e) { - LOG.error("Error registering this VorgangsManager.", e); + if (supportedOrganisationsEinheiten.isEmpty()) { + LOG.warn("Missing organisationseinheitenIds. Skipping registration."); + return; } - } - - private void register(List<String> supportedOrganisationsEinheiten) { - if (CollectionUtils.isNotEmpty(supportedOrganisationsEinheiten)) { - registerAddress(supportedOrganisationsEinheiten, vorgangManagerAddress); - } else { - LOG.warn("No OrganistationsEinheitenIds provided. Not registering this VorgangsManager"); - } - } - - void registerAddress(List<String> supportedOrganisationsEinheiten, Optional<String> vorgangManagerAddress) { - vorgangManagerAddress.ifPresentOrElse(address -> { - zufiRemoteService.registerVorgangManager(supportedOrganisationsEinheiten, address); - }, () -> LOG.error("Property ozgcloud.vorgang-manager.address not set. Not registering this VorgangsManager")); + zufiRemoteService.registerVorgangManager(supportedOrganisationsEinheiten, vorgangManagerProperties.getAddress()); } } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java index bc436dedd25d7bd9ee4ef1ad95f7cfffb1612e8b..aab5f17c1c67ebe61d6122fb13a3da561628ed6b 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java @@ -2,25 +2,29 @@ package de.ozgcloud.vorgang.registry; import java.util.List; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor; -import de.ozgcloud.zufi.grpc.registration.GrpcVorgangManagerRegistrationRequest; -import de.ozgcloud.zufi.grpc.registration.VorgangManagerRegistrationServiceGrpc.VorgangManagerRegistrationServiceBlockingStub; +import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcVorgangManagerRegistrationRequest; +import de.ozgcloud.zufi.grpc.organisationseinheit.VorgangManagerRegistrationServiceGrpc.VorgangManagerRegistrationServiceBlockingStub; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.devh.boot.grpc.client.inject.GrpcClient; @Log4j2 @Service +@ConditionalOnProperty(prefix = "ozgcloud.zufi-manager", name = { "address" }) class ZufiRemoteService { + @GrpcClient("zufi-manager") private VorgangManagerRegistrationServiceBlockingStub serviceStub; public void registerVorgangManager(@NonNull List<String> organistationsEinheitenIds, String vorgangManagerAddress) { - boolean success = getServiceStub() - .register(buildRequest(organistationsEinheitenIds, vorgangManagerAddress)).getSuccess(); - LOG.info("Register success: " + success); + var result = getServiceStub().register(buildRequest(organistationsEinheitenIds, vorgangManagerAddress)); + if (!result.getSuccess()) { + LOG.warn("Registration failed: {}", result.getMessage()); + } } private VorgangManagerRegistrationServiceBlockingStub getServiceStub() { 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 51e2ba9baad098db8ba6c73cd84f6ee75ddd8d1a..67678fb2648931db32733b0f3c113d43e0d87bc5 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 @@ -42,6 +42,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import de.ozgcloud.command.Command; +import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; import de.ozgcloud.vorgang.clientattribute.ClientAttributeMap; import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted; diff --git a/vorgang-manager-server/src/main/resources/application-local.yml b/vorgang-manager-server/src/main/resources/application-local.yml index 3c001700cf121f982f772d96606412189ad50db3..f6a467f4938cfac669d42e0bbf2c81cfd10d9eb4 100644 --- a/vorgang-manager-server/src/main/resources/application-local.yml +++ b/vorgang-manager-server/src/main/resources/application-local.yml @@ -43,6 +43,9 @@ grpc: enabled: false spring: + cloud: + config: + enabled: false data: mongodb: database: vorgang-manager-local @@ -55,7 +58,12 @@ spring: '[mail.smtp.starttls.enable]': true ozgcloud: + administration: + sync: + enabled: false aktenzeichen: de.ozgcloud.vorgang.vorgang.AktenzeichenProviderEA + application: + address: http://localhost:9090 notification: mail-from: ea@ozg-sh.de redirect: @@ -64,7 +72,7 @@ ozgcloud: url: http://localhost:9092/migration/user user: cleanup: - cron: 0 */5 * * * * + cron: "-" feature: bescheid: enable-dummy-document-processor: true diff --git a/vorgang-manager-server/src/main/resources/application.yml b/vorgang-manager-server/src/main/resources/application.yml index 6784f1d84c27c3a9745a4eb3f978d175cb440eeb..7bf48c56cfe7b1d089dd2dc367d1b6bcdd25d09c 100644 --- a/vorgang-manager-server/src/main/resources/application.yml +++ b/vorgang-manager-server/src/main/resources/application.yml @@ -5,12 +5,14 @@ logging: mongock: runner-type: initializingbean - migration-scan-package: + migration-scan-package: - de.ozgcloud.vorgang.common.migration enabled: true transactionEnabled: false spring: + config: + import: optional:configserver:${ozgcloud_administration_address}/configserver/ application: name: OzgCloud_VorgangManager data: @@ -28,7 +30,7 @@ grpc: address: self:self negotiationType: TLS user-manager: - negotiationType: TLS + negotiationType: TLS email: address: self:self negotiationType: TLS @@ -40,6 +42,8 @@ grpc: command-manager: address: self:self negotiationType: PLAINTEXT + zufi-manager: + negotiationType: TLS server: security: @@ -68,10 +72,17 @@ management: endpoints: web: exposure: - include: health,prometheus + include: health,prometheus,refresh ozgcloud: + administration: + sync: + delay: 900_000 production: false + registry: + scheduler: + fixedDelayMinutes: 5 + initialDelayMinutes: 5 osi: postfach: scheduler: @@ -80,6 +91,8 @@ ozgcloud: mail-from: EA-Poststelle@itvsh.de notification: mail-from: hilfe@ozgcloud.support + wiedervorlageDueToday: + cron: "0 15 0 * * *" nachrichten-manager: address: self:self negotiation-type: plaintext @@ -96,4 +109,4 @@ ozgcloud: user-manager: address: ${grpc.client.user-manager.address:false} negotiation-type: ${grpc.client.user-manager.negotiationType} - + diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumITCase.java index 61fc27b309e3d269706f3a8bd3c1fd74da19ff6e..1488e8f8dd4f1baef4b2831081ccd6a078a6ef36 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumITCase.java @@ -181,7 +181,7 @@ class AntragraumITCase { grpcService.findRueckfragen( GrpcFindRueckfrageRequestTestFactory.createBuilder().setSamlToken(TestUtils.loadTextFile("SamlResponse.xml")).build(), responseObserver); - verify(responseObserver).onNext(captor.capture()); + verify(responseObserver, timeout(30000)).onNext(captor.capture()); return captor.getValue().getRueckfrageHeadList(); } } @@ -189,12 +189,13 @@ class AntragraumITCase { private Vorgang createVorgang(TrustLevel trustLevel) { return VorgangTestFactory.createBuilder() .id(null) + .version(0) .header(VorgangHeadTestFactory.createBuilder().serviceKonto(createBayernIdServiceKonto(trustLevel)).build()) .build(); } private ServiceKonto createBayernIdServiceKonto(TrustLevel trustLevel) { - return ServiceKontoTestFactory.createBuilder().type("BayernID").trustLevel(trustLevel.getValue()).build(); + return ServiceKontoTestFactory.createBuilder().type("BAYERN_ID").trustLevel(trustLevel.getValue()).build(); } private VorgangAttachedItem createPostfachNachrichtVorgangAttachedItem(String vorgangId) { @@ -219,7 +220,7 @@ class AntragraumITCase { PostfachAddress.VERSION_FIELD, 1, PostfachAddress.IDENTIFIER_FIELD, Map.of(PostfachNachricht.FIELD_POSTFACH_ID, PostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE), - PostfachAddress.SERVICEKONTO_TYPE_FIELD, "BayernID")); + PostfachAddress.SERVICEKONTO_TYPE_FIELD, "BAYERN_ID")); return nachrichtItem; } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java index 516b1ea807fd936a7d7c91b034f8bba505c02017..c609c9f7e9df3ea1e1ff757b819d6dcce45169a7 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java @@ -23,14 +23,20 @@ */ package de.ozgcloud.nachrichten.postfach; +import static org.awaitility.Awaitility.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.TimeUnit; 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.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -40,10 +46,14 @@ import org.springframework.context.ApplicationEventPublisher; import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandCreatedEvent; +import de.ozgcloud.command.VorgangAttachedItemCreatedEvent; import de.ozgcloud.common.test.ITCase; +import de.ozgcloud.notification.user.UserNotificationEventListener; import de.ozgcloud.vorgang.VorgangManagerServerApplication; +import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem; import de.ozgcloud.vorgang.command.CommandService; import de.ozgcloud.vorgang.command.CommandTestFactory; +import de.ozgcloud.vorgang.command.Order; import de.ozgcloud.vorgang.vorgang.VorgangService; @ITCase @@ -65,6 +75,9 @@ class PostfachEventListenerITCase { @MockBean private CommandService commandService; + @MockBean + private UserNotificationEventListener userNotificationEventListener; + @Nested class TestSendPostfachNachricht { @@ -89,4 +102,54 @@ class PostfachEventListenerITCase { } } + @Nested + class TestOnIncomingPostfachNachrichtItemCreated { + + private static final Command COMMAND = CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.name()) + .bodyObject(Map.of(VorgangAttachedItem.FIELDNAME_ITEM_NAME, AttachedItemRemoteService.ITEM_NAME, + PostfachNachricht.FIELD_DIRECTION, "IN")).build(); + + @Test + void shouldCallListener() { + var event = new VorgangAttachedItemCreatedEvent(COMMAND, CommandTestFactory.CREATED_RESOURCE); + + publisher.publishEvent(event); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(listener).onIncomingPostfachNachrichtItemCreated(event)); + } + + @DisplayName("should not call listener") + @ParameterizedTest(name = "on order {0}") + @EnumSource(value = Order.class, names = { "CREATE_ATTACHED_ITEM" }, mode = EnumSource.Mode.EXCLUDE) + void shouldNotCallListenerOnWrongOrder(Order order) { + var command = CommandTestFactory.createBuilder().order(order.name()).build(); + + publisher.publishEvent(new VorgangAttachedItemCreatedEvent(command, CommandTestFactory.CREATED_RESOURCE)); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(listener, never()).onIncomingPostfachNachrichtItemCreated(any())); + } + + @DisplayName("should not call listener when not postfach mail item") + @Test + void shouldNotCallListenerOnWrongItem() { + var command = CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.name()) + .bodyObject(Map.of(VorgangAttachedItem.FIELDNAME_ITEM_NAME, "not-postfach-mail-item")).build(); + + publisher.publishEvent(new VorgangAttachedItemCreatedEvent(command, CommandTestFactory.CREATED_RESOURCE)); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(listener, never()).onIncomingPostfachNachrichtItemCreated(any())); + } + + @DisplayName("should not call listener when not incoming item") + @Test + void shouldNotCallListenerOnWrongDirection() { + var command = CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.name()) + .bodyObject(Map.of(VorgangAttachedItem.FIELDNAME_ITEM_NAME, AttachedItemRemoteService.ITEM_NAME, + PostfachNachricht.FIELD_DIRECTION, "OUT")).build(); + + publisher.publishEvent(new VorgangAttachedItemCreatedEvent(command, CommandTestFactory.CREATED_RESOURCE)); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(listener, never()).onIncomingPostfachNachrichtItemCreated(any())); + } + } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java index 1ef45402d363fe6e8a0a695dd349c88383f31773..fbae6587b954a7ec5313c997719bb4ceb03d97b2 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java @@ -164,4 +164,5 @@ class VorgangAttachedItemEventListenerITCase { await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(service).revokeDelete(command)); } } + } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java index 28611d93e880d5012906f5dc8da81aea4c5a2846..26b2c4ba13544fdaf44d06f89a12a5308a2b676a 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java @@ -51,6 +51,7 @@ import org.springframework.context.ApplicationEventPublisher; import de.ozgcloud.command.Command; import de.ozgcloud.command.RevokeCommandEvent; +import de.ozgcloud.command.VorgangAttachedItemCreatedEvent; import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory; import de.ozgcloud.vorgang.command.CommandService; import de.ozgcloud.vorgang.command.CommandTestFactory; @@ -98,7 +99,7 @@ class VorgangAttachedItemEventListenerTest { void withItem() { listener.createItem(CommandCreatedEventTestFactory.create(command)); - verify(service).create(eq(CommandTestFactory.ID), itemCaptor.capture()); + verify(service).create(eq(command), itemCaptor.capture()); assertThat(itemCaptor.getValue()).usingRecursiveComparison() .ignoringFields(VorgangAttachedItem.FIELDNAME_ID, VorgangAttachedItem.FIELDNAME_VERSION) .isEqualTo(VorgangAttachedItemTestFactory.create()); @@ -108,7 +109,7 @@ class VorgangAttachedItemEventListenerTest { void withIdAndVersionAsNull() { listener.createItem(CommandCreatedEventTestFactory.create(command)); - verify(service).create(eq(CommandTestFactory.ID), itemCaptor.capture()); + verify(service).create(eq(command), itemCaptor.capture()); var item = itemCaptor.getValue(); assertThat(item.getId()).isNull(); @@ -496,4 +497,5 @@ class VorgangAttachedItemEventListenerTest { verify(service).revokePatch(command, CommandTestFactory.PREVIOUS_STATE); } } + } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java index cfaf9ff74c00daa0d1405a656fb898ce181a0256..ef465103f6ad9e81c6a4741bd581d40179b1d6aa 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java @@ -289,7 +289,8 @@ class VorgangAttachedItemITCase { private Command createRevokeCommand() { return CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.name()) .relationId(persistedItem.getId()) - .relationVersion(persistedItem.getVersion()) + .relationVersion(persistedItem.getVersion() - 1) + .createdResource(persistedItem.getId()) .bodyObject(VorgangAttachedItemTestFactory.asMap()).build(); } } @@ -298,11 +299,11 @@ class VorgangAttachedItemITCase { @Nested class TestRevokeUpdateItem { - private final Map<String, Object> createItem = Map.<String, Object>of("EntryToRecoverByRevokeKey", "EntryToRecoverByRevokeValue", + private final Map<String, Object> createItem = Map.of("EntryToRecoverByRevokeKey", "EntryToRecoverByRevokeValue", VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE); private VorgangAttachedItem persistedItem; - private final Map<String, Object> updateItem = Map.<String, Object>of( + private final Map<String, Object> updateItem = Map.of( VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, "RevertByRevokeValue", "NewToRemoveByRevokeKey", "NewToRemoveByRevokeValue"); private Command updatedCommand; @@ -391,11 +392,11 @@ class VorgangAttachedItemITCase { @Nested class TestRevokePatchItem { - private final Map<String, Object> createItem = Map.<String, Object>of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, + private final Map<String, Object> createItem = Map.of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE); private VorgangAttachedItem persistedItem; - private final Map<String, Object> patchItem = Map.<String, Object>of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, "UpdatedStringValue"); + private final Map<String, Object> patchItem = Map.of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, "UpdatedStringValue"); private Command patchedCommand; private String vorgangId; diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java index 6bafdceabe71af6f52b99993f7a89d309f612924..ca9b0e78ab82bf475d52383be1dbae940bb6e3fb 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java @@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.ApplicationEventPublisher; +import de.ozgcloud.command.Command; import de.ozgcloud.common.test.ITCase; import de.ozgcloud.vorgang.command.CommandTestFactory; @@ -27,25 +28,28 @@ class VorgangAttachedItemServiceITCase { @Nested class TestCreate { + + private static final Command COMMAND = CommandTestFactory.create(); + @Test void shouldDenyMissingClientName() { var item = VorgangAttachedItemTestFactory.createBuilder().client(StringUtils.EMPTY).build(); - assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item)).isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> service.create(COMMAND, item)).isInstanceOf(ConstraintViolationException.class); } @Test void shouldDenyMissingVorgangId() { var item = VorgangAttachedItemTestFactory.createBuilder().vorgangId(StringUtils.EMPTY).build(); - assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item)).isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> service.create(COMMAND, item)).isInstanceOf(ConstraintViolationException.class); } @Test void shouldDenyMissingItemName() { var item = VorgangAttachedItemTestFactory.createBuilder().itemName(StringUtils.EMPTY).build(); - assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item)).isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> service.create(COMMAND, item)).isInstanceOf(ConstraintViolationException.class); } } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java index 932e678e5585088726653434c5e55ee0210fc3a9..7447aa18488ebd0ed7406989214afbda377580da 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -46,6 +47,8 @@ import org.springframework.context.ApplicationEventPublisher; import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandRevokeFailedEvent; import de.ozgcloud.command.CommandRevokedEvent; +import de.ozgcloud.command.VorgangAttachedItemCreatedEvent; +import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory; import de.ozgcloud.vorgang.command.CommandTestFactory; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; @@ -64,53 +67,205 @@ class VorgangAttachedItemServiceTest { @Nested class TestCreateItem { + private static final VorgangAttachedItem PREPARED_ITEM = VorgangAttachedItemTestFactory.create(); + private static final VorgangAttachedItem PERSISTED_ITEM = VorgangAttachedItemTestFactory.createBuilder() + .id(CommandTestFactory.CREATED_RESOURCE).build(); + + @Captor + private ArgumentCaptor<VorgangAttachedItemCreatedEvent> eventCaptor; + + @BeforeEach + void init() { + when(repository.save(any())).thenReturn(PERSISTED_ITEM); + doReturn(PREPARED_ITEM).when(service).prepareForCreation(any()); + } + + @Test + void shouldCallPrepareForCreation() { + var item = VorgangAttachedItemTestFactory.create(); + + service.create(CommandTestFactory.create(), item); + + verify(service).prepareForCreation(item); + } + @Test void shouldCallRepository() { - when(repository.save(any())).thenReturn(VorgangAttachedItemTestFactory.create()); + service.create(CommandTestFactory.create(), VorgangAttachedItemTestFactory.create()); + + verify(repository).save(PREPARED_ITEM); + } + + @Test + void shouldCallBuildExecutedCommand() { + var command = CommandTestFactory.create(); - service.create(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create()); + service.create(command, VorgangAttachedItemTestFactory.create()); - verify(repository).save(any()); + verify(service).buildExecutedCommand(command, PERSISTED_ITEM); } @Test void shouldPublishEvent() { - when(repository.save(any())).thenReturn(VorgangAttachedItemTestFactory.create()); + var executedCommand = CommandTestFactory.create(); + doReturn(executedCommand).when(service).buildExecutedCommand(any(), any()); - service.create(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create()); + service.create(CommandTestFactory.create(), VorgangAttachedItemTestFactory.create()); - verify(publisher).publishEvent(any(VorgangAttachedItemCreatedEvent.class)); + verify(publisher).publishEvent(eventCaptor.capture()); + assertThat(eventCaptor.getValue()).satisfies(event -> { + assertThat(event.getCommand()).isSameAs(executedCommand); + assertThat(event.getCreatedResource()).isEqualTo(CommandTestFactory.CREATED_RESOURCE); + }); } + } - @Nested - class TestPrepareForCreation { - @Test - void shouldRemoveId() { - var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); + @Nested + class TestPrepareForCreation { + @Test + void shouldRemoveId() { + var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); - assertThat(prepared.getId()).isNull(); - } + assertThat(prepared.getId()).isNull(); + } - @Test - void shouldSetVersionToZero() { - var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); + @Test + void shouldSetVersionToZero() { + var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); - assertThat(prepared.getVersion()).isZero(); - } + assertThat(prepared.getVersion()).isZero(); + } - @Test - void shouldRemoveIdFromItem() { - var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); + @Test + void shouldRemoveIdFromItem() { + var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); - assertThat(prepared.getItem()).doesNotContainKey(VorgangAttachedItem.FIELDNAME_ID); - } + assertThat(prepared.getItem()).doesNotContainKey(VorgangAttachedItem.FIELDNAME_ID); + } - @Test - void shouldSetIsDeletedToFalse() { - var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); + @Test + void shouldSetIsDeletedToFalse() { + var prepared = service.prepareForCreation(VorgangAttachedItemTestFactory.create()); - assertThat(prepared.isDeleted()).isFalse(); - } + assertThat(prepared.isDeleted()).isFalse(); + } + } + + @Nested + class TestBuildExecutedCommand { + + private static final VorgangAttachedItem ITEM = VorgangAttachedItemTestFactory.create(); + + @Test + void shouldSetId() { + var result = buildExecutedCommand(); + + assertThat(result.getId()).isEqualTo(CommandTestFactory.ID); + } + + @Test + void shouldSetVorgangId() { + var result = buildExecutedCommand(); + + assertThat(result.getVorgangId()).isEqualTo(VorgangTestFactory.ID); + } + + @Test + void shouldSetRelationId() { + var result = buildExecutedCommand(); + + assertThat(result.getRelationId()).isEqualTo(CommandTestFactory.RELATION_ID); + } + + @Test + void shouldSetRelationVersion() { + var result = buildExecutedCommand(); + + assertThat(result.getRelationVersion()).isEqualTo(CommandTestFactory.RELATION_VERSION); + } + + @Test + void shouldSetOrder() { + var result = buildExecutedCommand(); + + assertThat(result.getOrder()).isEqualTo(CommandTestFactory.ORDER.name()); + } + + @Test + void shouldSetCreatedAt() { + var result = buildExecutedCommand(); + + assertThat(result.getCreatedAt()).isEqualTo(CommandTestFactory.CREATED_AT); + } + + @Test + void shouldSetCreatedBy() { + var result = buildExecutedCommand(); + + assertThat(result.getCreatedBy()).isEqualTo(CommandTestFactory.CREATED_BY); + } + + @Test + void shouldSetStatus() { + var result = buildExecutedCommand(); + + assertThat(result.getStatus()).isEqualTo(CommandTestFactory.STATUS); + } + + @Test + void shouldSetCreatedResource() { + var result = buildExecutedCommand(); + + assertThat(result.getCreatedResource()).isEqualTo(VorgangAttachedItemTestFactory.ID); + } + + @Test + void shouldCallBuildBodyObject() { + buildExecutedCommand(); + + verify(service).buildBodyObject(ITEM); + } + + @Test + void shouldSetBodyObject() { + var bodyObject = Map.<String, Object>of("key", "value"); + doReturn(bodyObject).when(service).buildBodyObject(any()); + + var result = buildExecutedCommand(); + + assertThat(result.getBodyObject()).isEqualTo(bodyObject); + } + + private Command buildExecutedCommand() { + return service.buildExecutedCommand(CommandTestFactory.create(), ITEM); + } + } + + @Nested + class TestBuildBodyObject { + + @Test + void shouldSetItemName() { + var result = service.buildBodyObject(VorgangAttachedItemTestFactory.create()); + + assertThat(result).containsEntry(VorgangAttachedItem.FIELDNAME_ITEM_NAME, ITEM_NAME); + } + + @Test + void shouldSetMailDirection() { + var item = VorgangAttachedItemTestFactory.createBuilder() + .item(Map.of(PostfachNachricht.FIELD_DIRECTION, PostfachNachricht.Direction.IN.name())).build(); + + var result = service.buildBodyObject(item); + + assertThat(result).containsEntry(PostfachNachricht.FIELD_DIRECTION, PostfachNachricht.Direction.IN.name()); + } + + @Test + void shouldHandleMissingDirection() { + var result = service.buildBodyObject(VorgangAttachedItemTestFactory.create()); + + assertThat(result).doesNotContainKey(PostfachNachricht.FIELD_DIRECTION); } } @@ -361,7 +516,7 @@ class VorgangAttachedItemServiceTest { @Nested class TestRevokeCreate { - private final Command command = CommandTestFactory.create(); + private final Command command = CommandTestFactory.createBuilder().createdResource(CommandTestFactory.CREATED_RESOURCE).build(); @Test void shouldCallHandleRevoke() { @@ -374,7 +529,7 @@ class VorgangAttachedItemServiceTest { void shouldCallDelete() { service.revokeCreate(command); - verify(service).delete(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION); + verify(service).delete(CommandTestFactory.CREATED_RESOURCE, CommandTestFactory.RELATION_VERSION + 1); } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/collaboration/CollaborationITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/collaboration/CollaborationITCase.java index 32db2a67bebf61625a2e5eea835a61eaa5c87665..3a1508c570ac7a6ac3bd1e41fe1815041e1541e6 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/collaboration/CollaborationITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/collaboration/CollaborationITCase.java @@ -24,7 +24,6 @@ package de.ozgcloud.vorgang.collaboration; import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.InstanceOfAssertFactories.*; import static org.awaitility.Awaitility.*; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.*; @@ -41,6 +40,8 @@ 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.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -60,7 +61,11 @@ import de.ozgcloud.collaboration.CollaborationServiceGrpc.CollaborationServiceBl import de.ozgcloud.collaboration.GrpcGetFileContentRequest; import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandStatus; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.common.test.DataITCase; +import de.ozgcloud.nachrichten.postfach.PostfachAddress; +import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.PostfachRemoteService; import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem; import de.ozgcloud.vorgang.callcontext.CallContext; import de.ozgcloud.vorgang.callcontext.TestCallContextAttachingInterceptor; @@ -71,6 +76,7 @@ import de.ozgcloud.vorgang.command.CreateCommandRequest; import de.ozgcloud.vorgang.files.FileService; import de.ozgcloud.vorgang.files.GridFsTestFactory; import de.ozgcloud.vorgang.files.OzgFileTestFactory; +import de.ozgcloud.vorgang.servicekonto.PostfachAddressTestFactory; import de.ozgcloud.vorgang.vorgang.Vorgang; import de.ozgcloud.vorgang.vorgang.VorgangHead; import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; @@ -89,6 +95,10 @@ import net.devh.boot.grpc.client.inject.GrpcClient; @DirtiesContext class CollaborationITCase { + private static final String FIELD_COLLABORATION_VORGANG_ID = "collaborationVorgangId"; + private static final String TITEL = "Collaboration Vorgang"; + private static final String ANFRAGE = "Anfrage"; + @Autowired private CommandService commandService; @@ -97,85 +107,21 @@ class CollaborationITCase { @MockBean private OzgCloudUserProfileService ozgCloudUserProfileService; + @MockBean + private PostfachRemoteService postfachRemoteService; @Mock private OzgCloudUserProfile ozgCloudUserProfile; - @Nested - class TestCreateCollaborationVorgang { + private String vorgangId; - @BeforeEach - void init() { - mongoOperations.dropCollection(Command.class); - mongoOperations.dropCollection(Vorgang.class); - mongoOperations.dropCollection(VorgangAttachedItem.class); - when(ozgCloudUserProfile.getId()).thenReturn(OzgCloudUserId.from(CommandTestFactory.CREATED_BY)); - when(ozgCloudUserProfileService.getById(any())).thenReturn(ozgCloudUserProfile); - - vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0L).build()).getId(); - } - - private static final String FIELD_COLLABORATION_VORGANG_ID = "collaborationVorgangId"; - private static final String TITEL = "Collaboration Vorgang"; - private static final String ANFRAGE = "Anfrage"; - - private String vorgangId; - - @Test - void shouldSetCollaborationVorgangId() { - var command = commandService.createCommand(buildCreateCollaborationVorgangCommand(vorgangId)); + @BeforeEach + void init() { + mongoOperations.dropCollection(Command.class); + mongoOperations.dropCollection(Vorgang.class); + mongoOperations.dropCollection(VorgangAttachedItem.class); - waitUntilCommandFinished(command.getId()); - - var collaborationRequests = loadCollaborationRequest(vorgangId); - assertThat(collaborationRequests).hasSize(1).first().extracting(VorgangAttachedItem::getItem, MAP) - .containsKey(FIELD_COLLABORATION_VORGANG_ID); - } - - @Test - void shouldCreateCollaborationVorgang() { - var command = commandService.createCommand(buildCreateCollaborationVorgangCommand(vorgangId)); - - waitUntilCommandFinished(command.getId()); - - var collaborationVorgang = loadCollaborationVorgang(vorgangId); - assertThat(collaborationVorgang.getHeader()).extracting(VorgangHead::getCollaborationLevel) - .isEqualTo(CreateCollaborationVorgangRequestTestFactory.COLLABORATION_LEVEL); - assertThat(collaborationVorgang.getHeader()).extracting(VorgangHead::getOrganisationsEinheitId) - .isEqualTo(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); - assertThat(collaborationVorgang.getClientAttributes()).isEmpty(); - } - - private CreateCommandRequest buildCreateCollaborationVorgangCommand(String vorgangId) { - return CreateCommandRequest.builder() - .callContext(CallContext.builder().client("test").build()) - .vorgangId(vorgangId) - .relationId(vorgangId) - .order("CREATE_COLLABORATION_REQUEST") - .bodyObject(Map.of( - "titel", TITEL, - "anfrage", ANFRAGE, - "zustaendigeStelle", ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)) - .build(); - } - - private void waitUntilCommandFinished(String commandId) { - await().atMost(60, TimeUnit.SECONDS).until( - () -> mongoOperations.findById(commandId, Command.class), - command -> command.getStatus() == CommandStatus.FINISHED); - } - - private Vorgang loadCollaborationVorgang(String sourceVorgangId) { - var collaborationVorgangId = loadCollaborationRequest(sourceVorgangId).getFirst().getItem().get(FIELD_COLLABORATION_VORGANG_ID); - return mongoOperations.findById(collaborationVorgangId, Vorgang.class); - } - - private List<VorgangAttachedItem> loadCollaborationRequest(String vorgangId) { - var query = new Query(new Criteria().andOperator( - Criteria.where(VorgangAttachedItem.FIELDNAME_VORGANG_ID).is(vorgangId), - Criteria.where(VorgangAttachedItem.FIELDNAME_ITEM_NAME).is("CollaborationRequest"))); - return mongoOperations.find(query, VorgangAttachedItem.class); - } + vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0L).build()).getId(); } @DisplayName("Get file content") @@ -244,4 +190,121 @@ class CollaborationITCase { return collaborationStub.withInterceptors(new TestCallContextAttachingInterceptor()); } } + + private CreateCommandRequest buildCreateCollaborationVorgangCommand(String vorgangId, int collaborationLevel) { + return CreateCommandRequest.builder() + .callContext(CallContext.builder().client("test").build()) + .vorgangId(vorgangId) + .relationId(vorgangId) + .order("CREATE_COLLABORATION_REQUEST") + .bodyObject(Map.of( + "titel", TITEL, + "anfrage", ANFRAGE, + "collaborationLevel", collaborationLevel, + "zustaendigeStelle", ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)) + .build(); + } + + private List<VorgangAttachedItem> loadCollaborationRequest(String vorgangId) { + var query = new Query(new Criteria().andOperator( + Criteria.where(VorgangAttachedItem.FIELDNAME_VORGANG_ID).is(vorgangId), + Criteria.where(VorgangAttachedItem.FIELDNAME_ITEM_NAME).is("CollaborationRequest"))); + return mongoOperations.find(query, VorgangAttachedItem.class); + } + + private void waitUntilCommandHasStatus(String commandId, CommandStatus status) { + await().atMost(60, TimeUnit.SECONDS).until( + () -> mongoOperations.findById(commandId, Command.class), + command -> command.getStatus() == status); + } + + @Nested + class TestCreateCollaborationVorgang { + + @BeforeEach + void init() { + when(ozgCloudUserProfile.getId()).thenReturn(OzgCloudUserId.from(CommandTestFactory.CREATED_BY)); + when(ozgCloudUserProfileService.getById(any())).thenReturn(ozgCloudUserProfile); + } + + @Test + void shouldSetCollaborationVorgangId() { + var command = commandService.createCommand( + buildCreateCollaborationVorgangCommand(vorgangId, CreateCollaborationVorgangRequestTestFactory.COLLABORATION_LEVEL)); + + waitUntilCommandHasStatus(command.getId(), CommandStatus.FINISHED); + + var collaborationRequests = loadCollaborationRequest(vorgangId); + assertThat(collaborationRequests).hasSize(1).first().extracting(VorgangAttachedItem::getItem, MAP) + .containsKey(FIELD_COLLABORATION_VORGANG_ID); + } + + @Test + void shouldCreateCollaborationVorgang() { + var command = commandService.createCommand( + buildCreateCollaborationVorgangCommand(vorgangId, CreateCollaborationVorgangRequestTestFactory.COLLABORATION_LEVEL)); + + waitUntilCommandHasStatus(command.getId(), CommandStatus.FINISHED); + + var collaborationVorgang = loadCollaborationVorgang(vorgangId); + assertThat(collaborationVorgang.getHeader()).extracting(VorgangHead::getCollaborationLevel) + .isEqualTo(CreateCollaborationVorgangRequestTestFactory.COLLABORATION_LEVEL); + assertThat(collaborationVorgang.getHeader()).extracting(VorgangHead::getOrganisationsEinheitId) + .isEqualTo(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); + assertThat(collaborationVorgang.getClientAttributes()).isEmpty(); + } + + private Vorgang loadCollaborationVorgang(String sourceVorgangId) { + var collaborationVorgangId = loadCollaborationRequest(sourceVorgangId).getFirst().getItem().get(FIELD_COLLABORATION_VORGANG_ID); + return mongoOperations.findById(collaborationVorgangId, Vorgang.class); + } + + } + + @Nested + class TestCreateFachstellenBeteiligungRequest { + + private static final int COLLABORATION_LEVEL = 4; + + @Captor + private ArgumentCaptor<PostfachNachricht> postfachNachrichtCaptor; + + @BeforeEach + void init() { + when(ozgCloudUserProfile.getId()).thenReturn(OzgCloudUserId.from(CommandTestFactory.CREATED_BY)); + when(ozgCloudUserProfileService.getById(any())).thenReturn(ozgCloudUserProfile); + } + + @Test + void shouldCreateCollaborationRequest() { + var command = commandService.createCommand(buildCreateCollaborationVorgangCommand(vorgangId, COLLABORATION_LEVEL)); + + waitUntilCommandHasStatus(command.getId(), CommandStatus.FINISHED); + + var collaborationRequests = loadCollaborationRequest(vorgangId); + assertThat(collaborationRequests).hasSize(1).first().extracting(VorgangAttachedItem::getItem, MAP) + .containsEntry(FIELD_COLLABORATION_VORGANG_ID, vorgangId); + } + + @Test + void shouldSendPostfachNachricht() { + var command = commandService.createCommand(buildCreateCollaborationVorgangCommand(vorgangId, COLLABORATION_LEVEL)); + + waitUntilCommandHasStatus(command.getId(), CommandStatus.FINISHED); + + verify(postfachRemoteService).sendMessage(postfachNachrichtCaptor.capture()); + assertThat(postfachNachrichtCaptor.getValue().getPostfachAddress()).extracting(PostfachAddress::getIdentifier) + .hasToString(PostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE); + } + + @Test + void shouldDeleteCollaborationRequest() { + doThrow(TechnicalException.class).when(postfachRemoteService).sendMessage(any()); + var command = commandService.createCommand(buildCreateCollaborationVorgangCommand(vorgangId, COLLABORATION_LEVEL)); + + waitUntilCommandHasStatus(command.getId(), CommandStatus.ERROR); + + assertThat(loadCollaborationRequest(vorgangId)).isEmpty(); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java index 6f99e9b91bef7f1664e80194b2755173a0c1da37..106c571385c18760a91d1198d34993944a08704d 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java @@ -92,21 +92,20 @@ class CommandRepositoryITCase { @Nested class TestFinishCommand { - @BeforeEach - void init() { - mongoOperations.dropCollection(PersistedCommand.COLLECTION_NAME); - } - @DisplayName("should update status to finished") @ParameterizedTest(name = "with status {0}") @EnumSource(value = CommandStatus.class, names = { "PENDING", "REVOKE_PENDING" }) void shouldUpdateStatusToFinished(CommandStatus commandStatus) { - var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(commandStatus).build()); + var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(commandStatus) + .createdResource(CommandTestFactory.CREATED_RESOURCE).build()); repository.finishCommand(command.getId()); var result = repository.findById(command.getId()); - assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.FINISHED); + assertThat(result).isPresent().get().satisfies(cmd -> { + assertThat(cmd.getStatus()).isEqualTo(CommandStatus.FINISHED); + assertThat(cmd.getCreatedResource()).isEqualTo(CommandTestFactory.CREATED_RESOURCE); + }); } @DisplayName("should update status to finished") @@ -322,7 +321,7 @@ class CommandRepositoryITCase { } @Test - // TODO schreibe ein Testcase für Order, Status und Zeit + // TODO schreibe ein Testcase für Order, Status und Zeit void shouldFindCommand() { var command = repository.save(createCommandBuilder() .status(CommandStatus.FINISHED) @@ -483,7 +482,7 @@ class CommandRepositoryITCase { @Test void shouldReturnParentId() { var commandId = mongoOperations.save( - CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, PARENT_ID)).build()) + CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, PARENT_ID)).build()) .getId(); var parentId = repository.getParentId(commandId); @@ -615,30 +614,39 @@ class CommandRepositoryITCase { void shouldSetCanceled() { var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(CommandStatus.NEW).build()); - repository.setRevokeStatus(command.getId()); + setRevokeStatus(command.getId()); var result = repository.findById(command.getId()); - assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.CANCELED); + assertThat(result).isPresent().get().satisfies(cmd -> { + assertThat(cmd.getStatus()).isEqualTo(CommandStatus.CANCELED); + assertThat(cmd.getCreatedResource()).isBlank(); + }); } @Test void shouldSetRevokePendingWhenPending() { var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).build()); - repository.setRevokeStatus(command.getId()); + setRevokeStatus(command.getId()); var result = repository.findById(command.getId()); - assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKE_PENDING); + assertThat(result).isPresent().get().satisfies(cmd -> { + assertThat(cmd.getStatus()).isEqualTo(CommandStatus.REVOKE_PENDING); + assertThat(cmd.getCreatedResource()).isEqualTo(CommandTestFactory.CREATED_RESOURCE); + }); } @Test void shouldSetRevokePendingWhenFinished() { var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(CommandStatus.FINISHED).build()); - repository.setRevokeStatus(command.getId()); + setRevokeStatus(command.getId()); var result = repository.findById(command.getId()); - assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKE_PENDING); + assertThat(result).isPresent().get().satisfies(cmd -> { + assertThat(cmd.getStatus()).isEqualTo(CommandStatus.REVOKE_PENDING); + assertThat(cmd.getCreatedResource()).isBlank(); + }); } @DisplayName("should not update when") @@ -647,10 +655,17 @@ class CommandRepositoryITCase { void shouldNotUpdate(CommandStatus status) { var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(status).build()); - repository.setRevokeStatus(command.getId()); + setRevokeStatus(command.getId()); var result = repository.findById(command.getId()); - assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(status); + assertThat(result).isPresent().get().satisfies(cmd -> { + assertThat(cmd.getStatus()).isEqualTo(status); + assertThat(cmd.getCreatedResource()).isNull(); + }); + } + + private void setRevokeStatus(String commandId) { + repository.setRevokeStatus(commandId, CommandTestFactory.CREATED_RESOURCE); } } 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 85714d30f81e92ba77ce0c7f575e89dcc04343fa..3f4d68d90efa91280762ec75d49a7692d352a175 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 @@ -214,10 +214,12 @@ class CommandServiceTest { @Nested class TestRevokePendingCommand { - private static final Command REVOKE_PENDING_COMMAND = CommandTestFactory.createBuilder().status(CommandStatus.REVOKE_PENDING).build(); + private static final Command REVOKE_PENDING_COMMAND = CommandTestFactory.createBuilder().status(CommandStatus.REVOKE_PENDING) + .createdResource(CommandTestFactory.CREATED_RESOURCE).build(); @BeforeEach void init() { + when(repository.setRevokeStatus(anyString(), anyString())).thenReturn(REVOKE_PENDING_COMMAND); doReturn(true).when(service).shouldRevoke(any()); doReturn(REVOKE_PENDING_COMMAND).when(service).getById(anyString()); } @@ -233,7 +235,7 @@ class CommandServiceTest { void shouldCallRepository() { setCommandFinished(); - verify(repository).setRevokeStatus(CommandTestFactory.ID); + verify(repository).setRevokeStatus(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE); } @Test diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java index 7df40567d8e858171053fe352454a7e67decde01..e890e4ea2097781bba11e16db414d51370c90562 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java @@ -168,7 +168,7 @@ class GrpcCommandServiceITCase { mongoOperations.dropCollection(Command.COLLECTION_NAME); mongoOperations.dropCollection(VorgangAttachedItem.COLLECTION_NAME); - vorgang = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()); + vorgang = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0).build()); when(readIsPermitted.test(any())).thenReturn(true); parentCommand = createParentCommand(); @@ -259,9 +259,5 @@ class GrpcCommandServiceITCase { return mongoOperations.findById(grpcCommand.getId(), Command.class); } - private void assertCommandIsFinished(GrpcCommand grpcCommand) { - var command = mongoOperations.findById(grpcCommand.getId(), Command.class); - assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED); - } } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M012_UpdateBayernIdPostfachTypeITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M012_UpdateBayernIdPostfachTypeITCase.java new file mode 100644 index 0000000000000000000000000000000000000000..546eb8da689160432261bef9bb4a08f4d7f577d8 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M012_UpdateBayernIdPostfachTypeITCase.java @@ -0,0 +1,137 @@ +/* + * 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.vorgang.common.migration; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import java.util.Map; + +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; + +import de.ozgcloud.common.test.DataITCase; + +@DataITCase +class M012_UpdateBayernIdPostfachTypeITCase { + + private static final String FIELD_HEADER = "header"; + private static final String FIELD_SERVICE_KONTO = "serviceKonto"; + private static final String FIELD_TYPE = "type"; + private static final String FIELD_EINGANG = "eingangs"; + + private final M012_UpdateBayernIdPostfachType migration = new M012_UpdateBayernIdPostfachType(); + + @Autowired + private MigrationDbTestUtils dbTestUtils; + @Autowired + private MongoTemplate template; + + @BeforeEach + void init() { + dbTestUtils.dropVorgangCollection(); + } + + @DisplayName("should migrate when") + @ParameterizedTest(name = "header's serviceKonto type is \"{0}\"") + @ValueSource(strings = { "BayernId", "BayernID" }) + void shouldMitgrateHeader(String type) { + saveVorgangWithHeaderServiceKonto(createServiceKonto(type)); + + migration.doMigration(template); + + assertThat(loadHeaderServiceKonto()).containsEntry(FIELD_TYPE, M012_UpdateBayernIdPostfachType.BAYERN_ID_TYPE_NEW); + } + + @DisplayName("should migrate when") + @ParameterizedTest(name = "eingang's serviceKonto type is \"{0}\"") + @ValueSource(strings = { "BayernId", "BayernID" }) + void shouldMigrateEingang(String type) { + saveVorgangWithEingangServiceKonto(createServiceKonto(type)); + + migration.doMigration(template); + + assertThat(loadEingangServiceKonto()).containsEntry(FIELD_TYPE, M012_UpdateBayernIdPostfachType.BAYERN_ID_TYPE_NEW); + } + + @DisplayName("should skip when") + @ParameterizedTest(name = "header's serviceKonto type is \"{0}\"") + @NullAndEmptySource + @ValueSource(strings = { "another", "OSI" }) + void shouldSkipWhenServiceKontoMissingInHeader(String type) { + saveVorgangWithHeaderServiceKonto(createServiceKonto(type)); + + migration.doMigration(template); + + assertThat(loadHeaderServiceKonto()).containsEntry(FIELD_TYPE, type); + } + + @DisplayName("should skip when") + @ParameterizedTest(name = "eingang's serviceKonto type is \"{0}\"") + @NullAndEmptySource + @ValueSource(strings = { "another", "OSI" }) + void shouldSkipWhenServiceKontoMissingInEingang(String type) { + saveVorgangWithEingangServiceKonto(createServiceKonto(type)); + + migration.doMigration(template); + + assertThat(loadEingangServiceKonto()).containsEntry(FIELD_TYPE, type); + } + + private Document createServiceKonto(String type) { + var serviceKonto = new Document(); + serviceKonto.put(FIELD_TYPE, type); + return serviceKonto; + } + + private void saveVorgangWithHeaderServiceKonto(Document serviceKonto) { + dbTestUtils.saveVorgang(new Document(Map.of(FIELD_HEADER, Map.of(FIELD_SERVICE_KONTO, serviceKonto)))); + } + + private void saveVorgangWithEingangServiceKonto(Document serviceKonto) { + var eingang = new Document(Map.of(FIELD_HEADER, Map.of(FIELD_SERVICE_KONTO, serviceKonto))); + dbTestUtils.saveVorgang(new Document(Map.of(FIELD_EINGANG, List.of(eingang)))); + } + + private Document loadHeaderServiceKonto() { + var vorgangs = dbTestUtils.findVorgang(new Query()); + return getServiceKonto(vorgangs.getFirst()); + } + + private Document loadEingangServiceKonto() { + var vorgangs = dbTestUtils.findVorgang(new Query()); + return getServiceKonto(vorgangs.getFirst().getList(FIELD_EINGANG, Document.class).getFirst()); + } + + private Document getServiceKonto(Document vorgang) { + return vorgang.get(FIELD_HEADER, Document.class).get(FIELD_SERVICE_KONTO, Document.class); + } +} \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java index 359c21709666e3ec0f2c5c8e07d5317ba351dc79..22d8cf0cbc1376ac758021b083685c7ac518efdb 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java @@ -37,13 +37,13 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import de.ozgcloud.command.Command; +import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; import de.ozgcloud.vorgang.command.CommandService; import de.ozgcloud.vorgang.command.CommandTestFactory; import de.ozgcloud.vorgang.status.StatusChangedEvent; import de.ozgcloud.vorgang.vorgang.SetAktenzeichenCompletedEvent; import de.ozgcloud.vorgang.vorgang.Vorgang; -import de.ozgcloud.vorgang.vorgang.VorgangAssignedEvent; import de.ozgcloud.vorgang.vorgang.VorgangDeletedEvent; import de.ozgcloud.vorgang.vorgang.VorgangDeletedEventTestFactory; import de.ozgcloud.vorgang.vorgang.VorgangService; @@ -127,7 +127,7 @@ class SearchEventListenerTest { @Nested class TestOnDeletedVorgang { - private VorgangDeletedEvent event = VorgangDeletedEventTestFactory.create(); + private final VorgangDeletedEvent event = VorgangDeletedEventTestFactory.create(); @Test void shouldCallService() { diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/GrpcRegistrationResponseTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/GrpcRegistrationResponseTestFactory.java index 7bf1b282a7708c1e16fab1f6f6a71873b5f245bf..831f430ef392061414267c8478689cbe90f1a712 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/GrpcRegistrationResponseTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/GrpcRegistrationResponseTestFactory.java @@ -1,6 +1,6 @@ package de.ozgcloud.vorgang.registry; -import de.ozgcloud.zufi.grpc.registration.GrpcVorgangManagerRegistrationResponse; +import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcVorgangManagerRegistrationResponse; public class GrpcRegistrationResponseTestFactory { public static GrpcVorgangManagerRegistrationResponse create() { diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/RegistryServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/RegistryServiceTest.java index 7f5f58b5e47dd5ecb7cf48219f092d42fc1134ad..aaf11c29d09a7e063e209f2b97b070bd7880a303 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/RegistryServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/RegistryServiceTest.java @@ -1,25 +1,24 @@ package de.ozgcloud.vorgang.registry; -import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.Collections; import java.util.List; -import java.util.Optional; -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.Mockito; import org.mockito.Spy; -import org.springframework.test.util.ReflectionTestUtils; + +import de.ozgcloud.vorgang.VorgangManagerProperties; class RegistryServiceTest { + private static final String ORGANISATION_EINHEITEN_ID = "123456"; private static final List<String> ORGANISATION_EINHEITEN_IDS = List.of(ORGANISATION_EINHEITEN_ID); - private static final Optional<String> VORGANG_MANAGER_ADDRESS = Optional.of("address"); + private static final String VORGANG_MANAGER_ADDRESS = "vorgang-manager-address"; @Spy @InjectMocks @@ -27,34 +26,24 @@ class RegistryServiceTest { @Mock private ZufiRemoteService zufiRemoteService; + @Mock + private VorgangManagerProperties vorgangManagerProperties; - @DisplayName("Test registering the VorgangManager") - @Nested - class TestRegistryVorgangManager { - @BeforeEach - void initVorgangManagerAddress() { - ReflectionTestUtils.setField(registryService, "vorgangManagerAddress", VORGANG_MANAGER_ADDRESS); - } - - @Test - void shouldCallZuFiRemoteService() { - registryService.registerVorgangManager(ORGANISATION_EINHEITEN_IDS); - - verify(zufiRemoteService).registerVorgangManager(anyList(), any()); - } + @Test + void shouldCallZuFiRemoteService() { + when(vorgangManagerProperties.getAddress()).thenReturn(VORGANG_MANAGER_ADDRESS); - @Test - void shouldNotCallZuFiRemoteServiceOnEmptyOrganisationsEinheitenIds() { - registryService.registerVorgangManager(Collections.emptyList()); + registryService.registerVorgangManager(ORGANISATION_EINHEITEN_IDS); - verify(zufiRemoteService, never()).registerVorgangManager(anyList(), any()); - } + verify(zufiRemoteService).registerVorgangManager(ORGANISATION_EINHEITEN_IDS, VORGANG_MANAGER_ADDRESS); + } - @Test - void shouldNotCallServiceStub() { - registryService.registerAddress(ORGANISATION_EINHEITEN_IDS, Optional.empty()); + @DisplayName("should not call zufi remote service when organisationseinheitenIds is empty") + @Test + void shouldNotCallRegisterAddress() { + registryService.registerVorgangManager(Collections.emptyList()); - verify(zufiRemoteService, never()).registerVorgangManager(any(), any()); - } + Mockito.verifyNoInteractions(zufiRemoteService); } + } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/ZufiRemoteServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/ZufiRemoteServiceTest.java index 384ca37218780385c58092d40024998380a4e4c2..a09030f20ec00b66f0edb7d1823874c5a0f41101 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/ZufiRemoteServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/registry/ZufiRemoteServiceTest.java @@ -14,8 +14,8 @@ import org.mockito.Mock; import org.mockito.Spy; import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor; -import de.ozgcloud.zufi.grpc.registration.GrpcVorgangManagerRegistrationRequest; -import de.ozgcloud.zufi.grpc.registration.VorgangManagerRegistrationServiceGrpc.VorgangManagerRegistrationServiceBlockingStub; +import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcVorgangManagerRegistrationRequest; +import de.ozgcloud.zufi.grpc.organisationseinheit.VorgangManagerRegistrationServiceGrpc.VorgangManagerRegistrationServiceBlockingStub; class ZufiRemoteServiceTest { private static final String ORGANISATIONS_EINHEITEN_ID = "123456"; 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 fb8085fe48a868c0c40ff629bf19ae4ec4dcea32..c6a8daf26e2d1696cad785c5cb1c66cf1d73f33a 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 @@ -47,6 +47,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.access.AccessDeniedException; import de.ozgcloud.command.Command; +import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted; import de.ozgcloud.vorgang.command.CommandTestFactory; diff --git a/vorgang-manager-server/src/test/resources/application-itcase.yml b/vorgang-manager-server/src/test/resources/application-itcase.yml index 96b714f6f813bab2e43f054df6147c89749a6dbf..2ab5f3470287edaf719a5db27b0cba4480042d0b 100644 --- a/vorgang-manager-server/src/test/resources/application-itcase.yml +++ b/vorgang-manager-server/src/test/resources/application-itcase.yml @@ -11,7 +11,19 @@ grpc: port: -1 ozgcloud: + administration: + sync: + enabled: false + application: + address: localhost aktenzeichen: de.ozgcloud.vorgang.vorgang.AktenzeichenProviderEA + notification: + scheduling: + enabled: false mongock: enabled: false +spring: + cloud: + config: + enabled: false diff --git a/vorgang-manager-utils/pom.xml b/vorgang-manager-utils/pom.xml index ce3991a3ca9e937f0065db46d5ac9a5fe8367ba8..0d232ba161371a55bbf231ffac22faaab225a57d 100644 --- a/vorgang-manager-utils/pom.xml +++ b/vorgang-manager-utils/pom.xml @@ -37,7 +37,7 @@ <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-utils</artifactId> <name>OZG-Cloud Vorgang Manager Utils</name> - <version>2.14.1</version> + <version>2.15.0-SNAPSHOT</version> <properties> <maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>