diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java b/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java index e5dd7541f2a8787a098e40222765c5fe48d8c62b..3250d70249af4e2b0308c01f664a8d33d09d1bb6 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java @@ -15,7 +15,8 @@ public enum SchemaConfig { SET_V_1_0_1(SCHEMA_BASE_URL.schemaUri.resolve("set-payload/1.0.1/set-payload.schema.json"), "set_schema_1.0.1.json"), SET_V_1_0_0(SCHEMA_BASE_URL.schemaUri.resolve("set-payload/1.0.0/set-payload.schema.json"), "set_schema_1.0.0.json"), METADATA_V_1_0_0(SCHEMA_BASE_URL.schemaUri.resolve("metadata/1.0.0/metadata.schema.json"), "metadata_schema_1.0.0.json"), - XZUFI_DESTINATION_SCHEMA(SCHEMA_BASE_URL.schemaUri.resolve("xzufi/destination.schema.json"), "destination_schema.json"); + XZUFI_DESTINATION_SCHEMA(SCHEMA_BASE_URL.schemaUri.resolve("xzufi/destination.schema.json"), "destination_schema.json"), + SUBMISSION_DATA_SCHEMA(URI.create("https://schema.fitko.de/fim/s00000096_1.0.schema.json"), "s00000096_1.0.schema.json"); private final URI schemaUri; @@ -50,7 +51,7 @@ public enum SchemaConfig { } public static List<String> getSubmissionDataSchemaPaths(final String submissionDataSchemaBaseDir) { - return Stream.empty() + return Stream.of(SUBMISSION_DATA_SCHEMA.fileName) .map(fileName -> submissionDataSchemaBaseDir + "/" + fileName) .collect(Collectors.toList()); } diff --git a/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java b/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java index ef356cb038f5576a41b9be92f44563ac84abf238..ed2f3167720a079eaee6b28377e28bab1a28170f 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -56,7 +57,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -107,7 +108,7 @@ class ValidDataGuardTest { void testMissingDestinationId() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{}", URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")) @@ -126,7 +127,7 @@ class ValidDataGuardTest { void testInvalidServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{\"test\" . \"data\"}", @@ -145,7 +146,7 @@ class ValidDataGuardTest { void testMissingServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{\"test\" . \"data\"}", @@ -171,7 +172,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -202,7 +203,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -234,7 +235,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -268,7 +269,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -321,7 +322,7 @@ class ValidDataGuardTest { void testMissingDestinationId() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -341,7 +342,7 @@ class ValidDataGuardTest { void testInvalidServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -361,7 +362,7 @@ class ValidDataGuardTest { void testMissingServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -387,7 +388,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") diff --git a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java index 31a70c2137720dce5bcd40a1875ecd2005e7ced7..0ffa40b74451a53af3d665615d54c69e4cc93e3f 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java @@ -155,11 +155,10 @@ public class DefaultValidationService implements ValidationService { String schema = schemaProvider.loadSubmissionDataSchema(schemaUri); try { - returnValidationResult(SCHEMA_FACTORY_DRAFT_2007.getSchema(schema).validate(MAPPER.readTree(json))); + return returnValidationResult(SCHEMA_FACTORY_DRAFT_2020.getSchema(schema).validate(MAPPER.readTree(json))); } catch (final JacksonException e) { return ValidationResult.error(e); } - return ValidationResult.ok(); } @Override diff --git a/core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json b/core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..9208f4cc78d33c8309f037a1407347d22d3bc867 --- /dev/null +++ b/core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json @@ -0,0 +1,1263 @@ +{ + "type": "object", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schema.fitko.de/fim/s00000096_1.0.schema.json", + "title": "Mutterschutzliste Detailangaben", + "$defs": { + "G00000253": { + "title": "Arbeitgeber - juristische Person (Anzeige schwangere oder stillende Frau)", + "type": "object", + "properties": { + "F60000319": { + "$ref": "#/$defs/F60000319" + }, + "G60000088": { + "$ref": "#/$defs/G60000088" + }, + "G00001408": { + "$ref": "#/$defs/G00001408" + }, + "G00001914": { + "$ref": "#/$defs/G00001914" + } + }, + "required": [ + "F60000319", + "G60000088", + "G00001408", + "G00001914" + ] + }, + "F60000319": { + "title": "Eingetragener Name / Organisationsname", + "description": "Laut XGewerbeanzeige.Betrieb.eingetragenerName soll der eingetragene Name 1-1000 Zeichen betragen.", + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "G60000088": { + "title": "Anschrift Inland", + "type": "object", + "properties": { + "G60000086": { + "$ref": "#/$defs/G60000086" + }, + "G60000087": { + "$ref": "#/$defs/G60000087" + } + } + }, + "G60000086": { + "title": "Anschrift Inland Straßenanschrift", + "type": "object", + "properties": { + "F60000243": { + "$ref": "#/$defs/F60000243" + }, + "F60000244": { + "$ref": "#/$defs/F60000244" + }, + "F60000246": { + "$ref": "#/$defs/F60000246" + }, + "F60000247": { + "$ref": "#/$defs/F60000247" + }, + "F60000248": { + "$ref": "#/$defs/F60000248" + } + }, + "required": [ + "F60000243", + "F60000246", + "F60000247" + ] + }, + "F60000243": { + "title": "Straße", + "description": "Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist die Feldlänge <= 55 Zeichen.", + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "F60000244": { + "title": "Hausnummer", + "description": "Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) und eines Zeichen (-) zusammen.", + "type": "string", + "minLength": 1, + "maxLength": 11 + }, + "F60000246": { + "title": "Postleitzahl", + "type": "string", + "minLength": 5, + "maxLength": 5, + "pattern": "^([0]{1}[1-9]{1}|[1-9]{1}[0-9]{1})[0-9]{3}$" + }, + "F60000247": { + "title": "Ort", + "description": "Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen.\r\nLaut BSI TR-03123 ≤ 105 Zeichen.", + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "F60000248": { + "title": "Anschrift Zusatzangaben", + "type": "string", + "minLength": 1, + "maxLength": 21 + }, + "G60000087": { + "title": "Anschrift Inland Postfachanschrift", + "type": "object", + "properties": { + "F60000249": { + "$ref": "#/$defs/F60000249" + }, + "F60000246": { + "$ref": "#/$defs/F60000246" + }, + "F60000247": { + "$ref": "#/$defs/F60000247" + } + }, + "required": [ + "F60000246", + "F60000247" + ] + }, + "F60000249": { + "title": "Postfach", + "description": "Die Zeichenlänge des Postfachs orientiert sich derzeit an der Länge einer Adresszeile auf einem Brief. Eine Schärfung/Überprüfung steht noch aus.", + "type": "string", + "minLength": 1, + "maxLength": 21 + }, + "G00001408": { + "title": "Kommunikation (Einverständnis E-Mail, Personalangelegenheit)", + "description": "In dieser Datenfeldgruppe wird per Regel gefordert, dass mindestens eine Kommunikationsmöglichkeit angegeben werden muss. Falls es gewünscht ist, dass keine Kommunikationsmöglichkeit angegeben werden braucht, muss die ganze Feldgruppe bei der Verwendung optional gesetzt werden.", + "type": "object", + "properties": { + "F60000240": { + "$ref": "#/$defs/F60000240" + }, + "F60000241": { + "$ref": "#/$defs/F60000241" + }, + "F00002483": { + "$ref": "#/$defs/F00002483" + }, + "F00002408": { + "$ref": "#/$defs/F00002408" + } + } + }, + "F60000240": { + "title": "Telefon", + "description": "Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.", + "type": "string", + "minLength": 1, + "maxLength": 23 + }, + "F60000241": { + "title": "Telefax", + "description": "Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.", + "type": "string", + "minLength": 1, + "maxLength": 23 + }, + "F00002483": { + "title": "E-Mail Personalangelegenheit", + "type": "string", + "minLength": 6, + "maxLength": 254, + "pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,63}$" + }, + "F00002408": { + "title": "Einverständnis E-Mail", + "type": "boolean" + }, + "G00001914": { + "title": "Ansprechpartner (ohne Funktion / Einverständnis E-Mail)", + "type": "object", + "properties": { + "F60000227": { + "$ref": "#/$defs/F60000227" + }, + "F60000228": { + "$ref": "#/$defs/F60000228" + }, + "F60000229": { + "$ref": "#/$defs/F60000229" + }, + "G00001399": { + "$ref": "#/$defs/G00001399" + } + }, + "required": [ + "F60000227" + ] + }, + "F60000227": { + "title": "Familienname", + "description": "Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen.", + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "F60000228": { + "title": "Vornamen", + "description": "Laut BSI TR-03123 soll Vorname ≤ 80 Zeichen betragen.\r\nLaut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen.", + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "F60000229": { + "title": "Doktorgrade", + "description": "Die Feldlänge ist laut BSI TR-03123 (hier Titel genannt) maximal 120 (Familienname + Titel + Geburtsname). \r\nDurch die Vielzahl von Kombinationsmöglichkeiten, falls mehrere Doktortitel vorhanden sind, ist es nicht sinnvoll, eine Codeliste zu hinterlegen.", + "type": "string", + "minLength": 3, + "maxLength": 119 + }, + "G00001399": { + "title": "Kommunikation (Einverständnis E-Mail)", + "description": "In dieser Datenfeldgruppe wird per Regel gefordert, dass mindestens eine Kommunikationsmöglichkeit angegeben werden muss. Falls es gewünscht ist, dass keine Kommunikationsmöglichkeit angegeben werden braucht, muss die ganze Feldgruppe bei der Verwendung optional gesetzt werden.", + "type": "object", + "properties": { + "F60000240": { + "$ref": "#/$defs/F60000240" + }, + "F60000241": { + "$ref": "#/$defs/F60000241" + }, + "F60000242": { + "$ref": "#/$defs/F60000242" + }, + "F00002408": { + "$ref": "#/$defs/F00002408" + } + } + }, + "F60000242": { + "title": "E-Mail", + "type": "string", + "minLength": 6, + "maxLength": 254, + "pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,63}$" + }, + "G00000271": { + "title": "Informationen zu einer schwangeren oder stillenden Frau", + "type": "object", + "properties": { + "G00000259": { + "$ref": "#/$defs/G00000259" + }, + "G00000260": { + "$ref": "#/$defs/G00000260" + }, + "G00000262": { + "$ref": "#/$defs/G00000262" + }, + "G00000264": { + "$ref": "#/$defs/G00000264" + }, + "G00000263": { + "$ref": "#/$defs/G00000263" + } + }, + "required": [ + "G00000259", + "G00000260", + "G00000262", + "G00000264", + "G00000263" + ] + }, + "G00000259": { + "title": "Persönliche Informationen schwangere stillende Frau Details", + "type": "object", + "properties": { + "F60000227": { + "$ref": "#/$defs/F60000227" + }, + "F60000228": { + "$ref": "#/$defs/F60000228" + }, + "G60000083": { + "$ref": "#/$defs/G60000083" + }, + "G60000093": { + "$ref": "#/$defs/G60000093" + }, + "F00000462": { + "$ref": "#/$defs/F00000462" + }, + "F00000467": { + "$ref": "#/$defs/F00000467" + }, + "F00000468": { + "$ref": "#/$defs/F00000468" + }, + "F00000471": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000471" + }, + "minItems": 1 + }, + "F00000473": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000473" + }, + "minItems": 1 + } + }, + "required": [ + "F60000227", + "G60000083", + "G60000093", + "F00000462" + ] + }, + "G60000083": { + "title": "Geburtsdatum (teilbekannt)", + "type": "object", + "properties": { + "F60000231": { + "$ref": "#/$defs/F60000231" + }, + "F60000232": { + "$ref": "#/$defs/F60000232" + }, + "F60000233": { + "$ref": "#/$defs/F60000233" + } + }, + "required": [ + "F60000233" + ] + }, + "F60000231": { + "title": "Tag (ohne Monat und Jahr)", + "type": "integer", + "minimum": 1, + "maximum": 31 + }, + "F60000232": { + "title": "Monat", + "type": "integer", + "minimum": 1, + "maximum": 12 + }, + "F60000233": { + "title": "Jahr", + "type": "integer", + "minimum": 1850, + "maximum": 2080 + }, + "G60000093": { + "title": "Anschrift Inland oder Ausland mit Frage", + "description": "Zu beachten: wird die Anschrift im Kontext der Online-Ausweisfunktion des neuen Personalausweis verwendet, können nur Personen mit Anschriften in Deutschland authentisiert werden (siehe auch https://www.personalausweisportal.de/DE/Buergerinnen-und-Buerger/Online-Ausweisen/Wohnsitz_im_Ausland/wohnsitz_im_ausland_node.html). Bei der Umsetzung müssen somit ausländische Anschriften ausgeschlossen werden.", + "type": "object", + "properties": { + "F60000263": { + "$ref": "#/$defs/F60000263" + }, + "G60000088": { + "$ref": "#/$defs/G60000088" + }, + "G60000091": { + "$ref": "#/$defs/G60000091" + } + }, + "required": [ + "F60000263" + ] + }, + "F60000263": { + "title": "Abfrage Anschrift Inland oder Ausland", + "description": "Verwendete Codeliste: Anschrift Inland oder Ausland 2020-08-18", + "type": "string", + "enum": [ + "001", + "002" + ] + }, + "G60000091": { + "title": "Anschrift Ausland", + "type": "object", + "properties": { + "F60000261": { + "$ref": "#/$defs/F60000261" + }, + "G60000092": { + "$ref": "#/$defs/G60000092" + } + }, + "required": [ + "F60000261", + "G60000092" + ] + }, + "F60000261": { + "title": "Staat", + "description": "Verwendete Codeliste: Staat 2021-02-19", + "type": "string", + "enum": [ + "000", + "121", + "122", + "123", + "124", + "125", + "126", + "127", + "128", + "129", + "130", + "131", + "134", + "135", + "136", + "137", + "139", + "140", + "141", + "142", + "143", + "144", + "145", + "146", + "147", + "148", + "149", + "150", + "151", + "152", + "153", + "154", + "155", + "156", + "157", + "158", + "160", + "161", + "163", + "164", + "165", + "166", + "167", + "168", + "169", + "170", + "181", + "221", + "223", + "224", + "225", + "226", + "227", + "229", + "230", + "231", + "232", + "233", + "236", + "237", + "238", + "239", + "242", + "243", + "244", + "245", + "246", + "247", + "248", + "249", + "251", + "252", + "253", + "254", + "255", + "256", + "257", + "258", + "259", + "261", + "262", + "263", + "265", + "267", + "268", + "269", + "271", + "272", + "273", + "274", + "277", + "278", + "281", + "282", + "283", + "284", + "285", + "286", + "287", + "289", + "291", + "320", + "322", + "323", + "324", + "326", + "327", + "328", + "330", + "332", + "333", + "334", + "335", + "336", + "337", + "340", + "345", + "346", + "347", + "348", + "349", + "351", + "353", + "354", + "355", + "357", + "359", + "361", + "364", + "365", + "366", + "367", + "368", + "369", + "370", + "371", + "421", + "422", + "423", + "424", + "425", + "426", + "427", + "429", + "430", + "431", + "432", + "434", + "436", + "437", + "438", + "439", + "441", + "442", + "444", + "445", + "446", + "447", + "448", + "449", + "450", + "451", + "454", + "456", + "457", + "458", + "460", + "461", + "462", + "467", + "469", + "470", + "471", + "472", + "474", + "475", + "476", + "477", + "479", + "482", + "483", + "523", + "524", + "526", + "527", + "530", + "531", + "532", + "533", + "536", + "537", + "538", + "540", + "541", + "543", + "544", + "545" + ] + }, + "G60000092": { + "title": "Anschriftzone", + "type": "object", + "properties": { + "F60000262": { + "type": "array", + "items": { + "$ref": "#/$defs/F60000262" + }, + "minItems": 2, + "maxItems": 5 + } + }, + "required": [ + "F60000262" + ] + }, + "F60000262": { + "title": "ZeileAnschrift", + "type": "string", + "minLength": 1, + "maxLength": 35 + }, + "F00000462": { + "title": "Status Frau (schwanger, stillend)", + "type": "string", + "enum": [ + "001", + "002" + ] + }, + "F00000467": { + "title": "Voraussichtlicher Entbindungstermin", + "type": "string", + "format": "date" + }, + "F00000468": { + "title": "Entbindungstermin", + "type": "string", + "format": "date" + }, + "F00000471": { + "title": "Ergebnis Entbindung", + "description": "Eine Mehrlingsgeburt kann über Mehrfachauswahl abgefragt werden.", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004", + "005" + ] + }, + "F00000473": { + "title": "Nachweis Schutzfristverlängerung Behinderung", + "type": "string" + }, + "G00000260": { + "title": "Informationen Beschäftigung schwangere stillende Frau Details", + "type": "object", + "properties": { + "F00000463": { + "$ref": "#/$defs/F00000463" + }, + "F00000601": { + "$ref": "#/$defs/F00000601" + }, + "G00000261": { + "$ref": "#/$defs/G00000261" + }, + "G00000280": { + "type": "array", + "items": { + "$ref": "#/$defs/G00000280" + }, + "minItems": 1 + } + }, + "required": [ + "F00000463", + "G00000261" + ] + }, + "F00000463": { + "title": "Beschäftigungsverhältnis Frau", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004", + "005", + "006", + "007", + "008", + "999" + ] + }, + "F00000601": { + "title": "Beschäftigungsverhältnis Frau Sonstiges", + "type": "string" + }, + "G00000261": { + "title": "Informationen Vertragslaufzeit", + "type": "object", + "properties": { + "F00000488": { + "$ref": "#/$defs/F00000488" + }, + "F00000489": { + "$ref": "#/$defs/F00000489" + }, + "F00000490": { + "$ref": "#/$defs/F00000490" + }, + "F00000491": { + "$ref": "#/$defs/F00000491" + } + }, + "required": [ + "F00000488", + "F00000489" + ] + }, + "F00000488": { + "title": "Vertrag Befristung", + "type": "string", + "enum": [ + "001", + "002" + ] + }, + "F00000489": { + "title": "Beschäftigungsbeginn", + "type": "string", + "format": "date" + }, + "F00000490": { + "title": "Beschäftigungsende", + "type": "string", + "format": "date" + }, + "F00000491": { + "title": "Kündigungsdatum", + "type": "string", + "format": "date" + }, + "G00000280": { + "title": "Angaben zur Elternzeit", + "type": "object", + "properties": { + "F60000048": { + "$ref": "#/$defs/F60000048" + }, + "F60000049": { + "$ref": "#/$defs/F60000049" + } + }, + "required": [ + "F60000048", + "F60000049" + ] + }, + "F60000048": { + "title": "Anfang", + "type": "string", + "format": "date" + }, + "F60000049": { + "title": "Ende", + "type": "string", + "format": "date" + }, + "G00000262": { + "title": "Informationen zur beabsichtigten Beschäftigung der schwangeren oder stillenden Frau Details", + "type": "object", + "properties": { + "F00000464": { + "$ref": "#/$defs/F00000464" + }, + "G00001404": { + "$ref": "#/$defs/G00001404" + }, + "F00000465": { + "$ref": "#/$defs/F00000465" + }, + "G00001405": { + "$ref": "#/$defs/G00001405" + }, + "F00002420": { + "$ref": "#/$defs/F00002420" + }, + "G00001406": { + "$ref": "#/$defs/G00001406" + }, + "F00000466": { + "$ref": "#/$defs/F00000466" + }, + "F00002421": { + "$ref": "#/$defs/F00002421" + }, + "F00002422": { + "$ref": "#/$defs/F00002422" + }, + "F00002423": { + "$ref": "#/$defs/F00002423" + } + }, + "required": [ + "F00000464", + "F00000466", + "F00002421" + ] + }, + "F00000464": { + "title": "Sonn- und Feiertagsarbeit (Mutterschutz)", + "type": "boolean" + }, + "G00001404": { + "title": "Sonn- und Feiertagsarbeit (Mutterschutz)", + "type": "object", + "properties": { + "F00000482": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000482" + }, + "minItems": 1 + }, + "F00002416": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002416" + }, + "minItems": 1 + }, + "F00002415": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002415" + }, + "minItems": 1 + } + }, + "required": [ + "F00000482", + "F00002416", + "F00002415" + ] + }, + "F00000482": { + "title": "Bereiterklärung Sonn- und Feiertagsarbeit", + "type": "string" + }, + "F00002416": { + "title": "Nachweis: Ausnahme § 10 Arbeitszeitgesetz ", + "type": "string" + }, + "F00002415": { + "title": "Nachweis: Ersatzruhetag", + "type": "string" + }, + "F00000465": { + "title": "Nachtarbeit (Mutterschutz)", + "type": "boolean" + }, + "G00001405": { + "title": "Nachtarbeit (Mutterschutz)", + "type": "object", + "properties": { + "F00000483": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000483" + }, + "minItems": 1 + }, + "F00002035": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002035" + }, + "minItems": 1 + }, + "F00002414": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002414" + }, + "minItems": 1 + }, + "F00000485": { + "$ref": "#/$defs/F00000485" + }, + "F00000249": { + "$ref": "#/$defs/F00000249" + }, + "F00000487": { + "$ref": "#/$defs/F00000487" + }, + "F60000296": { + "type": "array", + "items": { + "$ref": "#/$defs/F60000296" + }, + "minItems": 1 + } + }, + "required": [ + "F00000483", + "F00002035", + "F00002414", + "F00000485" + ] + }, + "F00000483": { + "title": "Erklärung Nachtarbeit", + "type": "string" + }, + "F00002035": { + "title": "Ärztliches Zeugnis (Unbedenklichkeitsbescheinigung)", + "type": "string" + }, + "F00002414": { + "title": "Nachweis: Ausschluss Gefährdung durch Alleinarbeit", + "type": "string" + }, + "F00000485": { + "title": "Status Antrag Nachtarbeit", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004" + ] + }, + "F00000249": { + "title": "Datum der Antragstellung", + "type": "string", + "format": "date" + }, + "F00000487": { + "title": "Genehmigungsdatum", + "type": "string", + "format": "date" + }, + "F60000296": { + "title": "Nachweis", + "type": "string" + }, + "F00002420": { + "title": "Teilnahme an Ausbildungsveranstaltungen (Mutterschutz)", + "type": "boolean" + }, + "G00001406": { + "title": "Nachtarbeit (Studentin/Schülerin - Mutterschutz)", + "type": "object", + "properties": { + "F00002036": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002036" + }, + "minItems": 1 + }, + "F00000484": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000484" + }, + "minItems": 1 + }, + "F00002414": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002414" + }, + "minItems": 1 + } + }, + "required": [ + "F00002036", + "F00000484", + "F00002414" + ] + }, + "F00002036": { + "title": "Nachweis: Erforderlichkeit Teilnahme an Ausbildungsveranstaltungen", + "type": "string" + }, + "F00000484": { + "title": "Nachtarbeit Ausbildung (Bereiterklärung)", + "type": "string" + }, + "F00000466": { + "title": "Mutterschutz getaktete Arbeit", + "type": "boolean" + }, + "F00002421": { + "title": "Heimarbeit (Mutterschutz)", + "type": "string" + }, + "F00002422": { + "title": "Umfang Heimarbeit (schwanger - Mutterschutz)", + "type": "string" + }, + "F00002423": { + "title": "Umfang Heimarbeit (stillend - Mutterschutz)", + "type": "string" + }, + "G00000264": { + "title": "Informationen zur Art der Beschäftigung der schwangeren oder stillenden Frau", + "type": "object", + "properties": { + "G00000267": { + "$ref": "#/$defs/G00000267" + }, + "F00000501": { + "$ref": "#/$defs/F00000501" + }, + "F00000503": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000503" + }, + "minItems": 1 + }, + "F00000502": { + "$ref": "#/$defs/F00000502" + }, + "F00002418": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002418" + }, + "minItems": 1 + }, + "G00000268": { + "$ref": "#/$defs/G00000268" + } + }, + "required": [ + "G00000267", + "F00000501", + "F00000503" + ] + }, + "G00000267": { + "title": "Informationen zur Beschäftigung vor Schwangerschaft", + "type": "object", + "properties": { + "F00000499": { + "$ref": "#/$defs/F00000499" + }, + "G00001597": { + "$ref": "#/$defs/G00001597" + }, + "F00000215": { + "$ref": "#/$defs/F00000215" + }, + "F00000500": { + "$ref": "#/$defs/F00000500" + } + }, + "required": [ + "F00000499", + "F00000215", + "F00000500" + ] + }, + "F00000499": { + "title": "Beschäftigungsort", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004" + ] + }, + "G00001597": { + "title": "Betriebsstätte (mit Organisationsname)", + "type": "object", + "properties": { + "F60000319": { + "$ref": "#/$defs/F60000319" + }, + "G60000086": { + "$ref": "#/$defs/G60000086" + }, + "G00001408": { + "$ref": "#/$defs/G00001408" + } + }, + "required": [ + "G60000086", + "G00001408" + ] + }, + "F00000215": { + "title": "Berufliche Tätigkeit - Art", + "type": "string" + }, + "F00000500": { + "title": "Name Arbeitsplatz Gefährdungsbeurteilung", + "description": "Über diesen Namen wird auf die externe Gefährdungsbeurteilung (§ 10 MuSchG; § 5 ArbSchG) verwiesen. In dieser Gefährungsbeurteilung sollten alle relevanten Aspekte aus § 9 (3) MuSchG, § 11 MuSchG, § 12 MuSchG aufgenommen werden.", + "type": "string" + }, + "F00000501": { + "title": "Ergebnis der Beurteilung der Arbeitsbedingungen", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004", + "005", + "006", + "007" + ] + }, + "F00000503": { + "title": "Gefährdungsbeurteilung Mutterschutz", + "type": "string" + }, + "F00000502": { + "title": "Umgestaltung der Arbeitsbedingungen", + "type": "string" + }, + "F00002418": { + "title": "Nachweis: Umgestaltung der Arbeitsbedingungen durch Schutzmaßnahmen", + "type": "string" + }, + "G00000268": { + "title": "Informationen zur Beschäftigung während der Schutzzeiten vor und nach der Entbindung", + "type": "object", + "properties": { + "F00000499": { + "$ref": "#/$defs/F00000499" + }, + "G00001597": { + "$ref": "#/$defs/G00001597" + }, + "F00000215": { + "$ref": "#/$defs/F00000215" + }, + "F00000500": { + "$ref": "#/$defs/F00000500" + } + }, + "required": [ + "F00000499", + "F00000215", + "F00000500" + ] + }, + "G00000263": { + "title": "Informationen zum Umfang der Beschäftigung der schwangeren oder stillenden Frau", + "type": "object", + "properties": { + "F00000494": { + "$ref": "#/$defs/F00000494" + }, + "F00000495": { + "$ref": "#/$defs/F00000495" + }, + "F00000496": { + "$ref": "#/$defs/F00000496" + }, + "F00000497": { + "$ref": "#/$defs/F00000497" + }, + "F00000498": { + "$ref": "#/$defs/F00000498" + }, + "F00002413": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002413" + }, + "minItems": 1 + }, + "F00002417": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002417" + }, + "minItems": 1 + }, + "F00002419": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002419" + }, + "minItems": 1 + } + }, + "required": [ + "F00000496", + "F00000497", + "F00000498", + "F00002413", + "F00002417", + "F00002419" + ] + }, + "F00000494": { + "title": "Tagesarbeitszeit", + "type": "number" + }, + "F00000495": { + "title": "Doppelwochenarbeitszeit", + "type": "number" + }, + "F00000496": { + "title": "Uhrzeit des frühest möglichen Arbeits- oder Ausbildungsbeginns", + "type": "string" + }, + "F00000497": { + "title": "Uhrzeit des spätest möglichen Arbeits- oder Ausbildungsendes", + "type": "string" + }, + "F00000498": { + "title": "Dauer aller Ruhepause in Minuten ", + "type": "string" + }, + "F00002413": { + "title": "Nachweis: Ausschluss Ruhezeiten unter 11 Stunden", + "type": "string" + }, + "F00002417": { + "title": "Nachweis: Freistellung Untersuchungen", + "type": "string" + }, + "F00002419": { + "title": "Nachweis: Vermeidung von Nachteilen ", + "type": "string" + } + }, + "properties": { + "G00000253": { + "$ref": "#/$defs/G00000253" + }, + "G00000271": { + "type": "array", + "items": { + "$ref": "#/$defs/G00000271" + }, + "minItems": 1 + } + }, + "required": [ + "G00000253", + "G00000271" + ] +} \ No newline at end of file diff --git a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java index ede11c83a93f887693e1075dba52b62c03f1737a..c61b729891b9a3731a04194832c2e2855e448886 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java @@ -24,7 +24,6 @@ import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.exceptions.ValidationException; import dev.fitko.fitconnect.api.services.crypto.MessageDigestService; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; -import dev.fitko.fitconnect.api.services.validation.ValidationService; import dev.fitko.fitconnect.core.crypto.HashService; import dev.fitko.fitconnect.core.schema.SchemaResourceProvider; import dev.fitko.fitconnect.core.testutil.LogCaptor; @@ -44,13 +43,15 @@ import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.*; class DefaultValidationServiceTest { - private ValidationService underTest; + private DefaultValidationService underTest; private MessageDigestService hashService; private static final LogCaptor logs = new LogCaptor(); + private RestTemplate restTemplate = mock(RestTemplate.class); private SchemaProvider schemaProvider; @BeforeEach @@ -62,7 +63,7 @@ class DefaultValidationServiceTest { final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); final List<String> submissionDataSchemas = SchemaConfig.getSubmissionDataSchemaPaths("/submission-data-schema"); final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemas); - schemaProvider = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); + schemaProvider = new SchemaResourceProvider(restTemplate, schemaResources); underTest = new DefaultValidationService(config, hashService, schemaProvider); } @@ -372,7 +373,7 @@ class DefaultValidationServiceTest { void testValidDestinationPayload() { // Given - final Map<String,Object> claims = Map.of( + final Map<String, Object> claims = Map.of( "iss", "submission-service", "jti", UUID.randomUUID().toString(), "iat", new Date().getTime(), @@ -392,7 +393,7 @@ class DefaultValidationServiceTest { void testDestinationPayloadIsMissingMandatoryClaims() { // Given - final Map<String,Object> claims = Map.of("test", "claim"); + final Map<String, Object> claims = Map.of("test", "claim"); // When final ValidationResult validationResult = underTest.validateDestinationSchema(claims); @@ -411,10 +412,14 @@ class DefaultValidationServiceTest { void testValidJson() throws IOException { // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn("{}"); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + final var validJson = getResource("/valid_json_data.json"); // When - final ValidationResult validationResult = underTest.validateJsonFormat(validJson, URI.create("urn:something")); + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(validJson, URI.create("urn:something")); // Then assertTrue(validationResult.isValid()); @@ -424,16 +429,56 @@ class DefaultValidationServiceTest { void testInvalidJson() throws IOException { // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn("{}"); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + final var invalidJson = getResource("/invalid_json_data.json"); // When - final ValidationResult validationResult = underTest.validateJsonFormat(invalidJson, URI.create("urn:something")); + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(invalidJson, URI.create("urn:something")); // Then assertFalse(validationResult.isValid()); assertTrue(validationResult.hasError()); assertThat(validationResult.getError().getMessage(), containsString("was expecting double-quote to start field name")); + } + + @Test + void testValidSubmissionDataSchema() throws IOException { + + // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn(getResource("/submission_data_schema.json")); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + final var invalidJson = "{ \"someString\": \"someStringValue\", \"someArray\": [\"someArrayValue\"] }"; + + // When + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(invalidJson, URI.create("urn:something")); + + // Then + assertTrue(validationResult.isValid()); + assertFalse(validationResult.hasError()); + } + + @Test + void testInvalidSubmissionDataSchema() throws IOException { + + // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn(getResource("/submission_data_schema.json")); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + + final var invalidJson = "{ \"wrongString\": \"someStringValue\", \"someArray\": [\"someArrayValue\"] }"; + + // When + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(invalidJson, URI.create("urn:something")); + + // Then + assertFalse(validationResult.isValid()); + assertTrue(validationResult.hasError()); + assertThat(validationResult.getError().getMessage(), containsString("$.someString")); } @Test diff --git a/core/src/test/resources/submission_data_schema.json b/core/src/test/resources/submission_data_schema.json new file mode 100644 index 0000000000000000000000000000000000000000..dfe7ac754a0a2ba79274c44f716ffed25eb20c2a --- /dev/null +++ b/core/src/test/resources/submission_data_schema.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://test/submission_data_schema.json", + "title": "test service", + "properties": { + "someString": { + "type": "string" + }, + "someArray": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": [ + "someString", + "someArray" + ] +} \ No newline at end of file