diff --git a/README.md b/README.md index 98cbf8c6..50eb1f9f 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,10 @@ See the [documentation on Initializer's logging properties](readme/rtprops.md#lo ## Releases notes +#### Version 2.8.0 +* Ampath forms translation files will now generate checksums. +* Enhancement to ensure that when an Ampath forms file is loaded, a new resource with the existing Ampath forms translations is created. + #### Version 2.7.0 * Added support for 'queues' domain. * Added support for 'addresshierarchy' domain. diff --git a/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsLoader.java b/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsLoader.java index 83f6436a..87e737c9 100644 --- a/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsLoader.java +++ b/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsLoader.java @@ -15,6 +15,7 @@ import org.openmrs.api.FormService; import org.openmrs.api.db.ClobDatatypeStorage; import org.openmrs.module.initializer.Domain; +import org.openmrs.module.initializer.api.ConfigDirUtil; import org.openmrs.module.initializer.api.utils.Utils; import org.openmrs.util.OpenmrsUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +27,8 @@ public class AmpathFormsLoader extends BaseFileLoader { public static final String AMPATH_FORMS_UUID = "794c4598-ab82-47ca-8d18-483a8abe6f4f"; + public static final String JSON_EXTENSION = "json"; + @Autowired private DatatypeService datatypeService; @@ -83,6 +86,21 @@ protected void load(File file) throws Exception { throw new Exception("Form Version is required"); } + // Delete Checksum Files for the translation files associated with the form + ConfigDirUtil configDirUtil = new ConfigDirUtil(iniz.getConfigDirPath(), iniz.getChecksumsDirPath(), + Domain.AMPATH_FORMS_TRANSLATIONS.getName(), true); + + for (File translationFile : configDirUtil.getFiles(JSON_EXTENSION)) { + String js = FileUtils.readFileToString(translationFile, StandardCharsets.UTF_8.toString()); + Map jf = new ObjectMapper().readValue(js, Map.class); + String translationForm = (String) jf.get("form"); + + if (StringUtils.equals(translationForm, formName)) { + configDirUtil + .deleteChecksumFile(replaceExtension(translationFile.getName(), ConfigDirUtil.CHECKSUM_FILE_EXT)); + } + } + String uuid = Utils.generateUuidFromObjects(AMPATH_FORMS_UUID, formName, formVersion); // Process Form // ISSUE-150 If form with uuid present then update it @@ -169,4 +187,22 @@ private void createNewForm(String uuid, String formName, String formDescription, clobData.setValue(jsonString); datatypeService.saveClobDatatypeStorage(clobData); } + + private static String replaceExtension(String fileName, String newExtension) { + // Validate inputs + if (StringUtils.isEmpty(fileName) || StringUtils.isEmpty(newExtension)) { + throw new IllegalArgumentException("File name and extension must not be null or empty"); + } + + // Find the last dot in the file name + int lastDotIndex = fileName.lastIndexOf('.'); + + // Handle the case where there's no dot in the file name + if (lastDotIndex == -1) { + return fileName + "." + newExtension; + } + + // Replace the extension + return fileName.substring(0, lastDotIndex) + "." + newExtension; + } } diff --git a/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsTranslationsLoader.java b/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsTranslationsLoader.java index 56fefb12..2933c863 100644 --- a/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsTranslationsLoader.java +++ b/api/src/main/java/org/openmrs/module/initializer/api/loaders/AmpathFormsTranslationsLoader.java @@ -2,6 +2,7 @@ import java.io.File; import java.util.Map; + import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.LocaleUtils; import org.apache.commons.lang3.StringUtils; @@ -9,19 +10,20 @@ import org.openmrs.Form; import org.openmrs.FormResource; import org.openmrs.api.FormService; -import org.openmrs.api.context.Context; import org.openmrs.messagesource.PresentationMessage; import org.openmrs.module.initializer.Domain; import org.openmrs.module.initializer.InitializerMessageSource; -import org.openmrs.module.initializer.api.ConfigDirUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; + import java.nio.charset.StandardCharsets; @Component public class AmpathFormsTranslationsLoader extends BaseFileLoader { + private static final String LONG_FREE_TEXT_DATATYPE = "org.openmrs.customdatatype.datatype.LongFreeTextDatatype"; + @Autowired private FormService formService; @@ -44,40 +46,42 @@ protected void load(File file) throws Exception { String jsonTranslationsString = FileUtils.readFileToString(file, StandardCharsets.UTF_8.toString()); Map jsonTranslationsDefinition = new ObjectMapper().readValue(jsonTranslationsString, Map.class); - String formResourceUuid = (String) jsonTranslationsDefinition.get("uuid"); - if (StringUtils.isBlank(formResourceUuid)) { - throw new IllegalArgumentException("Uuid is required for AMPATH forms translations loader."); - } - String language = (String) jsonTranslationsDefinition.get("language"); if (StringUtils.isBlank(language)) { throw new IllegalArgumentException("'language' property is required for AMPATH forms translations loader."); } Form form = null; - FormResource formResource = Context.getFormService().getFormResourceByUuid(formResourceUuid); - if (formResource == null) { - formResource = new FormResource(); - formResource.setUuid(formResourceUuid); - } else { - form = formResource.getForm(); - } + String formName = (String) jsonTranslationsDefinition.get("form"); + if (formName == null) { + throw new IllegalArgumentException("'form' property is required for AMPATH forms translations loader."); + } + form = formService.getForm(formName); if (form == null) { - String formName = (String) jsonTranslationsDefinition.get("form"); - if (formName == null) { - throw new IllegalArgumentException("'form' property is required for AMPATH forms translations loader."); - } - form = formService.getForm(formName); - if (form == null) { - throw new IllegalArgumentException( - "Could not find a form named '" + formName + "'. Please ensure an existing form is configured."); + throw new IllegalArgumentException( + "Could not find a form named '" + formName + "'. Please ensure an existing form is configured."); + } + + FormResource formResource = null; + for (FormResource fr : formService.getFormResourcesForForm(form)) { + if (LONG_FREE_TEXT_DATATYPE.equals(fr.getDatatypeClassname())) { + Map jsonMap = new ObjectMapper().readValue(fr.getValue().toString(), Map.class); + if (jsonMap.containsKey("translations") && StringUtils.equals(jsonMap.get("language").toString(), + jsonTranslationsDefinition.get("language").toString())) { + formResource = fr; + break; + } } } - formResource.setForm(form); - formResource.setName(form.getName() + "_translations_" + language); - formResource.setDatatypeClassname("org.openmrs.customdatatype.datatype.LongFreeTextDatatype"); + if (formResource == null) { + formResource = new FormResource(); + formResource.setForm(form); + formResource.setName(form.getName() + "_translations_" + language); + formResource.setDatatypeClassname(LONG_FREE_TEXT_DATATYPE); + } + formResource.setValue(jsonTranslationsString); formService.saveFormResource(formResource); @@ -89,9 +93,4 @@ protected void load(File file) throws Exception { LocaleUtils.toLocale(language), formNameTranslation, null)); } } - - @Override - public ConfigDirUtil getDirUtil() { - return new ConfigDirUtil(iniz.getConfigDirPath(), iniz.getChecksumsDirPath(), getDomainName(), true); - } } diff --git a/api/src/test/java/org/openmrs/module/initializer/api/form/AmpathFormsTranslationsLoaderIntegrationTest.java b/api/src/test/java/org/openmrs/module/initializer/api/form/AmpathFormsTranslationsLoaderIntegrationTest.java index 596a7287..b57712a9 100644 --- a/api/src/test/java/org/openmrs/module/initializer/api/form/AmpathFormsTranslationsLoaderIntegrationTest.java +++ b/api/src/test/java/org/openmrs/module/initializer/api/form/AmpathFormsTranslationsLoaderIntegrationTest.java @@ -10,6 +10,7 @@ import org.junit.runners.MethodSorters; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.openmrs.Form; import org.openmrs.FormResource; import org.openmrs.api.FormService; import org.openmrs.api.context.Context; @@ -31,8 +32,6 @@ public class AmpathFormsTranslationsLoaderIntegrationTest extends DomainBaseModu private static final String FORM_TRANSLATIONS_FOLDER_PATH = "src/test/resources/ampathformstranslations/"; - private static final String RESOURCE_UUID = "c5bf3efe-3798-4052-8dcb-09aacfcbabdc"; - @Autowired private AmpathFormsTranslationsLoader ampathFormsTranslationsLoader; @@ -60,13 +59,12 @@ public void load_shouldLoadAFormTranslationsFileWithAllAttributesSpecifiedAsForm ampathFormsTranslationsLoader.load(); // Verify - FormResource formResource = formService.getFormResourceByUuid(RESOURCE_UUID); + Form form = formService.getForm("Test Form 1"); + FormResource formResource = formService.getFormResource(form, "Test Form 1_translations_fr"); Assert.assertNotNull(formResource); - Assert.assertEquals("c5bf3efe-3798-4052-8dcb-09aacfcbabdc", formResource.getUuid()); ObjectMapper mapper = new ObjectMapper(); JsonNode actualObj = mapper.readTree((String) formResource.getValue()); - Assert.assertEquals("c5bf3efe-3798-4052-8dcb-09aacfcbabdc", actualObj.get("uuid").getTextValue()); Assert.assertEquals("French Translations", actualObj.get("description").getTextValue()); Assert.assertEquals("fr", actualObj.get("language").getTextValue()); Assert.assertEquals("Encontre", actualObj.get("translations").get("Encounter").getTextValue()); @@ -90,15 +88,14 @@ public void load_shouldLoadAndUpdateAFormTranslationsFileAsFormResource() throws // Test that initial version loads in with expected values ampathFormsTranslationsLoader.load(); - FormResource formResource = formService.getFormResourceByUuid(RESOURCE_UUID); - // Verify + Form form = formService.getForm("Test Form 1"); + FormResource formResource = formService.getFormResource(form, "Test Form 1_translations_fr"); + Assert.assertNotNull(formResource); - Assert.assertEquals("c5bf3efe-3798-4052-8dcb-09aacfcbabdc", formResource.getUuid()); ObjectMapper mapper = new ObjectMapper(); JsonNode ampathTranslations = mapper.readTree((String) formResource.getValue()); - Assert.assertEquals("c5bf3efe-3798-4052-8dcb-09aacfcbabdc", ampathTranslations.get("uuid").getTextValue()); Assert.assertEquals("French Translations", ampathTranslations.get("description").getTextValue()); Assert.assertEquals("fr", ampathTranslations.get("language").getTextValue()); Assert.assertEquals("Encontre", ampathTranslations.get("translations").get("Encounter").getTextValue()); @@ -115,13 +112,14 @@ public void load_shouldLoadAndUpdateAFormTranslationsFileAsFormResource() throws // Replay // Now load updated values ampathFormsTranslationsLoader.load(); - FormResource formResourceUpdated = formService.getFormResourceByUuid(RESOURCE_UUID); + + Form formUpdated = formService.getForm("Test Form 1"); + FormResource formResourceUpdated = formService.getFormResource(formUpdated, "Test Form 1_translations_fr"); // Verify Assert.assertNotNull(formResourceUpdated); ObjectMapper mapperUpdated = new ObjectMapper(); JsonNode ampathTranslationsUpdated = mapperUpdated.readTree((String) formResourceUpdated.getValue()); - Assert.assertEquals("c5bf3efe-3798-4052-8dcb-09aacfcbabdc", ampathTranslationsUpdated.get("uuid").getTextValue()); Assert.assertEquals("French Translations Updated", ampathTranslationsUpdated.get("description").getTextValue()); Assert.assertEquals("fr", ampathTranslationsUpdated.get("language").getTextValue()); Assert.assertEquals("Tante", ampathTranslationsUpdated.get("translations").get("Aunt").getTextValue()); @@ -140,23 +138,6 @@ public void load_shouldThrowGivenInvalidFormAssociatedWithFormTranslations() thr } - @Test - public void load_shouldThrowGivenMissingUuidPropertyInFormTranslationsDef() throws Exception { - // Setup - thrown.expectMessage("IllegalArgumentException: Uuid is required for AMPATH forms translations loader."); - - String missingUuidTranslationDefFile = "src/test/resources/testdata/testAmpathformstranslations/invalid_form_missing_uuid_translations_fr.json"; - File srcFile = new File(missingUuidTranslationDefFile); - File dstFile = new File( - ampathFormsTranslationsLoader.getDirUtil().getDomainDirPath() + "/test_form_translations_fr.json"); - - FileUtils.copyFile(srcFile, dstFile); - - // Replay - ampathFormsTranslationsLoader.loadUnsafe(Collections.emptyList(), true); - - } - @Test public void load_shouldThrowGivenMissingFormFieldInFormTranslationsDef() throws Exception { // Setup diff --git a/pom.xml b/pom.xml index 5fad3c9d..c4207b40 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 2.1.1 2.2.0 2.3.6 - 2.4.0 + 2.4.5 2.5.5 ${openmrsVersion2.1} diff --git a/readme/ampathforms.md b/readme/ampathforms.md index d7329568..4ef0462f 100644 --- a/readme/ampathforms.md +++ b/readme/ampathforms.md @@ -67,5 +67,7 @@ The JSON source for these forms can be obtained from [AMPATH Form Builder](https **NOTE:** Like other form engines (and as a result of the form tooling), the unique identifier for a form is its name. As a result, the `uuid` field provided by the Form Builder is usually `"xxxx"` and not used. Instead, the form UUID is determined based on the form name and the form version. Any previous version of the form with the same name, however, will also be replaced with whatever form is loaded by Initializer. It is therefore not recommended to combine Initializer with another mechanism for loading forms into the system, e.g., by using the Form Builder directly. +**NOTE:** When an Ampath forms file is loaded, a new resource with the existing Ampath forms translations is created + #### Further examples: Please look at the test configuration folder for sample import files for all domains, see [here](../api/src/test/resources/testAppDataDir/configuration).