From 38478f6aacc21c4f8a38448f9cc3083d27da6798 Mon Sep 17 00:00:00 2001 From: Wambere Date: Fri, 15 Dec 2023 23:24:57 +0300 Subject: [PATCH] Add functionality to separately validate app config files (#92) --- .../command/ValidateFhirResourcesCommand.java | 47 +++++- .../test/resources/fhirConfigsJsonSchema.json | 156 ++++++++++++++++++ 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 efsity/src/test/resources/fhirConfigsJsonSchema.json diff --git a/efsity/src/main/java/org/smartregister/command/ValidateFhirResourcesCommand.java b/efsity/src/main/java/org/smartregister/command/ValidateFhirResourcesCommand.java index a44309b7..9a7b1e9c 100644 --- a/efsity/src/main/java/org/smartregister/command/ValidateFhirResourcesCommand.java +++ b/efsity/src/main/java/org/smartregister/command/ValidateFhirResourcesCommand.java @@ -10,16 +10,22 @@ import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.SingleValidationMessage; import ca.uhn.fhir.validation.ValidationResult; + +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; import java.util.Map; +import net.jimblackler.jsonschemafriend.*; import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService; import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.json.JSONObject; import org.smartregister.domain.FctFile; import org.smartregister.util.FctUtils; import picocli.CommandLine; @@ -32,18 +38,24 @@ public class ValidateFhirResourcesCommand implements Runnable { required = true) private String input; + @CommandLine.Option( + names = {"-s", "--schema"}, + description = "configs schema" + ) + private String configSchema; + @Override public void run() { if (input != null) { try { validateFhirResources(input); - } catch (IOException e) { + } catch (IOException | ValidationException | GenerationException e) { throw new RuntimeException(e); } } } - private void validateFhirResources(String inputFilePath) throws IOException { + private void validateFhirResources(String inputFilePath) throws IOException, ValidationException, GenerationException { long start = System.currentTimeMillis(); @@ -69,8 +81,12 @@ private void validateFhirResources(String inputFilePath) throws IOException { if (!Files.isDirectory(Paths.get(inputFilePath))) { FctUtils.printInfo(String.format("\u001b[35m%s\u001b[0m", inputFilePath)); inputFile = FctUtils.readFile(inputFilePath); - IBaseResource resource = iParser.parseResource(inputFile.getContent()); - failCheck = validateResource(validator, resource); + if(isConfigFile(inputFile)){ + failCheck = validateConfig(inputFile); + } else { + IBaseResource resource = iParser.parseResource(inputFile.getContent()); + failCheck = validateResource(validator, resource); + } } else { Map> folderTofilesIndexMap = @@ -84,8 +100,12 @@ private void validateFhirResources(String inputFilePath) throws IOException { inputFile = FctUtils.readFile(nestedEntry.getValue()); try { - IBaseResource resource = iParser.parseResource(inputFile.getContent()); - failCheck = ( validateResource(validator, resource) == -1) ? -1 : failCheck; + if(isConfigFile(inputFile)){ + failCheck = validateConfig(inputFile); + } else { + IBaseResource resource = iParser.parseResource(inputFile.getContent()); + failCheck = ( validateResource(validator, resource) == -1) ? -1 : failCheck; + } } catch (DataFormatException | NoSuchMethodError e) { FctUtils.printError(e.toString()); } @@ -125,4 +145,19 @@ private int validateResource(FhirValidator validator, IBaseResource resource) { return 0; } } + + boolean isConfigFile(FctFile inputFile){ + JSONObject resource = new JSONObject(inputFile.getContent()); + return resource.has("configType"); + } + + int validateConfig(FctFile configFile) throws GenerationException, ValidationException { + SchemaStore schemaStore = new SchemaStore(); + Schema schema = schemaStore.loadSchema(new File(String.valueOf(Paths.get(configSchema)))); + + Validator validator = new Validator(); + validator.validateJson(schema, configFile.getContent()); + FctUtils.printToConsole("Config file is valid!"); + return 0; + } } diff --git a/efsity/src/test/resources/fhirConfigsJsonSchema.json b/efsity/src/test/resources/fhirConfigsJsonSchema.json new file mode 100644 index 00000000..32f707dd --- /dev/null +++ b/efsity/src/test/resources/fhirConfigsJsonSchema.json @@ -0,0 +1,156 @@ +{ + "$id": "https://fhir-configs-validation-schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "FHIR configs JSON Schema", + "type": "object", + "properties": { + "configType": { + "type": "string" + } + }, + "required": ["configType"], + "allOf": [ + { + "if": { + "properties": { + "configType": { + "const": "profile" + } + } + }, + "then": { + "properties": { + "appId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "fhirResource": { + "type": "object" + }, + "rules": { + "type": "array" + }, + "views": { + "type": "array" + }, + "overFlowMenuItems": { + "type": "array" + } + }, + "required": ["appId", "id", "fhirResource", "rules", "views", "overFlowMenuItems"] + } + }, + { + "if": { + "properties": { + "configType": { + "const": "register" + } + } + }, + "then": { + "properties": { + "appId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "fhirResource": { + "type": "object" + }, + "registerCard": { + "type": "object" + } + }, + "required": ["appId", "id", "fhirResource", "registerCard"] + } + }, + { + "if": { + "properties": { + "configType": { + "const": "sync" + } + } + }, + "then": { + "properties": { + "resourceType": { + "type": "string" + }, + "parameter": { + "type": "array" + } + }, + "required": ["resourceType", "parameter"] + } + }, + { + "if": { + "properties": { + "configType": { + "const": "navigation" + } + } + }, + "then": { + "properties": { + "appId": { + "type": "string" + }, + "menuActionButton": { + "type": "object" + }, + "clientRegisters": { + "type": "array" + }, + "staticMenu": { + "type": "array" + } + }, + "required": ["appId", "menuActionButton", "clientRegisters", "staticMenu"] + } + }, + { + "if": { + "properties": { + "configType": { + "const": "application" + } + } + }, + "then": { + "properties": { + "appId": { + "type": "string" + }, + "theme": { + "type": "string" + }, + "appTitle": { + "type": "string" + }, + "remoteSyncPageSize": { + "type": "integer" + }, + "languages": { + "type": "array" + }, + "useDarkTheme": { + "type": "boolean" + }, + "syncInterval": { + "type": "integer" + }, + "syncStrategy": { + "type": "array" + } + }, + "required": ["appId", "theme", "appTitle", "remoteSyncPageSize", "languages", "useDarkTheme", "syncInterval", "syncStrategy"] + } + } + ] +} \ No newline at end of file