diff --git a/Jenkinsfile b/Jenkinsfile index 1b8dc8b1a49a9cae77b1656a4f596d1ade211c09..f0168cfb81263f8e62bd607d9da3b931b0f98a6b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -34,18 +34,19 @@ pipeline { def fsAdapterVersion = getParentPomVersion('formsolutions-adapter/pom.xml') def formCycleAdapterVersion = getParentPomVersion('formcycle-adapter/pom.xml') def xtaAdapterVersion = getParentPomVersion('xta-adapter/pom.xml') + def enterpriseAdapterVersion = getParentPomVersion('enterprise-adapter/pom.xml') if(env.BRANCH_NAME == 'release'){ - if ( !isReleaseVersion([rootVersion, plutoVersion, commonVersion, routerVersion, ifAdapterVersion, fsAdapterVersion, formCycleAdapterVersion, xtaAdapterVersion])) { + if ( !isReleaseVersion([rootVersion, plutoVersion, commonVersion, routerVersion, ifAdapterVersion, fsAdapterVersion, formCycleAdapterVersion, xtaAdapterVersion, enterpriseAdapterVersion])) { error("Keine Release Version für Branch ${env.BRANCH_NAME}.") } } else { - if ( !isSnapshotVersion([rootVersion, commonVersion, routerVersion, ifAdapterVersion, fsAdapterVersion, formCycleAdapterVersion, xtaAdapterVersion])) { + if ( !isSnapshotVersion([rootVersion, commonVersion, routerVersion, ifAdapterVersion, fsAdapterVersion, formCycleAdapterVersion, xtaAdapterVersion, enterpriseAdapterVersion])) { error("Keine Snapshot Version für Branch ${env.BRANCH_NAME}.") } } - if ( !isSameVersion([commonVersion, routerVersion, ifAdapterVersion, fsAdapterVersion, formCycleAdapterVersion, xtaAdapterVersion], rootVersion)) { + if ( !isSameVersion([commonVersion, routerVersion, ifAdapterVersion, fsAdapterVersion, formCycleAdapterVersion, xtaAdapterVersion, enterpriseAdapterVersion], rootVersion)) { error("Versionen sind nicht identisch") } } @@ -107,18 +108,21 @@ pipeline { tagAndPushDockerImage('formsolutions-adapter', IMAGE_TAG) tagAndPushDockerImage('formcycle-adapter', IMAGE_TAG) tagAndPushDockerImage('xta-adapter', IMAGE_TAG) + tagAndPushDockerImage('enterprise-adapter', IMAGE_TAG) if (env.BRANCH_NAME == 'master') { tagAndPushDockerImage('intelliform-adapter', 'snapshot-latest') tagAndPushDockerImage('formsolutions-adapter', 'snapshot-latest') tagAndPushDockerImage('formcycle-adapter', 'snapshot-latest') tagAndPushDockerImage('xta-adapter', 'snapshot-latest') + tagAndPushDockerImage('enterprise-adapter', 'snapshot-latest') } else if (env.BRANCH_NAME == 'release') { tagAndPushDockerImage('intelliform-adapter', 'latest') tagAndPushDockerImage('formsolutions-adapter', 'latest') tagAndPushDockerImage('formcycle-adapter', 'latest') tagAndPushDockerImage('xta-adapter', 'latest') + tagAndPushDockerImage('enterprise-adapter', 'latest') } } } @@ -285,12 +289,14 @@ Void setNewDevAdapterVersion() { setNewFsAdapterVersion('dev') setNewFormcycleAdapterVersion('dev') setNewXtaAdapterVersion('dev') + setNewEnterpriseAdapterVersion('dev') } Void setNewTestAdapterVersion() { setNewAfmAdapterVersion('test') setNewFsAdapterVersion('test') setNewFormcycleAdapterVersion('test') + setNewEnterpriseAdapterVersion('test') } Void setNewAfmAdapterVersion(String environment) { @@ -341,6 +347,18 @@ Void setNewXtaAdapterVersion(String environment) { } } +Void setNewEnterpriseAdapterVersion(String environment) { + dir("gitops") { + def envFile = "${environment}/application/values/enterprise-adapter-values.yaml" + def envVersions = readYaml file: envFile + + envVersions.enterprise_adapter.image.tag = IMAGE_TAG + envVersions.enterprise_adapter.helm.version = HELM_CHART_VERSION + + writeYaml file: envFile, data: envVersions, overwrite: true + } +} + Void pushNewDevVersion() { pushNewGitopsVersion('dev') } diff --git a/common/src/main/java/de/ozgcloud/eingang/Application.java b/common/src/main/java/de/ozgcloud/eingang/Application.java index 9ba0845dd5e75092e6a599bfce3a771e0eb7b2ce..164da65a2a41320484d988faa3edd42bfd75dc05 100644 --- a/common/src/main/java/de/ozgcloud/eingang/Application.java +++ b/common/src/main/java/de/ozgcloud/eingang/Application.java @@ -23,6 +23,8 @@ */ package de.ozgcloud.eingang; +import java.util.TimeZone; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @@ -32,6 +34,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; public class Application { public static void main(String[] args) { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); SpringApplication.run(Application.class, args); } } diff --git a/common/src/main/java/de/ozgcloud/eingang/LogRunner.java b/common/src/main/java/de/ozgcloud/eingang/LogRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..642b7c4cf4dfa9cc9ab89dac490e3ad0a87ebdec --- /dev/null +++ b/common/src/main/java/de/ozgcloud/eingang/LogRunner.java @@ -0,0 +1,21 @@ +package de.ozgcloud.eingang; + +import java.nio.charset.Charset; + +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import lombok.extern.log4j.Log4j2; + +@Log4j2 +@Component +class LogRunner implements ApplicationListener<ContextRefreshedEvent> { + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + LOG.info("Standard Charset: " + Charset.defaultCharset()); + + } + +} diff --git a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormHeader.java b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormHeader.java index 59c9ff40de61d79844db7c2abb904439e52cacc1..24b0e72766bf67f7702ea1974e7b2a2f69f1f22d 100644 --- a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormHeader.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormHeader.java @@ -37,6 +37,7 @@ import lombok.ToString; public class FormHeader { private String requestId; + private String vorgangNummer; @Builder.Default private ZonedDateTime createdAt = ZonedDateTime.now(); private String formId; diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/VorgangNummerSupplier.java b/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java similarity index 91% rename from formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/VorgangNummerSupplier.java rename to common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java index b7f953e975a88d6876e39f1a5b23b65ccd5af234..5d1468262c469c9595dabe39e5a7159a3f70a2de 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/VorgangNummerSupplier.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.formcycle; +package de.ozgcloud.eingang.common.vorgang; import java.time.Instant; import java.time.LocalDate; @@ -6,7 +6,7 @@ import java.time.LocalDate; import org.springframework.stereotype.Component; @Component -class VorgangNummerSupplier { +public class VorgangNummerSupplier { static final String BASE30_ALPHABET = "23456789ABCDEFGHJKMNPQRSTVWXYZ"; static final int SUFFIX_LENGTH = 6; diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/AntragstellerTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/AntragstellerTestFactory.java index ed3ed7816b082b0139413eceee38a8196b63e968..ce9d59c38cf6f5ee88d9c8fc40c150001bebbc0a 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/AntragstellerTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/AntragstellerTestFactory.java @@ -37,9 +37,9 @@ public class AntragstellerTestFactory { public static final String SUB_VERBOTENE_VEREINIGUNG_KEY = "MitgliedschaftInVerboternerVereinigung"; public static final String SUB_VERBOTENE_VEREINIGUNG_VALUE = "true"; - public static final String VORNAME = "Helge"; - public static final String NACHNAME = "Schneider"; - public static final String GEBURTSNAME = "Schneider"; + public static final String VORNAME = "Theo"; + public static final String NACHNAME = "Test"; + public static final String GEBURTSNAME = "Toast"; public static final String GEBURTSDATUM = "30.8.1955"; public static final String GEBURTSORT = "Mülheim an der Ruhr"; public static final String EMAIL = "schneider@helgeschneider.local"; diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/DeleteOnCloseInputStreamTest.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/DeleteOnCloseInputStreamTest.java index 62d595e591d0d0622488016f14d7304ecd5c7df9..b7b7515b27ad056e865630a26e923d3f863c8f59 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/DeleteOnCloseInputStreamTest.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/DeleteOnCloseInputStreamTest.java @@ -3,17 +3,26 @@ package de.ozgcloud.eingang.common.formdata; import static org.assertj.core.api.Assertions.*; import java.io.File; +import java.io.IOException; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; import de.itvsh.kop.common.errorhandling.TechnicalException; class DeleteOnCloseInputStreamTest { - @InjectMocks private DeleteOnCloseInputStream stream; + @Test + void shouldDeleteFileOnClose() throws IOException { + File file = File.createTempFile("Test", "test"); + stream = new DeleteOnCloseInputStream(file); + + stream.close(); + + assertThat(file).doesNotExist(); + } + @Test void shouldThrowException() { var notExists = new File("notExists"); diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormHeaderTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormHeaderTestFactory.java index 676210d6754ed4aab7dbc4891d7190277313b1ab..cf79e40328ceddd314d9841b7e95ceb0b0731a1c 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormHeaderTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormHeaderTestFactory.java @@ -35,6 +35,7 @@ public class FormHeaderTestFactory { public static final String FORM_NAME = "formName"; public static final String FORM_ID = "formId"; public static final String REQUEST_ID = "requestId"; + public static final String VORGANG_NUMMER = "ABCD-1234"; public static final ZonedDateTime CREATED_AT = ZonedDateTime.now(); public static FormHeader create() { @@ -44,6 +45,7 @@ public class FormHeaderTestFactory { public static FormHeader.FormHeaderBuilder createBuilder() { return FormHeader.builder() .requestId(REQUEST_ID) + .vorgangNummer(VORGANG_NUMMER) .createdAt(CREATED_AT) .formId(FORM_ID) .formName(FORM_NAME) diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/VorgangNummerSupplierTest.java b/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java similarity index 97% rename from formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/VorgangNummerSupplierTest.java rename to common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java index 568e82353a6de66daf3195c3cbf429ffbd9cb567..d474cd190edfb39454d96c98a67d2d1a0886690d 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/VorgangNummerSupplierTest.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.formcycle; +package de.ozgcloud.eingang.common.vorgang; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; diff --git a/common/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/common/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 0000000000000000000000000000000000000000..79b126e6cdb86bec1f4f08c205de8961bde1934a --- /dev/null +++ b/common/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +org.mockito.junit.jupiter.MockitoExtension \ No newline at end of file diff --git a/common/src/test/resources/junit-platform.properties b/common/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000000000000000000000000000000000..1cebb76d5a58ac034b2627d12411d82d1e85821e --- /dev/null +++ b/common/src/test/resources/junit-platform.properties @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled = true \ No newline at end of file diff --git a/enterprise-adapter/pom.xml b/enterprise-adapter/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..e02b3e6c8b386daea23e98c1d4f614c370196861 --- /dev/null +++ b/enterprise-adapter/pom.xml @@ -0,0 +1,105 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>de.itvsh.kop.eingangsadapter</groupId> + <artifactId>parent</artifactId> + <version>1.13.0-SNAPSHOT</version> + </parent> + <artifactId>enterprise-adapter</artifactId> + <name>EM - Enterprise Interface Adapter</name> + + <properties> + <spring-boot.build-image.imageName> + docker.ozg-sh.de/enterprise-adapter:build-latest + </spring-boot.build-image.imageName> + </properties> + + <dependencies> + <!--ozg-Cloud--> + <dependency> + <groupId>de.itvsh.kop.eingangsadapter</groupId> + <artifactId>common</artifactId> + </dependency> + <dependency> + <groupId>de.itvsh.kop.eingangsadapter</groupId> + <artifactId>semantik-adapter</artifactId> + </dependency> + + + <!--spring--> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + + + + <!--dev tools--> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct</artifactId> + </dependency> + + <!--test --> + <dependency> + <groupId>de.itvsh.kop.eingangsadapter</groupId> + <artifactId>common</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>ci-build</id> + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <id>build-image</id> + <phase> + install</phase> + <goals> + <goal>build-image</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> \ No newline at end of file diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryController.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryController.java new file mode 100644 index 0000000000000000000000000000000000000000..20b6563bd1a8f6dd48a55340a4f803b05b9e542d --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryController.java @@ -0,0 +1,64 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.io.IOException; +import java.time.ZonedDateTime; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; +import de.ozgcloud.eingang.enterprise.entry.EntryResponse.ResponseVorgang; +import de.ozgcloud.eingang.semantik.SemantikAdapter; + +@Controller +@ResponseBody +@RequestMapping("antrag") +public class EntryController { + + private static final String STARTING_STATUS = "NEU"; + + @Autowired + private EntryDataMapper mapper; + + @Autowired + private SemantikAdapter semantikAdapter; + @Autowired + private VorgangNummerSupplier vorgangNummerSupplier; + + @ResponseStatus(HttpStatus.ACCEPTED) + @PostMapping(consumes = "multipart/form-data", produces = MediaType.APPLICATION_JSON_VALUE) + public EntryResponse receiveAntrag(@RequestPart Resource formData) throws IOException { + var mapped = mapper.mapEntryData(formData.getInputStream()); + mapped = addVorgangNummer(mapped); + + var vorgangId = semantikAdapter.processFormData(mapped); + + return buildResponse(mapped, vorgangId); + } + + private FormData addVorgangNummer(FormData formData) { + var header = formData.getHeader().toBuilder().vorgangNummer(vorgangNummerSupplier.get()).build(); + return formData.toBuilder().header(header).build(); + } + + EntryResponse buildResponse(FormData formData, String vorgangId) { + return EntryResponse.builder() + .transactionId(formData.getHeader().getRequestId()) + .vorgang(ResponseVorgang.builder() + .vorgangId(vorgangId) + .vorgangNummer(formData.getHeader().getVorgangNummer()) + .status(STARTING_STATUS) + .statusSince(ZonedDateTime.now().withNano(0)) + .build()) + .build(); + } +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryData.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryData.java new file mode 100644 index 0000000000000000000000000000000000000000..5fedcbcae2f1aa5fc028dace4634df10794564c6 --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryData.java @@ -0,0 +1,38 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Builder; +import lombok.Getter; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Getter +@Jacksonized +public class EntryData { + + private ControlData control; + private List<EntryFormDataItem> formData; + + @Builder + @Getter + @Jacksonized + public static class ControlData { + private String transactionId; + private String zustaendigeStelle; + private String[] leikaIds; + private ResultEndpoint resultEndpoint; + private String formId; + @JsonProperty("name") + private String formName; + + @Builder + @Getter + @Jacksonized + public static class ResultEndpoint { + private String address; + } + } +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryDataMapper.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryDataMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..1c2c5340499d72c4101fc52bbbd40ddec37c3c2d --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryDataMapper.java @@ -0,0 +1,34 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.io.IOException; +import java.io.InputStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.ozgcloud.eingang.common.formdata.FormData; + +@Component +class EntryDataMapper { + + @Autowired + private ObjectMapper objectMapper; + @Autowired + private FormDataMapper formDataMapper; + + public FormData mapEntryData(InputStream request) { + return formDataMapper.mapEntryData(readRequest(request)); + } + + EntryData readRequest(InputStream request) { + try { + return objectMapper.readValue(request, EntryData.class); + } catch (IOException e) { + throw new ReadingRequestException(e); + } + + } + +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataField.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataField.java new file mode 100644 index 0000000000000000000000000000000000000000..7a7623d46aa01306b28979c9791b17c4677e1653 --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataField.java @@ -0,0 +1,48 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.time.LocalDate; +import java.util.Objects; + +import org.apache.commons.lang3.StringUtils; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Getter +@Jacksonized +@ToString(onlyExplicitlyIncluded = true) +public class EntryFormDataField implements EntryFormDataItem { + + private String name; + @ToString.Include + private String label; + + private String stringValue; + private Boolean booleanValue; + private Number numberValue; + private LocalDate dateValue; + + @Override + public boolean isFormField() { + return true; + } + + public Object getValue() { + if (StringUtils.isNotBlank(stringValue)) { + return stringValue; + } + if (Objects.nonNull(booleanValue)) { + return booleanValue; + } + if (Objects.nonNull(numberValue)) { + return numberValue; + } + if (Objects.nonNull(dateValue)) { + return dateValue; + } + return null; + } +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataItem.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataItem.java new file mode 100644 index 0000000000000000000000000000000000000000..c2c318fd80dfa8319fa565c56b7a5ee8a0343bf9 --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataItem.java @@ -0,0 +1,21 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.DEDUCTION) +@JsonSubTypes({ @Type(EntryFormDataField.class), @Type(EntryFormDataSubForm.class) }) +public interface EntryFormDataItem { + String getName(); + String getLabel(); + + default boolean isSubForm() { + return false; + } + + default boolean isFormField() { + return false; + } +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataSubForm.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataSubForm.java new file mode 100644 index 0000000000000000000000000000000000000000..402f2bc1bdbc8e5af6ae3fc1b4cfa9836c4e5725 --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataSubForm.java @@ -0,0 +1,28 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.util.List; + +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Getter +@Jacksonized +@ToString(onlyExplicitlyIncluded = true) +public class EntryFormDataSubForm implements EntryFormDataItem { + + private String name; + @ToString.Include + private String label; + + @Singular + private List<EntryFormDataItem> formItems; + + @Override + public boolean isSubForm() { + return true; + } +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryResponse.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..840df7a6d5b14b01f38bf6ef67d5a5b9e96b00bf --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/EntryResponse.java @@ -0,0 +1,23 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.time.ZonedDateTime; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +class EntryResponse { + + private String transactionId; + private ResponseVorgang vorgang; + + @Builder + @Getter + static class ResponseVorgang { + private String vorgangId; + private String vorgangNummer; + private String status; + private ZonedDateTime statusSince; + } +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/FormDataMapper.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/FormDataMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..287a9e4c71a00c916f70b4c180860111e55047f5 --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/FormDataMapper.java @@ -0,0 +1,60 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.Pair; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; + +@Mapper +public interface FormDataMapper { + + public static final String VALUE_KEY = "value"; + public static final String LABEL_KEY = "label"; + + @Mapping(target = "antragsteller", ignore = true) + @Mapping(target = "attachment", ignore = true) + @Mapping(target = "attachments", ignore = true) + @Mapping(target = "numberOfAttachments", ignore = true) + @Mapping(target = "representation", ignore = true) + @Mapping(target = "representations", ignore = true) + @Mapping(target = "numberOfRepresentations", ignore = true) + + @Mapping(target = "id", ignore = true) + @Mapping(target = "header", source = "control") + + @Mapping(target = "zustaendigeStelle", source = "control.zustaendigeStelle") + FormData mapEntryData(EntryData entryData); + + @Mapping(target = "createdAt", ignore = true) + @Mapping(target = "formEngineName", constant = "EnterpriseSoftware") + @Mapping(target = "requestId", source = "transactionId") + @Mapping(target = "sender", ignore = true) // TODO fill from authentication + @Mapping(target = "serviceKonto", ignore = true) + FormHeader mapHeader(EntryData.ControlData controlData); + + default ZustaendigeStelle fromId(String organisationsEinheitenId) { + return ZustaendigeStelle.builder().organisationseinheitenId(organisationsEinheitenId).build(); + } + + default Map<String, Object> mapFormItems(List<EntryFormDataItem> items) { + return items.stream().map(item -> Pair.of(item.getName(), + item.isFormField() ? mapFormField((EntryFormDataField) item) : mapSubForm((EntryFormDataSubForm) item))) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + } + + default Map<String, Object> mapFormField(EntryFormDataField field) { + return Map.of(LABEL_KEY, field.getLabel(), VALUE_KEY, field.getValue()); + } + + default Map<String, Object> mapSubForm(EntryFormDataSubForm subForm) { + return Map.of(LABEL_KEY, subForm.getLabel(), VALUE_KEY, mapFormItems(subForm.getFormItems())); + } + +} diff --git a/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/ReadingRequestException.java b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/ReadingRequestException.java new file mode 100644 index 0000000000000000000000000000000000000000..d1d4e3f9c4467aac99cf52838c164f3f1e26f49c --- /dev/null +++ b/enterprise-adapter/src/main/java/de/ozgcloud/eingang/enterprise/entry/ReadingRequestException.java @@ -0,0 +1,14 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import de.itvsh.kop.common.errorhandling.TechnicalException; + +public class ReadingRequestException extends TechnicalException { + + private static final String MESSAGE = "Error reading Request."; + + public ReadingRequestException(Exception cause) { + super(MESSAGE, cause); + + } + +} diff --git a/enterprise-adapter/src/main/resources/application-local.yml b/enterprise-adapter/src/main/resources/application-local.yml new file mode 100644 index 0000000000000000000000000000000000000000..d9a71da93f7f52d781c7645744fb20030a390ce4 --- /dev/null +++ b/enterprise-adapter/src/main/resources/application-local.yml @@ -0,0 +1,24 @@ +logging: + config: classpath:log4j2-local.xml + +server: + port: 9294 + error: + include-stacktrace: always + +management: + server: + port: 0 + endpoints: + enabled-by-default: false + +kop: + adapter: + targetPlutoName: local + fallbackStrategy: DENY + +grpc: + client: + pluto-local: + address: static://127.0.0.1:9090 + negotiationType: PLAINTEXT \ No newline at end of file diff --git a/enterprise-adapter/src/main/resources/application.yml b/enterprise-adapter/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..6ebdfd473fe13324482e8be56c40248f82d2ae7e --- /dev/null +++ b/enterprise-adapter/src/main/resources/application.yml @@ -0,0 +1,44 @@ +logging: + level: + ROOT: WARN + '[de.itvsh]': INFO + +spring: + servlet: + multipart: + max-file-size: 124MB + max-request-size: 256MB + file-size-threshold: 10MB + +server: + http2: + enabled: true + error: + include-stacktrace: never + +management: + server: + port: 8081 + health: + livenessState: + enabled: true + readinessState: + enabled: true + endpoint: + health: + group: + exploratory: + include: livenessState,readinessState,ping + show-details: always + probes: + enabled: true + prometheus: + enabled: true + endpoints: + web: + exposure: + include: health,prometheus + +kop: + adapter: + routingStrategy: SINGLE \ No newline at end of file diff --git a/enterprise-adapter/src/main/resources/log4j2-local.xml b/enterprise-adapter/src/main/resources/log4j2-local.xml new file mode 100644 index 0000000000000000000000000000000000000000..5d7001e1f9186d197a2d301d3910c9d73ed05d15 --- /dev/null +++ b/enterprise-adapter/src/main/resources/log4j2-local.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <Appenders> + <Console name="CONSOLE" target="SYSTEM_OUT"> + <PatternLayout pattern="[%-5level] %c{1.} %msg%n"/> + </Console> + </Appenders> + + <Loggers> + <Root level="WARN"> + <appender-ref ref="CONSOLE" /> + </Root> + </Loggers> +</configuration> \ No newline at end of file diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/ControlDataTestFactory.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/ControlDataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..9f26f3e2c8262ba57cbc3eb69385636f737c5e3a --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/ControlDataTestFactory.java @@ -0,0 +1,30 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import de.ozgcloud.eingang.enterprise.entry.EntryData.ControlData; +import de.ozgcloud.eingang.enterprise.entry.EntryData.ControlData.ResultEndpoint; + +public class ControlDataTestFactory { + + public static final String TRANSACTION_ID = "4e7a6ae7-4d0f-444d-8971-7cfc051c9924"; + public static final String ZUSTAENDIGE_STELLE = "248240886"; + public static final String[] LEIKA_IDS = new String[] { "99108011000000", "99108011153000" }; + + public static final String RESULT_ENDPOIN_ADDRESS = "https://idalabs.de/backend/api"; + + public static final String FORM_ID = "KFAS_LIVE_KI_10_Haltverbot_befristet"; + public static final String NAME = "Anmeldung zur Einrichtung einer zeitlich befristeten Haltverbotszone gem. § 45 Abs. 1 Straßenverkehrsordnung (StVO)"; + + public static ControlData create() { + return createBuilder().build(); + } + + public static ControlData.ControlDataBuilder createBuilder() { + return ControlData.builder() + .transactionId(TRANSACTION_ID) + .zustaendigeStelle(ZUSTAENDIGE_STELLE) + .leikaIds(LEIKA_IDS) + .resultEndpoint(ResultEndpoint.builder().address(RESULT_ENDPOIN_ADDRESS).build()) + .formId(FORM_ID) + .formName(NAME); + } +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java new file mode 100644 index 0000000000000000000000000000000000000000..17bd6cd4c8a19bf43d320a8e0e2afc96fd71f31c --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java @@ -0,0 +1,46 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import de.itvsh.kop.common.test.ITCase; +import de.itvsh.kop.common.test.TestUtils; +import de.ozgcloud.eingang.router.VorgangService; +import lombok.SneakyThrows; + +@ITCase +@AutoConfigureMockMvc +@ActiveProfiles({ "itcase", "local" }) +class EnterpriseEntryITCase { + + @MockBean + private VorgangService vorgangService; + + @Autowired + private MockMvc mockMvc; + + @Test + void shouldCallVorgangService() { + doPostRequest(); + + verify(vorgangService).createVorgang(any()); + } + + @SneakyThrows + private ResultActions doPostRequest() { + return mockMvc.perform(multipart("/antrag") + .file(new MockMultipartFile("formData", TestUtils.loadTextFile("request/simple.json").getBytes()))) + .andExpect(status().is2xxSuccessful()); + } +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryControllerTest.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7086aee89422861a125508b3f5a619f87e8d00d5 --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryControllerTest.java @@ -0,0 +1,138 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.core.io.Resource; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import de.itvsh.kop.common.test.TestUtils; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; +import de.ozgcloud.eingang.semantik.SemantikAdapter; +import lombok.SneakyThrows; + +class EntryControllerTest { + + @Spy + @InjectMocks + private EntryController controller; + + @Mock + private EntryDataMapper mapper; + @Mock + private SemantikAdapter semantikAdapter; + @Mock + private VorgangNummerSupplier vorgangNummerSupplier; + + private MockMvc mockMvc; + + @BeforeEach + void init() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Nested + class ReceiveAntrag { + + private final FormHeader header = FormHeaderTestFactory.createBuilder().vorgangNummer(null).build(); + private final FormData formData = FormDataTestFactory.createBuilder().header(header).build(); + + @Captor + private ArgumentCaptor<InputStream> streamCaptor; + @Captor + private ArgumentCaptor<FormData> formDataCaptor; + + private final EntryResponse response = EntryResponseTestFactory.create(); + + @BeforeEach + void init() { + when(mapper.mapEntryData(any())).thenReturn(formData); + doReturn(response).when(controller).buildResponse(any(), any()); + when(vorgangNummerSupplier.get()).thenReturn(FormHeaderTestFactory.VORGANG_NUMMER); + } + + @Test + @SneakyThrows + void shouldReturnAccepted() { + doPostRequest().andExpect(status().isAccepted()); + } + + @Test + @SneakyThrows + void shouldCallMapper() { + var request = TestUtils.loadTextFile("request/simple.json"); + + doPostRequest(); + + verify(mapper).mapEntryData(streamCaptor.capture()); + var inputBytes = IOUtils.readFully(streamCaptor.getValue(), request.getBytes().length); + assertThat(inputBytes).hasSameSizeAs(request.getBytes()).isEqualTo(request.getBytes()); + } + + @Test + void shouldCallSemantikAdapter() { + doPostRequest(); + + verify(semantikAdapter).processFormData(notNull()); + } + + @Test + void shouldSetVorgangNummer() { + doPostRequest(); + + verify(semantikAdapter).processFormData(formDataCaptor.capture()); + assertThat(formDataCaptor.getValue().getHeader().getVorgangNummer()).isEqualTo(FormHeaderTestFactory.VORGANG_NUMMER); + } + + @Test + @SneakyThrows + void shouldReturnResponse() { + var response = controller.receiveAntrag(mock(Resource.class)); + + assertThat(response).isSameAs(this.response); + } + + @SneakyThrows + private ResultActions doPostRequest() { + return mockMvc.perform(multipart("/antrag") + .file(new MockMultipartFile("formData", TestUtils.loadTextFile("request/simple.json").getBytes()))) + .andExpect(status().is2xxSuccessful()); + } + } + + @Nested + class BuildResponse { + + @Test + @SneakyThrows + void shouldCreateResponse() { + var response = controller.buildResponse(FormDataTestFactory.create(), ResponseVorgangTestFactory.VORGANG_ID); + + assertThat(response).usingRecursiveComparison() + .ignoringFields("vorgang.statusSince") + .isEqualTo(EntryResponseTestFactory.create()); + } + } + +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryDataMapperTest.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryDataMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..120c99e5cd5d5c5edc9efd7b911203ae81877c18 --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryDataMapperTest.java @@ -0,0 +1,82 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.io.InputStream; + +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 com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import de.itvsh.kop.common.test.TestUtils; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import lombok.SneakyThrows; + +class EntryDataMapperTest { + + @Spy + @InjectMocks + private EntryDataMapper mapper; + @Mock + private FormDataMapper formDataMapper; + + @Spy + private ObjectMapper objectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true) + .registerModule(new JavaTimeModule()); + + @Nested + class TestMappingEntryData { + + private InputStream jsonInput = TestUtils.loadFile("request/simple.json"); + + @Nested + class TestReadRequest { + @Test + void shouldReadJson() { + var read = mapper.readRequest(jsonInput); + + assertThat(read).usingRecursiveComparison().isEqualTo(EntryDataTestFactory.create()); + } + } + + @Test + void shouldReadRequest() { + mapper.mapEntryData(jsonInput); + + verify(mapper).readRequest(jsonInput); + } + + @Test + @SneakyThrows + void shouldCallFormDataMapper() { + var entryData = EntryDataTestFactory.create(); + doReturn(entryData).when(objectMapper).readValue(any(InputStream.class), Mockito.<Class<EntryData>>any()); + + mapper.mapEntryData(jsonInput); + + verify(formDataMapper).mapEntryData(entryData); + } + + @Test + void shouldReturnMappedResult() { + FormData formData = FormDataTestFactory.create(); + when(formDataMapper.mapEntryData(any())).thenReturn(formData); + + var result = mapper.mapEntryData(jsonInput); + + assertThat(result).isSameAs(formData); + } + } + +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryDataTestFactory.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryDataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..855fa290a29a92945a32767c9f90452b907a9e4c --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryDataTestFactory.java @@ -0,0 +1,14 @@ +package de.ozgcloud.eingang.enterprise.entry; + +public class EntryDataTestFactory { + + public static EntryData create() { + return createBuilder().build(); + } + + public static EntryData.EntryDataBuilder createBuilder() { + return EntryData.builder() + .control(ControlDataTestFactory.create()) + .formData(EntryFormDataTestFactory.create()); + } +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataTestFactory.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..26ca19bb78272b00118c6ad28d70a86556165df3 --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryFormDataTestFactory.java @@ -0,0 +1,70 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import static de.ozgcloud.eingang.enterprise.entry.FormDataMapper.*; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +public class EntryFormDataTestFactory { + + public static final String FORM_FIELD_NAME = "field_name"; + public static final String FORM_FIELD_VALUE = "field_string_value"; + public static final String FORM_FIELD_LABEL = "field_label"; + + public static final String SUB_FORM_NAME = "antragsteller"; + public static final String SUB_FORM_LABEL = "Antragstellende Person"; + + public static final String SUB_FORM_STRING_FIELD_NAME = "lastname"; + public static final String SUB_FORM_STRING_FIELD_LABEL = "Nachname"; + public static final String SUB_FORM_STRING_FIELD_VALUE = "Täst"; + + public static final String SUB_FORM_NUMBER_FIELD_NAME = "age"; + public static final String SUB_FORM_NUMBER_FIELD_LABEL = "Alter"; + public static final Number SUB_FORM_NUMBER_FIELD_VALUE = 5.5; + + public static final String SUB_FORM_DATE_FIELD_NAME = "birthday"; + public static final String SUB_FORM_DATE_FIELD_LABEL = "Geburtsdatum"; + public static final LocalDate SUB_FORM_DATE_FIELD_VALUE = LocalDate.parse("2017-05-01"); + + public static final String SUB_FORM_BOOLEAN_FIELD_NAME = "geprüft"; + public static final String SUB_FORM_BOOLEAN_FIELD_LABEL = "Geprüft"; + public static final Boolean SUB_FORM_BOOLEAN_FIELD_VALUE = true; + + public static List<EntryFormDataItem> create() { + return List.of( + EntryFormDataField.builder().name(FORM_FIELD_NAME).label(FORM_FIELD_LABEL).stringValue(FORM_FIELD_VALUE).build(), + EntryFormDataSubForm.builder().name(SUB_FORM_NAME).label(SUB_FORM_LABEL) + .formItem(EntryFormDataField.builder() + .name(SUB_FORM_STRING_FIELD_NAME) + .label(SUB_FORM_STRING_FIELD_LABEL) + .stringValue(SUB_FORM_STRING_FIELD_VALUE) + .build()) + .formItem(EntryFormDataField.builder() + .name(SUB_FORM_NUMBER_FIELD_NAME) + .label(SUB_FORM_NUMBER_FIELD_LABEL) + .numberValue(SUB_FORM_NUMBER_FIELD_VALUE) + .build()) + .formItem(EntryFormDataField.builder() + .name(SUB_FORM_DATE_FIELD_NAME) + .label(SUB_FORM_DATE_FIELD_LABEL) + .dateValue(SUB_FORM_DATE_FIELD_VALUE) + .build()) + .formItem(EntryFormDataField.builder() + .name(SUB_FORM_BOOLEAN_FIELD_NAME) + .label(SUB_FORM_BOOLEAN_FIELD_LABEL) + .booleanValue(SUB_FORM_BOOLEAN_FIELD_VALUE) + .build()) + .build()); + } + + public static Map<String, Object> createAsFormDataMap() { + return Map.of( + FORM_FIELD_NAME, Map.of(LABEL_KEY, FORM_FIELD_LABEL, VALUE_KEY, FORM_FIELD_VALUE), + SUB_FORM_NAME, Map.of(LABEL_KEY, SUB_FORM_LABEL, VALUE_KEY, Map.of( + SUB_FORM_STRING_FIELD_NAME, Map.of(LABEL_KEY, SUB_FORM_STRING_FIELD_LABEL, VALUE_KEY, SUB_FORM_STRING_FIELD_VALUE), + SUB_FORM_NUMBER_FIELD_NAME, Map.of(LABEL_KEY, SUB_FORM_NUMBER_FIELD_LABEL, VALUE_KEY, SUB_FORM_NUMBER_FIELD_VALUE), + SUB_FORM_DATE_FIELD_NAME, Map.of(LABEL_KEY, SUB_FORM_DATE_FIELD_LABEL, VALUE_KEY, SUB_FORM_DATE_FIELD_VALUE), + SUB_FORM_BOOLEAN_FIELD_NAME, Map.of(LABEL_KEY, SUB_FORM_BOOLEAN_FIELD_LABEL, VALUE_KEY, SUB_FORM_BOOLEAN_FIELD_VALUE)))); + } +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryResponseTestFactory.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryResponseTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..b72c5b964049b6864305ebcbd626481f08c5cce9 --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EntryResponseTestFactory.java @@ -0,0 +1,16 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; + +class EntryResponseTestFactory { + + static final EntryResponse create() { + return createBuilder().build(); + } + + static final EntryResponse.EntryResponseBuilder createBuilder() { + return EntryResponse.builder() + .transactionId(FormHeaderTestFactory.REQUEST_ID) + .vorgang(ResponseVorgangTestFactory.create()); + } +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/FormDataMapperTest.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/FormDataMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f725885390ee66c6da08232950680b787884562c --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/FormDataMapperTest.java @@ -0,0 +1,26 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; +import org.mockito.InjectMocks; + +class FormDataMapperTest { + + @InjectMocks + private FormDataMapper mapper = Mappers.getMapper(FormDataMapper.class); + + @Nested + class TestMapFormItems { + + @Test + void shouldMapFormItems() { + var mapped = mapper.mapFormItems(EntryFormDataTestFactory.create()); + + assertThat(mapped).usingRecursiveComparison().isEqualTo(EntryFormDataTestFactory.createAsFormDataMap()); + } + } + +} diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/ResponseVorgangTestFactory.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/ResponseVorgangTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..021642935a5410133666d9b3b04d1702516b2e66 --- /dev/null +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/ResponseVorgangTestFactory.java @@ -0,0 +1,24 @@ +package de.ozgcloud.eingang.enterprise.entry; + +import java.time.ZonedDateTime; +import java.util.UUID; + +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.enterprise.entry.EntryResponse.ResponseVorgang; + +public class ResponseVorgangTestFactory { + + final static String VORGANG_ID = UUID.randomUUID().toString(); + + static ResponseVorgang create() { + return createBuilder().build(); + } + + static ResponseVorgang.ResponseVorgangBuilder createBuilder() { + return ResponseVorgang.builder() + .vorgangId(VORGANG_ID) + .vorgangNummer(FormHeaderTestFactory.VORGANG_NUMMER) + .status("NEU") + .statusSince(ZonedDateTime.now()); + } +} diff --git a/enterprise-adapter/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/enterprise-adapter/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 0000000000000000000000000000000000000000..79b126e6cdb86bec1f4f08c205de8961bde1934a --- /dev/null +++ b/enterprise-adapter/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +org.mockito.junit.jupiter.MockitoExtension \ No newline at end of file diff --git a/enterprise-adapter/src/test/resources/junit-platform.properties b/enterprise-adapter/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000000000000000000000000000000000..1cebb76d5a58ac034b2627d12411d82d1e85821e --- /dev/null +++ b/enterprise-adapter/src/test/resources/junit-platform.properties @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled = true \ No newline at end of file diff --git a/enterprise-adapter/src/test/resources/request/simple.json b/enterprise-adapter/src/test/resources/request/simple.json new file mode 100644 index 0000000000000000000000000000000000000000..de767a2355614a0426a6c6bcfe295a2d56713336 --- /dev/null +++ b/enterprise-adapter/src/test/resources/request/simple.json @@ -0,0 +1,45 @@ +{ + "control": { + "transactionId": "4e7a6ae7-4d0f-444d-8971-7cfc051c9924", + "zustaendigeStelle": "248240886", + "leikaIds": [ + "99108011000000", + "99108011153000" + ], + "resultEndpoint": { + "address": "https://idalabs.de/backend/api" + }, + "formId": "KFAS_LIVE_KI_10_Haltverbot_befristet", + "name": "Anmeldung zur Einrichtung einer zeitlich befristeten Haltverbotszone gem. § 45 Abs. 1 Straßenverkehrsordnung (StVO)" + }, + "formData": [ + { + "name": "field_name", + "label": "field_label", + "stringValue": "field_string_value" + }, + { + "name": "antragsteller", + "label": "Antragstellende Person", + "formItems": [ + { + "name": "lastname", + "label": "Nachname", + "stringValue": "Täst" + }, { + "name": "age", + "label": "Alter", + "numberValue": 5.5 + }, { + "name": "birthday", + "label": "Geburtsdatum", + "dateValue": "2017-05-01" + }, { + "name": "geprüft", + "label": "Geprüft", + "booleanValue": true + } + ] + } + ] +} \ No newline at end of file diff --git a/formcycle-adapter/formcycle-adapter-impl/pom.xml b/formcycle-adapter/formcycle-adapter-impl/pom.xml index b042a9d64955ef6827e4f94a0669fa132180c3dc..0eec81b38b2b59561b8f1375f64542519ed66ca0 100644 --- a/formcycle-adapter/formcycle-adapter-impl/pom.xml +++ b/formcycle-adapter/formcycle-adapter-impl/pom.xml @@ -50,11 +50,13 @@ <groupId>de.itvsh.ozg.pluto</groupId> <artifactId>pluto-utils</artifactId> <type>test-jar</type> + <scope>test</scope> </dependency> <dependency> <groupId>de.itvsh.kop.eingangsadapter</groupId> <artifactId>common</artifactId> <type>test-jar</type> + <scope>test</scope> </dependency> <!--spring--> diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java index dbae0279f05c805c2a90cbbebfb8176ad203e513..b467456464ff81be104e520df101cb4597cf09bc 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java @@ -47,6 +47,7 @@ import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; import de.ozgcloud.eingang.semantik.SemantikAdapter; import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; import lombok.RequiredArgsConstructor; diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java index 529668d934ee727e571ce437e92a5b877624639c..1e9430b99f44ee7befc31568c96d3fe940622868 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java @@ -53,6 +53,7 @@ import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; import de.ozgcloud.eingang.formcycle.common.protobuf.ProtobufMessageConverter; import de.ozgcloud.eingang.semantik.SemantikAdapter; diff --git a/formsolutions-adapter/src/main/resources/application.yml b/formsolutions-adapter/src/main/resources/application.yml index f5cf1c4d726b124486b30b389e4ebb2265437dc3..2bc54133d38ff7ad321dac42a977a83226ec67e8 100644 --- a/formsolutions-adapter/src/main/resources/application.yml +++ b/formsolutions-adapter/src/main/resources/application.yml @@ -2,6 +2,7 @@ logging: level: ROOT: WARN '[de.itvsh]': INFO + '[de.ozgcloud]': INFO server: port: 8080 diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java index 19d35efce455bf42a5329463b4893b13a51aaed2..5d9faa593aa0a61b19dee676ab2a233106e010f3 100644 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java +++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.w3c.dom.Document; @@ -99,11 +100,13 @@ class SemantikFormDataMapper { } private byte[] getXmlFormData(DepositData depositData) { + var primaryId = depositData.getPrimaryDataAttachmentId(); + return depositData.getAttachments().stream() - .filter(attachment -> attachment.getName().endsWith(CONTENT_FORMDATA_FILENAME_SUFFIX)) + .filter(attachment -> StringUtils.equals(attachment.getId(), primaryId)) .map(Attachment::getContent) .findFirst() - .orElseThrow(() -> new RuntimeException("Request does not contain a file ending with " + CONTENT_FORMDATA_FILENAME_SUFFIX)); + .orElseThrow(() -> new RuntimeException("Request does not contain primary data attachment")); } private void addFiles(Document document, List<IncomingFile> depositRequestFiles, Map<String, Object> formDataMap) { diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java index 49c38a83bab24294079f8e37f2b548a3cb9f1ca9..174569a3e12d247dd7dc3ac4d9e9ca609298f858 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java @@ -47,6 +47,7 @@ public class DepositTestFactory { static Deposit withData(DepositData data) { Deposit deposit = new Deposit(); + data.setPrimaryDataAttachmentId(AttachmentTestFactory.XML_ID); deposit.setData(data); return deposit; diff --git a/pom.xml b/pom.xml index 9e6924bab385fe1fa4ac3227804b25b962eac5d8..ee801b1b07702ed83e05dbae9c4c5cfd2f6536a5 100644 --- a/pom.xml +++ b/pom.xml @@ -24,17 +24,19 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - + <parent> <groupId>de.itvsh.kop.common</groupId> <artifactId>kop-common-parent</artifactId> - <version>2.3.1</version> - <relativePath/> <!-- lookup parent from repository --> + <version>2.3.2-SNAPSHOT</version> + <relativePath /> <!-- lookup parent from repository --> </parent> - + <groupId>de.itvsh.kop.eingangsadapter</groupId> <artifactId>parent</artifactId> <version>1.13.0-SNAPSHOT</version> @@ -50,12 +52,13 @@ <module>semantik-adapter</module> <module>formcycle-adapter</module> <module>xta-adapter</module> + <module>enterprise-adapter</module> </modules> <properties> <mapstruct.version>1.4.2.Final</mapstruct.version> - <pluto.version>1.10.0</pluto.version> + <pluto.version>1.16.0-SNAPSHOT</pluto.version> <jsoup.version>1.14.3</jsoup.version> <xmlschema.version>2.3.0</xmlschema.version> @@ -154,9 +157,9 @@ </plugin> <plugin> <groupId>com.evolvedbinary.maven.jvnet</groupId> - <artifactId>jaxb30-maven-plugin</artifactId> - <version>${jaxb3-plugin.version}</version> - <executions> + <artifactId>jaxb30-maven-plugin</artifactId> + <version>${jaxb3-plugin.version}</version> + <executions> <execution> <goals> <goal>generate</goal> @@ -206,9 +209,9 @@ </plugin> </plugins> </pluginManagement> - + <plugins> - + </plugins> </build> diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java index 673c669553c99dd68de122f73cdfbec9ee90e5a1..0284bb67723f6534c65f5c8a6663d243afcc7c9b 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java @@ -106,7 +106,8 @@ public class VorgangRemoteService { uploadedAttachments = uploadAttachments(); uploadedRepresentations = uploadRepresentations(); - return finishCreation(); + finishCreation(); + return vorgangId; } String startCreation() { diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java index c9250df82bca02981537461af4eed0e0ee271186..9d617ae52e65f0b17720abb50d13aac388ff430e 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java @@ -40,9 +40,10 @@ public class VorgangService { @Autowired private GrpcEingangMapper grpcEingangMapper; - public void createVorgang(FormData formData) { + public String createVorgang(FormData formData) { var eingang = grpcEingangMapper.toEingang(formData); var organisationsEinheitenId = Optional.ofNullable(formData.getZustaendigeStelle()).map(ZustaendigeStelle::getOrganisationseinheitenId); - remoteService.createVorgang(formData, eingang, organisationsEinheitenId); + + return remoteService.createVorgang(formData, eingang, organisationsEinheitenId); } } \ No newline at end of file diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java index 8b1634ee12f084227bd6b5c68c4e38b79a0941bb..2f846096906aca51f4d3adf35fab0c910070d750 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java @@ -160,10 +160,10 @@ class VorgangRemoteServiceTest { } @Test - void shouldReturnMessage() { + void shouldReturnVorgangId() { var result = createVorgang(); - assertThat(result).isEqualTo(finishResponse.getMessage()); + assertThat(result).isEqualTo(vorgangId); } private String createVorgang() { diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java index efee4d47f49fdda8145bd9f427fa9e2762018a82..74840e2f51139b08cf49bb19bb7016a71dfa2bd9 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java @@ -44,11 +44,11 @@ public class SemantikAdapter { @Autowired private VorgangService vorgangService; - public void processFormData(FormData formData) { + public String processFormData(FormData formData) { formData = parseByEngineAdapter(formData); formData = parseByFormAdapter(formData); - vorgangService.createVorgang(formData); + return vorgangService.createVorgang(formData); } private FormData parseByEngineAdapter(FormData formData) { diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl index a4be54ca4df7a6cefe3c57127c55e5c5bc4621ef..142c08058d339b16a4a710c0bd2f72d41765d627 100644 --- a/src/main/helm/templates/_helpers.tpl +++ b/src/main/helm/templates/_helpers.tpl @@ -71,7 +71,9 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }} {{- end -}} {{- define "app.ingress.host" }} -{{- if eq (.Values.image).name "formsolutions-adapter" }} +{{- if (.Values.ingress).adapterBezeichner }} +{{- printf "%s-%s.%s" (include "app.kopBezeichner" .) .Values.ingress.adapterBezeichner .Values.baseUrl }} +{{- else if eq (.Values.image).name "formsolutions-adapter" }} {{- printf "%s-fs.%s" (include "app.kopBezeichner" .) .Values.baseUrl }} {{- else if eq (.Values.image).name "formcycle-adapter" }} {{- printf "%s-formcycle.%s" (include "app.kopBezeichner" .) .Values.baseUrl }} diff --git a/src/test/helm/ingress_test.yaml b/src/test/helm/ingress_test.yaml index 8cb3a6872ae4323531e5f768abce72e8739dda24..7561bb305275f8ca3e90dc3a317c762bae8dd995 100644 --- a/src/test/helm/ingress_test.yaml +++ b/src/test/helm/ingress_test.yaml @@ -92,6 +92,17 @@ tests: value: helm-formcycle.test.sh.ozg-cloud.de + - it: should create custom adapter host + set: + ingress.adapterBezeichner: test + asserts: + - equal: + path: spec.rules[0].host + value: helm-test.test.sh.ozg-cloud.de + - equal: + path: spec.tls[0].hosts[0] + value: helm-test.test.sh.ozg-cloud.de + - it: should use letsencrypt-prod cluster-issuer as default asserts: - equal: