Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1784,12 +1784,24 @@ public void syncSharesAsync(ShareTreeCriteria criteria) {

private void doSave(Case caze, boolean handleChanges, CaseDataDto existingCaseDto, boolean syncShares) {
service.ensurePersisted(caze);
ensureDefaultCustomizableFieldValues(caze, existingCaseDto);
if (handleChanges) {
updateCaseVisitAssociations(existingCaseDto, caze);
onCaseChanged(existingCaseDto, caze, syncShares);
}
}

private void ensureDefaultCustomizableFieldValues(Case caze, CaseDataDto existingCaseDto) {
if (existingCaseDto == null || existingCaseDto.getUuid() == null) {
customizableFieldValueService.ensureDefaultValuesForEntity(caze.getUuid(), CustomizableFieldContext.CASE);
}

epiDataFacade.ensureDefaultCustomizableFieldValues(
caze.getEpiData(),
existingCaseDto != null ? existingCaseDto.getEpiData() : null,
caze.getDisease());
}

private void updateCaseVisitAssociations(CaseDataDto existingCase, Case caze) {

if (existingCase != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ public ContactDto save(ContactDto dto, boolean handleChanges, boolean handleCase

Contact entity = fillOrBuildEntity(dto, existingContact, checkChangeDate);
service.ensurePersisted(entity);
epiDataFacade.ensureDefaultCustomizableFieldValues(
entity.getEpiData(),
existingContactDto != null ? existingContactDto.getEpiData() : null,
entity.getDisease());

if (existingContact == null && featureConfigurationFacade.isTaskGenerationFeatureEnabled(TaskType.CONTACT_INVESTIGATION)) {
createInvestigationTask(entity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ protected CustomizableFieldMetadataDto toDto(CustomizableFieldMetadata source) {
return target;
}

private static CustomizableFieldVisibilityRestrictions parseVisibilityRestrictions(String json) {
public static CustomizableFieldVisibilityRestrictions parseVisibilityRestrictions(String json) {
if (StringUtils.isBlank(json)) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
package de.symeda.sormas.backend.customizablefield;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.criteria.CriteriaBuilder;
Expand All @@ -27,10 +30,14 @@
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;

import de.symeda.sormas.api.common.DeletableEntityType;
import de.symeda.sormas.api.common.DeletionDetails;
import de.symeda.sormas.api.customizablefield.CustomizableFieldContext;
import de.symeda.sormas.api.customizablefield.CustomizableFieldValueDto;
import de.symeda.sormas.api.customizablefield.CustomizableFieldVisibilityContext;
import de.symeda.sormas.api.customizablefield.CustomizableFieldVisibilityRestrictions;
import de.symeda.sormas.backend.common.AbstractCoreAdoService;
import de.symeda.sormas.backend.common.AbstractDomainObject;
import de.symeda.sormas.backend.common.DeletableAdo;
Expand All @@ -42,6 +49,9 @@
@LocalBean
public class CustomizableFieldValueService extends AbstractCoreAdoService<CustomizableFieldValue, CustomizableFieldValueJoins> {

@EJB
private CustomizableFieldMetadataService customizableFieldMetadataService;

public CustomizableFieldValueService() {
super(CustomizableFieldValue.class, DeletableEntityType.CUSTOMIZABLE_FIELD_VALUE);
}
Expand Down Expand Up @@ -98,6 +108,59 @@ public void saveEntityValues(
}
}

public void ensureDefaultValuesForEntity(String entityUuid, CustomizableFieldContext contextClass) {
ensureDefaultValuesForEntity(entityUuid, contextClass, null);
}

/**
* Ensures default values for customizable fields for the given entity.
* <p>
* Only fields that are visible for the given visibility context will have their default values
* persisted. Fields with specific visibility restrictions will be skipped
* if the visiblity context is not matched.
*
* @param entityUuid
* the UUID of the entity
* @param contextClass
* the context class for the customizable fields
* @param visibilityContext
* the visibility context to check against field restrictions; may be null to skip
* visibility checks
*/
public void ensureDefaultValuesForEntity(
String entityUuid,
CustomizableFieldContext contextClass,
CustomizableFieldVisibilityContext visibilityContext) {
if (StringUtils.isBlank(entityUuid) || contextClass == null) {
return;
}

Map<CustomizableFieldMetadata, CustomizableFieldValue> existing = getValuesForEntity(entityUuid, contextClass);
Set<String> existingMetadataUuids = new HashSet<>();
for (CustomizableFieldMetadata metadata : existing.keySet()) {
existingMetadataUuids.add(metadata.getUuid());
}

for (CustomizableFieldMetadata metadata : customizableFieldMetadataService.getActiveFieldsForContext(contextClass)) {
if (existingMetadataUuids.contains(metadata.getUuid()) || StringUtils.isBlank(metadata.getDefaultValue())) {
continue;
}

// Skip fields that are not visible for the given context
if (visibilityContext != null && metadata.getVisibilityRestrictions() != null && !metadata.getVisibilityRestrictions().isBlank()) {
CustomizableFieldVisibilityRestrictions metadataVisibilityRestrictions =
CustomizableFieldMetadataFacadeEjb.parseVisibilityRestrictions(metadata.getVisibilityRestrictions());
if (!metadataVisibilityRestrictions.matches(visibilityContext)) {
continue;
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

CustomizableFieldValue value = createNewValue(metadata, entityUuid, contextClass);
value.setValue(metadata.getDefaultValue());
ensurePersisted(value);
}
}

Comment thread
raulbob marked this conversation as resolved.
public void deleteValuesForEntity(String entityUuid, CustomizableFieldContext contextClass) {
Map<CustomizableFieldMetadata, CustomizableFieldValue> values = getValuesForEntity(entityUuid, contextClass);
for (CustomizableFieldValue value : values.values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
import javax.ejb.LocalBean;
import javax.ejb.Stateless;

import de.symeda.sormas.api.Disease;
import de.symeda.sormas.api.activityascase.ActivityAsCaseDto;
import de.symeda.sormas.api.common.DeletionDetails;
import de.symeda.sormas.api.customizablefield.CustomizableFieldContext;
import de.symeda.sormas.api.customizablefield.CustomizableFieldVisibilityContext;
import de.symeda.sormas.api.epidata.EpiDataDto;
import de.symeda.sormas.api.epidata.EpiDataFacade;
import de.symeda.sormas.api.exposure.ExposureDto;
Expand Down Expand Up @@ -79,6 +81,35 @@ public void softDeleteCustomizableFieldValues(EpiData epiData, DeletionDetails d
}
}

public void ensureDefaultCustomizableFieldValues(EpiData epiData, EpiDataDto existingEpiData, Disease disease) {
if (epiData == null || epiData.getUuid() == null) {
return;
}

// Build visibility context from the provided disease
CustomizableFieldVisibilityContext visibilityContext = disease != null ? new CustomizableFieldVisibilityContext().withDisease(disease) : null;

if (existingEpiData == null || existingEpiData.getUuid() == null) {
customizableFieldValueService.ensureDefaultValuesForEntity(epiData.getUuid(), CustomizableFieldContext.EPIDATA, visibilityContext);
}

HashSet<String> existingExposureUuids = new HashSet<>();
if (existingEpiData != null && existingEpiData.getExposures() != null) {
for (ExposureDto existingExposure : existingEpiData.getExposures()) {
if (existingExposure.getUuid() != null) {
existingExposureUuids.add(existingExposure.getUuid());
}
}
}

for (Exposure exposure : epiData.getExposures()) {
if (exposure.getUuid() != null && !existingExposureUuids.contains(exposure.getUuid())) {
// Exposure inherits disease from parent EpiData's disease
customizableFieldValueService.ensureDefaultValuesForEntity(exposure.getUuid(), CustomizableFieldContext.EXPOSURE, visibilityContext);
}
}
}

public EpiData fillOrBuildEntity(EpiDataDto source, EpiData target, boolean checkChangeDate) {
if (source == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import de.symeda.sormas.api.caze.CaseClassification;
import de.symeda.sormas.api.caze.CaseDataDto;
import de.symeda.sormas.api.caze.InvestigationStatus;
import de.symeda.sormas.api.contact.ContactDto;
import de.symeda.sormas.api.customizablefield.CustomizableFieldContext;
import de.symeda.sormas.api.customizablefield.CustomizableFieldGroup;
import de.symeda.sormas.api.customizablefield.CustomizableFieldMetadataDto;
Expand Down Expand Up @@ -69,12 +70,7 @@ void testCaseRelatedCustomizableFields(CustomizableFieldContext context) {
CustomizableFieldMetadataFacade metadataFacade = getBean(CustomizableFieldMetadataFacadeEjb.CustomizableFieldMetadataFacadeEjbLocal.class);
CustomizableFieldValueFacade valueFacade = getBean(CustomizableFieldValueFacadeEjb.CustomizableFieldValueFacadeEjbLocal.class);

CustomizableFieldMetadataDto metadata = new CustomizableFieldMetadataDto();
metadata.setName("customField_" + context.name().toLowerCase());
metadata.setFieldType(CustomizableFieldType.TEXT);
metadata.setContextClass(context);
metadata.setUiGroup(CustomizableFieldGroup.getGroupsForContext(context).stream().findFirst().orElse(null));
metadata.setUiLinePosition(1);
CustomizableFieldMetadataDto metadata = buildMetadata(context, "customField_" + context.name().toLowerCase());

CustomizableFieldMetadataDto savedMetadata = metadataFacade.save(metadata);
assertThat(savedMetadata.getUuid(), is(notNullValue()));
Expand Down Expand Up @@ -114,6 +110,79 @@ void testCaseRelatedCustomizableFields(CustomizableFieldContext context) {
assertThat(values.get(savedMetadata).getValue(), is(equalTo("custom-value")));
}

@ParameterizedTest
@EnumSource(value = CustomizableFieldContext.class,
names = {
"CASE",
"EPIDATA",
"EXPOSURE" })
void testCaseRelatedDefaultValuesArePersistedOnCreate(CustomizableFieldContext context) {
CustomizableFieldMetadataFacade metadataFacade = getBean(CustomizableFieldMetadataFacadeEjb.CustomizableFieldMetadataFacadeEjbLocal.class);
CustomizableFieldValueFacade valueFacade = getBean(CustomizableFieldValueFacadeEjb.CustomizableFieldValueFacadeEjbLocal.class);

CustomizableFieldMetadataDto metadata = buildMetadata(context, "defaultField_" + context.name().toLowerCase());
metadata.setDefaultValue("default-" + context.name().toLowerCase());
CustomizableFieldMetadataDto savedMetadata = metadataFacade.save(metadata);

PersonDto person = creator.createPerson("Default", "Case", Sex.MALE, 1981, 2, 2);
CaseDataDto caze = creator.createCase(
surveillanceSupervisor.toReference(),
person.toReference(),
Disease.EVD,
CaseClassification.PROBABLE,
InvestigationStatus.PENDING,
new java.util.Date(),
rdcf);

if (context == CustomizableFieldContext.EXPOSURE) {
caze.getEpiData().getExposures().add(ExposureDto.build(ExposureType.TRAVEL));
caze = getCaseFacade().save(caze);
}

Map<CustomizableFieldMetadataDto, CustomizableFieldValueDto> values =
valueFacade.getValuesForEntity(getEntityUuidForContext(context, caze), context);

assertThat(values, hasKey(savedMetadata));
assertThat(values.get(savedMetadata).getValue(), is(equalTo(savedMetadata.getDefaultValue())));
}

@ParameterizedTest
@EnumSource(value = CustomizableFieldContext.class,
names = {
"EPIDATA",
"EXPOSURE" })
void testContactRelatedDefaultValuesArePersistedOnCreate(CustomizableFieldContext context) {
CustomizableFieldMetadataFacade metadataFacade = getBean(CustomizableFieldMetadataFacadeEjb.CustomizableFieldMetadataFacadeEjbLocal.class);
CustomizableFieldValueFacade valueFacade = getBean(CustomizableFieldValueFacadeEjb.CustomizableFieldValueFacadeEjbLocal.class);

CustomizableFieldMetadataDto metadata = buildMetadata(context, "contactDefaultField_" + context.name().toLowerCase());
metadata.setDefaultValue("contact-default-" + context.name().toLowerCase());
CustomizableFieldMetadataDto savedMetadata = metadataFacade.save(metadata);

PersonDto person = creator.createPerson("Default", "Contact", Sex.FEMALE, 1982, 3, 3);
ContactDto contact = creator.createContact(surveillanceSupervisor.toReference(), person.toReference(), Disease.EVD, dto -> {
if (context == CustomizableFieldContext.EXPOSURE) {
dto.getEpiData().getExposures().add(ExposureDto.build(ExposureType.TRAVEL));
}
});

Map<CustomizableFieldMetadataDto, CustomizableFieldValueDto> values =
valueFacade.getValuesForEntity(getEntityUuidForContext(context, contact), context);

assertThat(values, hasKey(savedMetadata));
assertThat(values.get(savedMetadata).getValue(), is(equalTo(savedMetadata.getDefaultValue())));
}

private CustomizableFieldMetadataDto buildMetadata(CustomizableFieldContext context, String name) {
CustomizableFieldMetadataDto metadata = new CustomizableFieldMetadataDto();
metadata.setName(name);
metadata.setFieldType(CustomizableFieldType.TEXT);
metadata.setContextClass(context);
metadata.setUiGroup(CustomizableFieldGroup.getGroupsForContext(context).stream().findFirst().orElse(null));
metadata.setUiLinePosition(1);
return metadata;
}

private String getEntityUuidForContext(CustomizableFieldContext context, CaseDataDto caze) {
switch (context) {
case CASE:
Expand All @@ -128,4 +197,17 @@ private String getEntityUuidForContext(CustomizableFieldContext context, CaseDat
throw new IllegalArgumentException("Unhandled context: " + context);
}
}

private String getEntityUuidForContext(CustomizableFieldContext context, ContactDto contact) {
switch (context) {
case EPIDATA:
return contact.getEpiData().getUuid();
case EXPOSURE:
return contact.getEpiData().getExposures() != null && !contact.getEpiData().getExposures().isEmpty()
? contact.getEpiData().getExposures().get(0).getUuid()
: null;
default:
throw new IllegalArgumentException("Unhandled context: " + context);
}
}
}
Loading
Loading