diff --git a/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/creator/ObservationCreator.java b/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/creator/ObservationCreator.java index 84a2e4747..11d126956 100644 --- a/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/creator/ObservationCreator.java +++ b/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/creator/ObservationCreator.java @@ -221,9 +221,7 @@ private Object getObservationValue(FormElement formElement, String answerValue, return handleDateValue(answerValue, errorMsgs, concept); case DateTime: return handleDateTimeValue(answerValue, errorMsgs, concept); - case Image: - case ImageV2: - case Video: + case Image, ImageV2, Video, Signature: return handleMediaValue(formElement, answerValue, errorMsgs, oldValue); case Subject: return individualService.getObservationValueForUpload(formElement, answerValue); diff --git a/avni-server-api/src/main/java/org/avni/server/service/EnhancedValidationService.java b/avni-server-api/src/main/java/org/avni/server/service/EnhancedValidationService.java index 58591fc73..1c599466e 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/EnhancedValidationService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/EnhancedValidationService.java @@ -151,7 +151,7 @@ private void validateAnswer(Concept question, FormElement formElement, Object va if (value == null || (value instanceof String && ((String) value).trim().isEmpty())) { return; } - + ConceptDataType dataType = ConceptDataType.valueOf(question.getDataType()); switch (dataType) { case Coded: @@ -182,8 +182,7 @@ private void validateAnswer(Concept question, FormElement formElement, Object va case PhoneNumber: validatePhoneNumberValue(question, value, errorMessages); break; - case Image: - case ImageV2: + case Image, ImageV2, Signature: validateImageValue(question, value, errorMessages); break; default: @@ -193,7 +192,7 @@ private void validateAnswer(Concept question, FormElement formElement, Object va private void validateCodedValue(Concept question, Object value, List errorMessages) { if (question.getConceptAnswers().stream().noneMatch(ans -> ans.getAnswerConcept().getUuid().equals(value))) { - errorMessages.add(String.format("Concept answer '%s' not found in Concept '%s' (%s)", + errorMessages.add(String.format("Concept answer '%s' not found in Concept '%s' (%s)", value, question.getName(), question.getUuid())); } } @@ -257,9 +256,9 @@ private void validateSubjectValue(Concept question, Object value, List e if (keyValues != null && keyValues.containsKey(KeyType.subjectTypeUUID)) { KeyValue keyValue = keyValues.get(KeyType.subjectTypeUUID); String subjectTypeUuid = keyValue.getValue().toString(); - + SubjectType subjectType = subjectTypeRepository.findByUuid(subjectTypeUuid); - + if (subjectType != null && individualRepository.findByLegacyIdOrUuidAndSubjectType((String) value, subjectType) == null) { errorMessages.add(formatErrorMessage(question, value)); } @@ -278,33 +277,33 @@ private void validateLocationValue(Concept question, Object value, List if (keyValues != null && keyValues.containsKey(KeyType.lowestAddressLevelTypeUUIDs)) { KeyValue keyValue = keyValues.get(KeyType.lowestAddressLevelTypeUUIDs); Object keyValueObj = keyValue.getValue(); - + if (keyValueObj instanceof List) { // Safe cast with instanceof check @SuppressWarnings("unchecked") List lowestLevelUuids = (List) keyValueObj; - + List lowestLevels = lowestLevelUuids.stream() .map(addressLevelTypeRepository::findByUuid) .filter(Objects::nonNull) .toList(); - + boolean isValid = lowestLevels.stream() .map(AddressLevelType::getAddressLevels) .flatMap(Collection::stream) .map(AddressLevel::getUuid) .toList() .contains(value); - + if (!isValid) { errorMessages.add(formatErrorMessage(question, value)); } } else { - errorMessages.add(String.format("Invalid lowest address level type for concept '%s'", + errorMessages.add(String.format("Invalid lowest address level type for concept '%s'", question.getName())); } } else { - errorMessages.add(String.format("Missing lowest address level type for concept '%s'", + errorMessages.add(String.format("Missing lowest address level type for concept '%s'", question.getName())); } } catch (Exception e) { @@ -330,8 +329,8 @@ private void validateImageValue(Concept question, Object value, List err URL dummyUrl = s3Service.generateMediaUploadUrl("dummy.jpg", HttpMethod.PUT); // Use non-deprecated constructor for URL URL imageUrl = new URI(value.toString()).toURL(); - - if (!Objects.equals(dummyUrl.getProtocol(), imageUrl.getProtocol()) || + + if (!Objects.equals(dummyUrl.getProtocol(), imageUrl.getProtocol()) || !Objects.equals(dummyUrl.getHost(), imageUrl.getHost())) { errorMessages.add(formatErrorMessage(question, value)); } @@ -362,7 +361,7 @@ private void splitQuestionGroupValueIfRequiredAndThenValidate(FormElement formEl validateCollectionItem(formElement, qGroupValue, formMapping, errorMessages); } } - + private void validateChildObservation(FormElement questionGroupFormElement, Map qGroupValueInstance, FormMapping formMapping, List errorMessages) { LinkedHashMap formElements = formMappingService.getEntityConceptMapForSpecificQuestionGroupFormElement(questionGroupFormElement, formMapping, INCLUDE_VOIDED_FORM_ELEMENTS); List observationRequests = qGroupValueInstance.entrySet().stream().map(this::createObservationRequest).collect(Collectors.toList()); @@ -379,14 +378,14 @@ private void validateChildObservation(FormElement questionGroupFormElement, Map< validateConceptValuesAreOfRequiredType(observationRequests, formElements, formMapping, errorMessages); } - + private void validateCollectionItem(FormElement formElement, Object item, FormMapping formMapping, List errorMessages) { if (item instanceof Map) { @SuppressWarnings("unchecked") Map valueMap = (Map) item; validateChildObservation(formElement, valueMap, formMapping, errorMessages); } else { - errorMessages.add(String.format("Invalid question group value type for concept '%s'", + errorMessages.add(String.format("Invalid question group value type for concept '%s'", formElement.getConcept().getName())); } } diff --git a/avni-server-data/src/main/java/org/avni/server/domain/ConceptDataType.java b/avni-server-data/src/main/java/org/avni/server/domain/ConceptDataType.java index c34ce77e6..1c5d151a5 100644 --- a/avni-server-data/src/main/java/org/avni/server/domain/ConceptDataType.java +++ b/avni-server-data/src/main/java/org/avni/server/domain/ConceptDataType.java @@ -25,11 +25,12 @@ public enum ConceptDataType { Audio, File, QuestionGroup, - Encounter; + Encounter, + Signature; private static final List dateTypes = Arrays.asList(Date, DateTime, Duration, Time); public static final List dashboardFilterSupportedTypes = Arrays.asList(Numeric, Text, Notes, Coded, Date, DateTime, Time, Id, Location); - public static final List mediaDataTypes = Arrays.asList(Image, ImageV2, Video, File, Audio); + public static final List mediaDataTypes = Arrays.asList(Image, ImageV2, Video, File, Audio, Signature); public static final List multiSelectTypes = Arrays.asList(Coded, Subject, Image, ImageV2, Video, File, Encounter); public static boolean dateType(String dataType) {