Skip to content

Commit

Permalink
Added support to reload the Ampath Forms translations (#273)
Browse files Browse the repository at this point in the history
  • Loading branch information
icrc-loliveira authored Jul 19, 2024
1 parent 6449d0b commit e728e4a
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 59 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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<String, Object> 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
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,28 @@

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;
import org.codehaus.jackson.map.ObjectMapper;
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;

Expand All @@ -44,40 +46,42 @@ protected void load(File file) throws Exception {
String jsonTranslationsString = FileUtils.readFileToString(file, StandardCharsets.UTF_8.toString());
Map<String, Object> 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<String, Object> 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);

Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<openmrsVersion2.1>2.1.1</openmrsVersion2.1>
<openmrsVersion2.2>2.2.0</openmrsVersion2.2>
<openmrsVersion2.3>2.3.6</openmrsVersion2.3>
<openmrsVersion2.4>2.4.0</openmrsVersion2.4>
<openmrsVersion2.4>2.4.5</openmrsVersion2.4>
<openmrsVersion2.5>2.5.5</openmrsVersion2.5>

<openmrsPlatformVersion>${openmrsVersion2.1}</openmrsPlatformVersion>
Expand Down
2 changes: 2 additions & 0 deletions readme/ampathforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

0 comments on commit e728e4a

Please sign in to comment.