Skip to content

Commit

Permalink
Closes #2554: Generalize Suggestion box to support controlled vocabul…
Browse files Browse the repository at this point in the history
…ary values

Co-authored-by: Sylwester Niewczas <[email protected]>
Co-authored-by: Krzysztof Mądry <[email protected]>
Co-authored-by: Filipe Dias Lewandowski
Signed-off-by: Daniel Korbel <[email protected]>
  • Loading branch information
3 people committed Sep 23, 2024
1 parent be984a2 commit 99ec619
Show file tree
Hide file tree
Showing 18 changed files with 37 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3098,4 +3098,5 @@ geobox.invalid.longitude=The longitude must be a number between -180 and 180.
geobox.invalid.latitude=The latitude must be a number between -90 and 90.
geobox.invalid.latitude.relation=The north latitude must be greater or equal to the south latitude.

validation.nonunique=The field must have a unique value.
validation.nonunique=The field must have a unique value.
validation.value.not.allowed.in.controlled.vocabulary=Value "{0}" is not allowed. Please select one from the list.
Original file line number Diff line number Diff line change
Expand Up @@ -3049,4 +3049,5 @@ geobox.invalid.longitude=D\u0142ugo\u015B\u0107 geograficzna musi zawiera\u0107
geobox.invalid.latitude=Szeroko\u015B\u0107 geograficzna musi zawiera\u0107 si\u0119 mi\u0119dzy -90 a 90.
geobox.invalid.latitude.relation=Szeroko\u015B\u0107 p\u00F3\u0142nocna musi by\u0107 nie mniejsza od po\u0142udniowej.

validation.nonunique=Pole musi mie\u0107 tylko jedn\u0105 warto\u015B\u0107.
validation.nonunique=Pole musi mie\u0107 tylko jedn\u0105 warto\u015B\u0107.
validation.value.not.allowed.in.controlled.vocabulary=Warto\u015B\u0107 "{0}" jest niedozwolona. Wybierz jedn\u0105 z listy.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import java.util.List;

/**
* @author skraffmiller, Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
* @author skraffmiller
*/
@Stateless
public class ControlledVocabularyValueServiceBean implements java.io.Serializable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
import java.util.Optional;
import java.util.stream.Collectors;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
public class SuggestionInputFieldRenderer implements InputFieldRenderer {
private static final String VALUE_HEADER_KEY_FORMAT = "datasetfieldtype.%s.suggestionDisplay.valueHeader";
private static final String DETAILS_HEADER_KEY_FORMAT = "datasetfieldtype.%s.suggestionDisplay.detailsHeader";
Expand All @@ -32,13 +29,13 @@ public class SuggestionInputFieldRenderer implements InputFieldRenderer {

// -------------------- CONSTRUCTORS --------------------

protected SuggestionInputFieldRenderer() {
public SuggestionInputFieldRenderer() {
}

/**
* Constructs renderer with support for suggestions.
*/
protected SuggestionInputFieldRenderer(
public SuggestionInputFieldRenderer(
SuggestionHandler suggestionHandler,
Map<String, String> datasetFieldTypeToSuggestionFilterMapping,
SuggestionDisplayType suggestionDisplayType,
Expand Down Expand Up @@ -121,6 +118,7 @@ public List<Suggestion> processSuggestionQuery(DatasetField datasetField, String
public List<Suggestion> createSuggestions(DatasetField datasetField, String query) {

Map<String, String> suggestionFilteredFields = new HashMap<>();

if (!datasetFieldTypeToSuggestionFilterMapping.isEmpty()) {
if(suggestionHandler.isDependentOnSiblings()) {
suggestionFilteredFields = findFilterValuesInSiblings(datasetField, datasetFieldTypeToSuggestionFilterMapping);
Expand All @@ -136,6 +134,21 @@ public List<Suggestion> createSuggestions(DatasetField datasetField, String quer
return suggestionHandler.generateSuggestions(suggestionFilteredFields, query);
}

// -------------------- PRIVATE --------------------

private Map<String, String> findFilterValuesInSiblings(DatasetField datasetField, Map<String, String> datasetFieldTypeToSuggestionFilterMapping) {
Map<String, String> filteredValues = datasetField.getDatasetFieldParent()
.getOrElseThrow(() -> new NullPointerException("datasetfield with type: " + datasetField.getTypeName() + " didn't have any parent required to generate suggestions"))
.getDatasetFieldsChildren().stream()
.filter(dsf -> datasetFieldTypeToSuggestionFilterMapping.containsKey(dsf.getTypeName()))
.map(dsf -> Tuple.of(
datasetFieldTypeToSuggestionFilterMapping.get(dsf.getTypeName()),
dsf.getFieldValue().getOrElse(StringUtils.EMPTY)))
.collect(Collectors.toMap(Tuple2::_1, Tuple2::_2));

return filteredValues.containsValue(StringUtils.EMPTY) ? new HashMap<>() : filteredValues;
}

private Map<String, String> getFilterValue(DatasetField datasetField) {
return datasetFieldTypeToSuggestionFilterMapping
.entrySet()
Expand All @@ -151,19 +164,4 @@ private Map<String, String> getFilterValue(DatasetField datasetField) {
// If no matching entry is found, return an empty map
.orElseGet(HashMap::new);
}

// -------------------- PRIVATE --------------------

private Map<String, String> findFilterValuesInSiblings(DatasetField datasetField, Map<String, String> datasetFieldTypeToSuggestionFilterMapping) {
Map<String, String> filteredValues = datasetField.getDatasetFieldParent()
.getOrElseThrow(() -> new NullPointerException("datasetfield with type: " + datasetField.getTypeName() + " didn't have any parent required to generate suggestions"))
.getDatasetFieldsChildren().stream()
.filter(dsf -> datasetFieldTypeToSuggestionFilterMapping.containsKey(dsf.getTypeName()))
.map(dsf -> Tuple.of(
datasetFieldTypeToSuggestionFilterMapping.get(dsf.getTypeName()),
dsf.getFieldValue().getOrElse(StringUtils.EMPTY)))
.collect(Collectors.toMap(Tuple2::_1, Tuple2::_2));

return filteredValues.containsValue(StringUtils.EMPTY) ? new HashMap<>() : filteredValues;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

/**
* This suggestion handler provides suggestions based on controlled vocabulary values.
*
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Stateless
public class ControlledVocabularySuggestionHandler implements SuggestionHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

import static java.util.stream.Collectors.toList;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Stateless
public class GrantAgencyAcronymSuggestionHandler implements SuggestionHandler {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

import static java.util.stream.Collectors.toList;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Stateless
public class GrantAgencySuggestionHandler implements SuggestionHandler {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

import static java.util.stream.Collectors.toList;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Stateless
public class GrantProgramSuggestionHandler implements SuggestionHandler {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Stateless
public class RorSuggestionHandler implements SuggestionHandler {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
import java.util.List;
import java.util.Map;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
public interface SuggestionHandler {

/**
Expand All @@ -18,7 +15,14 @@ public interface SuggestionHandler {
/**
* @return true if this handler is dependent on siblings input values.
* If it is dependant it will use other input values
* to filter out while generating suggestions
* to filter out while generating suggestions.
* Sibling means the group of inputs that shares common parent input.
* F.e.: when input grant is parent and have children as follow: grantAgency,
* grantRor, grantAcronym it means that whenever one of its children will have value
* it will be taken to filter out values during generating suggestions.
* Of course its need to be configured via <code>getAllowedFilters() method</code>
*
* @see this#getAllowedFilters()
*/
boolean isDependentOnSiblings();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.harvard.iq.dataverse.validation.field.validators;

import edu.harvard.iq.dataverse.ControlledVocabularyValueServiceBean;
import edu.harvard.iq.dataverse.common.BundleUtil;
import edu.harvard.iq.dataverse.persistence.dataset.ControlledVocabularyValue;
import edu.harvard.iq.dataverse.persistence.dataset.ValidatableField;
import edu.harvard.iq.dataverse.validation.field.FieldValidationResult;
Expand All @@ -14,8 +15,6 @@
/**
* Validator for fields that should only contain values from a controlled vocabulary.
* The vocabulary is passed in through the parameters.
*
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Eager
@ApplicationScoped
Expand Down Expand Up @@ -45,8 +44,10 @@ public String getName() {
if(matchesFromDb.size() == 1 && matchesFromDb.get(0).getStrValue().equalsIgnoreCase(value)) {
return FieldValidationResult.ok();
} else {
return FieldValidationResult.invalid(field,
"Value '" + value + "' is not allowed. Please select one from the list");
return FieldValidationResult.invalid(
field,
BundleUtil.getStringFromBundle("validation.value.not.allowed.in.controlled.vocabulary", value)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
* @see edu.harvard.iq.dataverse.persistence.dataset.ValidatableField
* @see edu.harvard.iq.dataverse.persistence.dataset.DatasetField
* @see edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldType#getValidation()
*
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Eager
@ApplicationScoped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
* @see edu.harvard.iq.dataverse.persistence.dataset.ValidatableField
* @see edu.harvard.iq.dataverse.persistence.dataset.DatasetField
* @see edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldType#getValidation()
*
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@Eager
@ApplicationScoped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class SuggestionInputFieldRendererTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
import static org.mockito.Mockito.when;
import static java.util.Collections.singletonList;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class ControlledVocabularySuggestionHandlerTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
class ControlledVocabularyValidatorTest {

@Mock
Expand Down Expand Up @@ -71,6 +68,6 @@ void testValidateValue_failure() {
testValue, testField, new HashMap<>(), new HashMap<>());

assertFalse(result.isOk());
assertEquals("Value 'InvalidValue' is not allowed. Please select one from the list", result.getMessage());
assertEquals("Value \"InvalidValue\" is not allowed. Please select one from the list.", result.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
import org.mockito.MockedStatic;
import org.mockito.junit.MockitoJUnitRunner;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
@RunWith(MockitoJUnitRunner.class)
public class RequiredByValueDependantFieldValidatorTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

import static org.assertj.core.api.Assertions.assertThat;

/**
* @author Filipe Dias Lewandowski, Krzysztof Mądry, Daniel Korbel, Sylwester Niewczas
*/
public class RequiredDependantFieldValidatorTest {

private final RequiredDependantFieldValidator validator = new RequiredDependantFieldValidator();
Expand Down

0 comments on commit 99ec619

Please sign in to comment.