diff --git a/doc/release-notes/10476-display-on-create-field-option.md b/doc/release-notes/10476-display-on-create-field-option.md new file mode 100644 index 00000000000..e4a38e181a2 --- /dev/null +++ b/doc/release-notes/10476-display-on-create-field-option.md @@ -0,0 +1,6 @@ +New feature: Collection administrators can now configure which metadata fields appear during dataset creation through the `displayOnCreate` property, even when fields are not required. This provides greater control over metadata visibility and can help improve metadata completeness. + +- The feature is currently available through the API endpoint `/api/dataverses/{alias}/inputLevels` +- UI implementation will be available in a future release [#11221](https://github.com/IQSS/dataverse/issues/11221) + +For more information, see the [API Guide](https://guides.dataverse.org/en/latest/api/native-api.html#update-collection-input-levels) and issues [#10476](https://github.com/IQSS/dataverse/issues/10476) and [#11224](https://github.com/IQSS/dataverse/pull/11224). \ No newline at end of file diff --git a/doc/sphinx-guides/source/_static/api/dataset-schema.json b/doc/sphinx-guides/source/_static/api/dataset-schema.json index 34b8a1eeedb..85ea5a0d773 100644 --- a/doc/sphinx-guides/source/_static/api/dataset-schema.json +++ b/doc/sphinx-guides/source/_static/api/dataset-schema.json @@ -26,6 +26,9 @@ }, "typeName": { "type": "string" + }, + "displayOnCreate": { + "type": "boolean" } } } diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index c63eedbe8a4..34a7d55bef8 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -1116,20 +1116,27 @@ This endpoint expects a JSON with the following format:: { "datasetFieldTypeName": "datasetFieldTypeName1", "required": true, - "include": true + "include": true, + "displayOnCreate": null }, { "datasetFieldTypeName": "datasetFieldTypeName2", "required": true, - "include": true + "include": true, + "displayOnCreate": true } ] +.. note:: + Required fields will always be displayed regardless of their displayOnCreate setting, as this is necessary for dataset creation. + When displayOnCreate is null, the field's default display behavior is used. + Parameters: - ``datasetFieldTypeName``: Name of the metadata field - ``required``: Whether the field is required (boolean) - ``include``: Whether the field is included (boolean) +- ``displayOnCreate`` (optional): Whether the field is displayed during dataset creation, even when not required (boolean) .. code-block:: bash diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index 129f590ca75..32ce570ddaa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -941,6 +941,12 @@ private Predicate buildFieldPresentInDataversePredicate(Dataverse dataverse, boo criteriaBuilder.isTrue(datasetFieldTypeInputLevelJoin.get("required")) ); + // Predicate for displayOnCreate in input level + Predicate displayOnCreateInputLevelPredicate = criteriaBuilder.and( + criteriaBuilder.equal(datasetFieldTypeRoot, datasetFieldTypeInputLevelJoin.get("datasetFieldType")), + criteriaBuilder.isTrue(datasetFieldTypeInputLevelJoin.get("displayOnCreate")) + ); + // Create a subquery to check for the absence of a specific DataverseFieldTypeInputLevel. Subquery subquery = criteriaQuery.subquery(Long.class); Root subqueryRoot = subquery.from(DataverseFieldTypeInputLevel.class); @@ -963,10 +969,19 @@ private Predicate buildFieldPresentInDataversePredicate(Dataverse dataverse, boo // Otherwise, use an always-true predicate (conjunction). Predicate displayedOnCreatePredicate = onlyDisplayedOnCreate ? criteriaBuilder.or( - criteriaBuilder.or( + // 1. Field marked as displayOnCreate in input level + displayOnCreateInputLevelPredicate, + + // 2. Field without input level that is marked as displayOnCreate or required + criteriaBuilder.and( + hasNoInputLevelPredicate, + criteriaBuilder.or( criteriaBuilder.isTrue(datasetFieldTypeRoot.get("displayOnCreate")), fieldRequiredInTheInstallation + ) ), + + // 3. Field required by input level requiredAsInputLevelPredicate ) : criteriaBuilder.conjunction(); diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldType.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldType.java index 16adf8e36bc..e4ada80b05d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldType.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldType.java @@ -273,13 +273,18 @@ public void setValidationFormat(String validationFormat) { * Determines whether this field type is displayed in the form when creating * the Dataset (or only later when editing after the initial creation). */ - private boolean displayOnCreate; + @Column(name = "displayoncreate", nullable = true) + private Boolean displayOnCreate; - public boolean isDisplayOnCreate() { + public Boolean isDisplayOnCreate() { return displayOnCreate; } - public void setDisplayOnCreate(boolean displayOnCreate) { + public Boolean getDisplayOnCreate() { + return displayOnCreate; + } + + public void setDisplayOnCreate(Boolean displayOnCreate) { this.displayOnCreate = displayOnCreate; } diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index 09560d1b4c7..8258fb613d3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -1856,6 +1856,7 @@ private void updateDatasetFieldInputLevels() { if (dsf != null){ // Yes, call "setInclude" dsf.setInclude(oneDSFieldTypeInputLevel.isInclude()); + dsf.getDatasetFieldType().setDisplayOnCreate(oneDSFieldTypeInputLevel.isDisplayOnCreate()); // remove from hash mapDatasetFields.remove(oneDSFieldTypeInputLevel.getDatasetFieldType().getId()); } diff --git a/src/main/java/edu/harvard/iq/dataverse/Dataverse.java b/src/main/java/edu/harvard/iq/dataverse/Dataverse.java index 9bb8992e789..d2cb51d0072 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Dataverse.java +++ b/src/main/java/edu/harvard/iq/dataverse/Dataverse.java @@ -438,6 +438,12 @@ public boolean isDatasetFieldTypeInInputLevels(Long datasetFieldTypeId) { .anyMatch(inputLevel -> inputLevel.getDatasetFieldType().getId().equals(datasetFieldTypeId)); } + public boolean isDatasetFieldTypeDisplayOnCreateAsInputLevel(Long datasetFieldTypeId) { + return dataverseFieldTypeInputLevels.stream() + .anyMatch(inputLevel -> inputLevel.getDatasetFieldType().getId().equals(datasetFieldTypeId) + && inputLevel.isDisplayOnCreate()); + } + public Template getDefaultTemplate() { return defaultTemplate; } diff --git a/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevel.java b/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevel.java index a3425987bf8..27cb1e00cad 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevel.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevel.java @@ -58,14 +58,16 @@ public class DataverseFieldTypeInputLevel implements Serializable { private DatasetFieldType datasetFieldType; private boolean include; private boolean required; + private boolean displayOnCreate; public DataverseFieldTypeInputLevel () {} - public DataverseFieldTypeInputLevel (DatasetFieldType fieldType, Dataverse dataverse, boolean required, boolean include) { + public DataverseFieldTypeInputLevel (DatasetFieldType fieldType, Dataverse dataverse, boolean required, boolean include, boolean displayOnCreate) { this.datasetFieldType = fieldType; this.dataverse = dataverse; this.required = required; this.include = include; + this.displayOnCreate = displayOnCreate; } public Long getId() { @@ -115,6 +117,14 @@ public void setRequired(boolean required) { this.required = required; } + public boolean isDisplayOnCreate() { + return displayOnCreate; + } + + public void setDisplayOnCreate(boolean displayOnCreate) { + this.displayOnCreate = displayOnCreate; + } + @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set diff --git a/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevelServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevelServiceBean.java index 1bd290ecc4d..3b4601d173b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevelServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataverseFieldTypeInputLevelServiceBean.java @@ -104,7 +104,7 @@ public void delete(DataverseFieldTypeInputLevel dataverseFieldTypeInputLevel) { cache.invalidate(); } - public void deleteFacetsFor(Dataverse d) { + public void deleteDataverseFieldTypeInputLevelFor(Dataverse d) { em.createNamedQuery("DataverseFieldTypeInputLevel.removeByOwnerId") .setParameter("ownerId", d.getId()) .executeUpdate(); @@ -117,4 +117,13 @@ public void create(DataverseFieldTypeInputLevel dataverseFieldTypeInputLevel) { em.persist(dataverseFieldTypeInputLevel); } + public DataverseFieldTypeInputLevel save(DataverseFieldTypeInputLevel inputLevel) { + if (inputLevel.getId() == null) { + em.persist(inputLevel); + return inputLevel; + } else { + return em.merge(inputLevel); + } + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/DataversePage.java b/src/main/java/edu/harvard/iq/dataverse/DataversePage.java index 351d304bad3..1f8c3defa7e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataversePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataversePage.java @@ -627,44 +627,17 @@ public String save() { if (dataverse.isMetadataBlockRoot() && (mdb.isSelected() || mdb.isRequired())) { selectedBlocks.add(mdb); for (DatasetFieldType dsft : mdb.getDatasetFieldTypes()) { - // currently we don't allow input levels for setting an optional field as conditionally required - // so we skip looking at parents (which get set automatically with their children) - if (!dsft.isHasChildren() && dsft.isRequiredDV()) { - boolean addRequiredInputLevels = false; - boolean parentAlreadyAdded = false; + if (!dsft.isChild()) { + // Save input level for parent field + saveInputLevels(listDFTIL, dsft, dataverse); - if (!dsft.isHasParent() && dsft.isInclude()) { - addRequiredInputLevels = !dsft.isRequired(); - } - if (dsft.isHasParent() && dsft.getParentDatasetFieldType().isInclude()) { - addRequiredInputLevels = !dsft.isRequired() || !dsft.getParentDatasetFieldType().isRequired(); - } - - if (addRequiredInputLevels) { - listDFTIL.add(new DataverseFieldTypeInputLevel(dsft, dataverse,true, true)); - - //also add the parent as required (if it hasn't been added already) - // todo: review needed .equals() methods, then change this to use a Set, in order to simplify code - if (dsft.isHasParent()) { - DataverseFieldTypeInputLevel parentToAdd = new DataverseFieldTypeInputLevel(dsft.getParentDatasetFieldType(), dataverse, true, true); - for (DataverseFieldTypeInputLevel dataverseFieldTypeInputLevel : listDFTIL) { - if (dataverseFieldTypeInputLevel.getDatasetFieldType().getId() == parentToAdd.getDatasetFieldType().getId()) { - parentAlreadyAdded = true; - break; - } - } - if (!parentAlreadyAdded) { - // Only add the parent once. There's a UNIQUE (dataverse_id, datasetfieldtype_id) - // constraint on the dataversefieldtypeinputlevel table we need to avoid. - listDFTIL.add(parentToAdd); - } - } + // Handle child fields + if (dsft.isHasChildren()) { + for (DatasetFieldType child : dsft.getChildDatasetFieldTypes()) { + saveInputLevels(listDFTIL, child, dataverse); + } } } - if ((!dsft.isHasParent() && !dsft.isInclude()) - || (dsft.isHasParent() && !dsft.getParentDatasetFieldType().isInclude())) { - listDFTIL.add(new DataverseFieldTypeInputLevel(dsft, dataverse,false, false)); - } } } } @@ -1030,27 +1003,11 @@ private void refreshAllMetadataBlocks() { for (DatasetFieldType dsft : mdb.getDatasetFieldTypes()) { if (!dsft.isChild()) { - DataverseFieldTypeInputLevel dsfIl = dataverseFieldTypeInputLevelService.findByDataverseIdDatasetFieldTypeId(dataverseIdForInputLevel, dsft.getId()); - if (dsfIl != null) { - dsft.setRequiredDV(dsfIl.isRequired()); - dsft.setInclude(dsfIl.isInclude()); - } else { - dsft.setRequiredDV(dsft.isRequired()); - dsft.setInclude(true); - } + loadInputLevels(dsft, dataverseIdForInputLevel); dsft.setOptionSelectItems(resetSelectItems(dsft)); if (dsft.isHasChildren()) { for (DatasetFieldType child : dsft.getChildDatasetFieldTypes()) { - DataverseFieldTypeInputLevel dsfIlChild = dataverseFieldTypeInputLevelService.findByDataverseIdDatasetFieldTypeId(dataverseIdForInputLevel, child.getId()); - if (dsfIlChild != null) { - child.setRequiredDV(dsfIlChild.isRequired()); - child.setInclude(dsfIlChild.isInclude()); - } else { - // in the case of conditionally required (child = true, parent = false) - // we set this to false; i.e this is the default "don't override" value - child.setRequiredDV(child.isRequired() && dsft.isRequired()); - child.setInclude(true); - } + loadInputLevels(child, dataverseIdForInputLevel); child.setOptionSelectItems(resetSelectItems(child)); } } @@ -1061,6 +1018,22 @@ private void refreshAllMetadataBlocks() { setAllMetadataBlocks(retList); } + private void loadInputLevels(DatasetFieldType dsft, Long dataverseIdForInputLevel) { + DataverseFieldTypeInputLevel dsfIl = dataverseFieldTypeInputLevelService + .findByDataverseIdDatasetFieldTypeId(dataverseIdForInputLevel, dsft.getId()); + + if (dsfIl != null) { + dsft.setRequiredDV(dsfIl.isRequired()); + dsft.setInclude(dsfIl.isInclude()); + dsft.setDisplayOnCreate(dsfIl.isDisplayOnCreate()); + } else { + // If there is no input level, use the default values + dsft.setRequiredDV(dsft.isRequired()); + dsft.setInclude(true); + dsft.setDisplayOnCreate(false); + } + } + public void validateAlias(FacesContext context, UIComponent toValidate, Object value) { if (!StringUtils.isEmpty((String) value)) { String alias = (String) value; @@ -1337,4 +1310,57 @@ public Set> getPidProviderOptions() { } return options; } + + public void updateDisplayOnCreate(Long mdbId, Long dsftId, boolean currentValue) { + for (MetadataBlock mdb : allMetadataBlocks) { + if (mdb.getId().equals(mdbId)) { + for (DatasetFieldType dsft : mdb.getDatasetFieldTypes()) { + if (dsft.getId().equals(dsftId)) { + // Update value in memory + dsft.setDisplayOnCreate(!currentValue); + + // Update or create input level + DataverseFieldTypeInputLevel existingLevel = dataverseFieldTypeInputLevelService + .findByDataverseIdDatasetFieldTypeId(dataverse.getId(), dsftId); + + if (existingLevel != null) { + existingLevel.setDisplayOnCreate(!currentValue); + dataverseFieldTypeInputLevelService.save(existingLevel); + } else { + DataverseFieldTypeInputLevel newLevel = new DataverseFieldTypeInputLevel( + dsft, + dataverse, + dsft.isRequiredDV(), + true, // default include + !currentValue // new value of displayOnCreate + ); + dataverseFieldTypeInputLevelService.save(newLevel); + } + } + } + } + } + } + + private void saveInputLevels(List listDFTIL, DatasetFieldType dsft, Dataverse dataverse) { + // If the field already has an input level, update it + DataverseFieldTypeInputLevel existingLevel = dataverseFieldTypeInputLevelService + .findByDataverseIdDatasetFieldTypeId(dataverse.getId(), dsft.getId()); + + if (existingLevel != null) { + existingLevel.setDisplayOnCreate(dsft.isDisplayOnCreate()); + existingLevel.setInclude(dsft.isInclude()); + existingLevel.setRequired(dsft.isRequiredDV()); + listDFTIL.add(existingLevel); + } else if (dsft.isInclude() || dsft.isDisplayOnCreate() || dsft.isRequiredDV()) { + // Only create new input level if there is any specific configuration + listDFTIL.add(new DataverseFieldTypeInputLevel( + dsft, + dataverse, + dsft.isRequiredDV(), + dsft.isInclude(), + dsft.isDisplayOnCreate() + )); + } + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java index f81266ded90..c56bd2f2956 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java @@ -952,17 +952,22 @@ public String getCollectionDatasetSchema(String dataverseAlias, Map childrenRequired = new ArrayList<>(); List childrenAllowed = new ArrayList<>(); if (dsft.isHasChildren()) { @@ -971,9 +976,8 @@ public String getCollectionDatasetSchema(String dataverseAlias, Map> map = new HashMap<>(); map.put("required", childrenRequired); map.put("allowed", childrenAllowed); schemaChildMap.put(dsft.getName(), map); } + if(dsft.isRequiredDV()){ requiredDSFT.add(dsft); } } } - } String reqMDBNames = ""; List hasReqFields = new ArrayList<>(); String retval = datasetSchemaPreface; + + // Build list of metadata blocks with required fields for (MetadataBlock mdb : selectedBlocks) { for (DatasetFieldType dsft : requiredDSFT) { if (dsft.getMetadataBlock().equals(mdb)) { @@ -1010,9 +1017,11 @@ public String getCollectionDatasetSchema(String dataverseAlias, Map0){ + if (countMDB > 0) { retval += ","; } retval += getCustomMDBSchema(mdb, requiredDSFT); @@ -1020,44 +1029,56 @@ public String getCollectionDatasetSchema(String dataverseAlias, Map requiredDSFT){ String retval = ""; boolean mdbHasReqField = false; int numReq = 0; List requiredThisMDB = new ArrayList<>(); + List allFieldsThisMDB = new ArrayList<>(mdb.getDatasetFieldTypes()); - for (DatasetFieldType dsft : requiredDSFT ){ - + // First collect all required fields for this metadata block + for (DatasetFieldType dsft : requiredDSFT) { if(dsft.getMetadataBlock().equals(mdb)){ numReq++; mdbHasReqField = true; requiredThisMDB.add(dsft); } } - if (mdbHasReqField){ - retval += startOfMDB.replace("blockName", mdb.getName()); - - retval += minItemsTemplate.replace("numMinItems", Integer.toString(requiredThisMDB.size())); - int count = 0; - for (DatasetFieldType dsft:requiredThisMDB ){ - count++; - String reqValImp = reqValTemplate.replace("reqFieldTypeName", dsft.getName()); - if (count < requiredThisMDB.size()){ - retval += reqValImp + "\n"; - } else { - reqValImp = StringUtils.substring(reqValImp, 0, reqValImp.length() - 1); - retval += reqValImp+ "\n"; - retval += endOfReqVal; - } - } + + // Start building the schema for this metadata block + retval += startOfMDB.replace("blockName", mdb.getName()); + // Add minItems constraint only if there are required fields + if (mdbHasReqField) { + retval += minItemsTemplate.replace("numMinItems", Integer.toString(requiredThisMDB.size())); + + // Add contains validation for each required field + int count = 0; + for (DatasetFieldType dsft : requiredThisMDB) { + count++; + String reqValImp = reqValTemplate.replace("reqFieldTypeName", dsft.getName()); + if (count < requiredThisMDB.size()) { + retval += reqValImp + "\n"; + } else { + reqValImp = StringUtils.substring(reqValImp, 0, reqValImp.length() - 1); + retval += reqValImp + "\n"; + retval += endOfReqVal; + } + } + } else { + // If no required fields, just close the items definition + retval += "\n \"items\": {\n" + + " \"$ref\": \"#/$defs/field\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"required\": [\"fields\"]\n" + + " }"; } return retval; @@ -1135,6 +1156,9 @@ static String getBaseSchemaStringFromFile(String pathToJsonFile) { " },\n" + " \"typeName\": {\n" + " \"type\": \"string\"\n" + + " },\n" + + " \"displayOnCreate\": {\n" + + " \"type\": \"boolean\"\n" + " }\n" + " }\n" + " }\n" + diff --git a/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java b/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java index 0fd7c2efbc7..ea0eb1aeaa2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java +++ b/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java @@ -102,7 +102,8 @@ public void setDatasetFieldTypes(List datasetFieldTypes) { public boolean isDisplayOnCreate() { for (DatasetFieldType dsfType : datasetFieldTypes) { - if (dsfType.isDisplayOnCreate()) { + Boolean displayOnCreate = dsfType.isDisplayOnCreate(); + if (displayOnCreate != null && displayOnCreate) { return true; } } diff --git a/src/main/java/edu/harvard/iq/dataverse/MetadataBlockServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/MetadataBlockServiceBean.java index 1e2a34f5472..f5bddf3fc79 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MetadataBlockServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/MetadataBlockServiceBean.java @@ -54,29 +54,66 @@ public List listMetadataBlocksDisplayedOnCreate(Dataverse ownerDa CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(MetadataBlock.class); Root metadataBlockRoot = criteriaQuery.from(MetadataBlock.class); Join datasetFieldTypeJoin = metadataBlockRoot.join("datasetFieldTypes"); - Predicate displayOnCreatePredicate = criteriaBuilder.isTrue(datasetFieldTypeJoin.get("displayOnCreate")); - + if (ownerDataverse != null) { Root dataverseRoot = criteriaQuery.from(Dataverse.class); - Join datasetFieldTypeInputLevelJoin = dataverseRoot.join("dataverseFieldTypeInputLevels", JoinType.LEFT); + Join datasetFieldTypeInputLevelJoin = + dataverseRoot.join("dataverseFieldTypeInputLevels", JoinType.LEFT); + + // Subquery to check if the input level exists + Subquery inputLevelSubquery = criteriaQuery.subquery(Long.class); + Root subqueryRoot = inputLevelSubquery.from(DataverseFieldTypeInputLevel.class); + inputLevelSubquery.select(criteriaBuilder.literal(1L)) + .where( + criteriaBuilder.equal(subqueryRoot.get("dataverse"), dataverseRoot), + criteriaBuilder.equal(subqueryRoot.get("datasetFieldType"), datasetFieldTypeJoin) + ); + // Predicate for displayOnCreate in the input level + Predicate displayOnCreateInputLevelPredicate = criteriaBuilder.and( + datasetFieldTypeInputLevelJoin.get("datasetFieldType").in(metadataBlockRoot.get("datasetFieldTypes")), + criteriaBuilder.isNotNull(datasetFieldTypeInputLevelJoin.get("displayOnCreate")), + criteriaBuilder.isTrue(datasetFieldTypeInputLevelJoin.get("displayOnCreate"))); + + // Predicate for required fields Predicate requiredPredicate = criteriaBuilder.and( - datasetFieldTypeInputLevelJoin.get("datasetFieldType").in(metadataBlockRoot.get("datasetFieldTypes")), - criteriaBuilder.isTrue(datasetFieldTypeInputLevelJoin.get("required"))); + datasetFieldTypeInputLevelJoin.get("datasetFieldType").in(metadataBlockRoot.get("datasetFieldTypes")), + criteriaBuilder.isTrue(datasetFieldTypeInputLevelJoin.get("required"))); + + // Predicate for default displayOnCreate (when there is no input level) + Predicate defaultDisplayOnCreatePredicate = criteriaBuilder.and( + criteriaBuilder.not(criteriaBuilder.exists(inputLevelSubquery)), + criteriaBuilder.or( + criteriaBuilder.isTrue(datasetFieldTypeJoin.get("displayOnCreate")), + criteriaBuilder.isTrue(datasetFieldTypeJoin.get("required")) + )); - Predicate unionPredicate = criteriaBuilder.or(displayOnCreatePredicate, requiredPredicate); + Predicate unionPredicate = criteriaBuilder.or( + displayOnCreateInputLevelPredicate, + requiredPredicate, + defaultDisplayOnCreatePredicate + ); criteriaQuery.where(criteriaBuilder.and( - criteriaBuilder.equal(dataverseRoot.get("id"), ownerDataverse.getId()), - metadataBlockRoot.in(dataverseRoot.get("metadataBlocks")), - unionPredicate + criteriaBuilder.equal(dataverseRoot.get("id"), ownerDataverse.getId()), + metadataBlockRoot.in(dataverseRoot.get("metadataBlocks")), + unionPredicate )); } else { - criteriaQuery.where(displayOnCreatePredicate); + // When ownerDataverse is null, we need to include fields that are either displayOnCreate=true OR required=true + Predicate displayOnCreatePredicate = criteriaBuilder.isTrue(datasetFieldTypeJoin.get("displayOnCreate")); + Predicate requiredPredicate = criteriaBuilder.isTrue(datasetFieldTypeJoin.get("required")); + + // We also need to ensure that fields from linked metadata blocks are included + Predicate linkedFieldsPredicate = criteriaBuilder.and( + criteriaBuilder.isNotNull(datasetFieldTypeJoin.get("id")), + criteriaBuilder.or(displayOnCreatePredicate, requiredPredicate) + ); + + criteriaQuery.where(linkedFieldsPredicate); } criteriaQuery.select(metadataBlockRoot).distinct(true); - TypedQuery typedQuery = em.createQuery(criteriaQuery); - return typedQuery.getResultList(); + return em.createQuery(criteriaQuery).getResultList(); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/TemplatePage.java b/src/main/java/edu/harvard/iq/dataverse/TemplatePage.java index 44070dcbb41..94ab9e70330 100644 --- a/src/main/java/edu/harvard/iq/dataverse/TemplatePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/TemplatePage.java @@ -166,11 +166,16 @@ private void updateDatasetFieldInputLevels(){ } for (DatasetField dsf: template.getFlatDatasetFields()){ - DataverseFieldTypeInputLevel dsfIl = dataverseFieldTypeInputLevelService.findByDataverseIdDatasetFieldTypeId(dvIdForInputLevel, dsf.getDatasetFieldType().getId()); - if (dsfIl != null){ + DataverseFieldTypeInputLevel dsfIl = dataverseFieldTypeInputLevelService.findByDataverseIdDatasetFieldTypeId( + dvIdForInputLevel, + dsf.getDatasetFieldType().getId() + ); + if (dsfIl != null) { dsf.setInclude(dsfIl.isInclude()); + dsf.getDatasetFieldType().setDisplayOnCreate(dsfIl.isDisplayOnCreate()); } else { dsf.setInclude(true); + dsf.getDatasetFieldType().setDisplayOnCreate(false); } } } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java b/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java index cbb0f4ffcfd..f29387aeb56 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java @@ -551,7 +551,7 @@ public static String getDataverseLangDirectory() { */ @POST @Path("/setDisplayOnCreate") - public Response setDisplayOnCreate(@QueryParam("datasetFieldType") String datasetFieldTypeIn, @QueryParam("setDisplayOnCreate") boolean setDisplayOnCreateIn) { + public Response setDisplayOnCreate(@QueryParam("datasetFieldType") String datasetFieldTypeIn, @QueryParam("setDisplayOnCreate") Boolean setDisplayOnCreateIn) { DatasetFieldType dft = datasetFieldService.findByName(datasetFieldTypeIn); if (dft == null) { return error(Status.NOT_FOUND, "Cound not find a DatasetFieldType by looking up " + datasetFieldTypeIn); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 18c8cfac61a..d677ced2ffe 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -803,13 +803,14 @@ private List parseInputLevels(JsonArray inputLevel boolean required = inputLevel.getBoolean("required"); boolean include = inputLevel.getBoolean("include"); + boolean displayOnCreate = inputLevel.getBoolean("displayOnCreate", false); if (required && !include) { String errorMessage = MessageFormat.format(BundleUtil.getStringFromBundle("dataverse.inputlevels.error.cannotberequiredifnotincluded"), datasetFieldTypeName); throw new WrappedResponse(badRequest(errorMessage)); } - newInputLevels.add(new DataverseFieldTypeInputLevel(datasetFieldType, dataverse, required, include)); + newInputLevels.add(new DataverseFieldTypeInputLevel(datasetFieldType, dataverse, required, include, displayOnCreate)); } return newInputLevels; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractWriteDataverseCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractWriteDataverseCommand.java index 2a72485d821..8227572da3b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractWriteDataverseCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractWriteDataverseCommand.java @@ -102,10 +102,10 @@ private void processFacets(CommandContext ctxt) { private void processInputLevels(CommandContext ctxt) { if (inputLevels != null) { if (inputLevels.isEmpty()) { - ctxt.fieldTypeInputLevels().deleteFacetsFor(dataverse); + ctxt.fieldTypeInputLevels().deleteDataverseFieldTypeInputLevelFor(dataverse); } else { dataverse.addInputLevelsMetadataBlocksIfNotPresent(inputLevels); - ctxt.fieldTypeInputLevels().deleteFacetsFor(dataverse); + ctxt.fieldTypeInputLevels().deleteDataverseFieldTypeInputLevelFor(dataverse); inputLevels.forEach(inputLevel -> { inputLevel.setDataverse(dataverse); ctxt.fieldTypeInputLevels().create(inputLevel); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseInputLevelsCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseInputLevelsCommand.java index b9b08992919..cc2c525e8f6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseInputLevelsCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseInputLevelsCommand.java @@ -2,6 +2,7 @@ import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.DataverseFieldTypeInputLevel; +import edu.harvard.iq.dataverse.MetadataBlock; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; @@ -28,8 +29,18 @@ public Dataverse execute(CommandContext ctxt) throws CommandException { if (inputLevelList == null || inputLevelList.isEmpty()) { throw new CommandException("Error while updating dataverse input levels: Input level list cannot be null or empty", this); } + + if (!dataverse.isMetadataBlockRoot()) { + Dataverse root = ctxt.dataverses().findRootDataverse(); + if (root != null) { + List inheritedBlocks = new ArrayList<>(root.getMetadataBlocks()); + dataverse.setMetadataBlocks(inheritedBlocks); + dataverse.setMetadataBlockRoot(true); + } + } + dataverse.addInputLevelsMetadataBlocksIfNotPresent(inputLevelList); - dataverse.setMetadataBlockRoot(true); + return ctxt.engine().submit(new UpdateDataverseCommand(dataverse, null, null, getRequest(), inputLevelList)); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/BriefJsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/BriefJsonPrinter.java index c16a46a1765..85bfe49846c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/BriefJsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/BriefJsonPrinter.java @@ -24,14 +24,14 @@ public JsonObjectBuilder json( DatasetVersion dsv ) { } public JsonObjectBuilder json( MetadataBlock blk ) { - return ( blk==null ) - ? null - : jsonObjectBuilder().add("id", blk.getId()) - .add("displayName", blk.getDisplayName()) - .add("displayOnCreate", blk.isDisplayOnCreate()) - .add("name", blk.getName()) - ; - } + if (blk == null) return null; + Boolean displayOnCreate = blk.isDisplayOnCreate(); + return jsonObjectBuilder().add("id", blk.getId()) + .add("displayName", blk.getDisplayName()) + .add("displayOnCreate", displayOnCreate == null ? false : displayOnCreate) + .add("name", blk.getName()) + ; + } public JsonObjectBuilder json( Workflow wf ) { return jsonObjectBuilder().add("id", wf.getId()) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index fdebbffc584..53184caeaf4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -74,10 +74,15 @@ public class JsonPrinter { @EJB static DatasetFieldServiceBean datasetFieldService; - - public static void injectSettingsService(SettingsServiceBean ssb, DatasetFieldServiceBean dfsb) { + + @EJB + static DataverseFieldTypeInputLevelServiceBean datasetFieldInputLevelService; + + public static void injectSettingsService(SettingsServiceBean ssb, DatasetFieldServiceBean dfsb, DataverseFieldTypeInputLevelServiceBean dfils) { settingsService = ssb; datasetFieldService = dfsb; + datasetFieldInputLevelService = dfils; + } public JsonPrinter() { @@ -654,44 +659,39 @@ public static JsonObjectBuilder json(MetadataBlock metadataBlock, boolean printO JsonObjectBuilder jsonObjectBuilder = jsonObjectBuilder() .add("id", metadataBlock.getId()) .add("name", metadataBlock.getName()) - .add("displayName", metadataBlock.getDisplayName()) - .add("displayOnCreate", metadataBlock.isDisplayOnCreate()); - - List datasetFieldTypesList; - - if (ownerDataverse != null) { - datasetFieldTypesList = datasetFieldService.findAllInMetadataBlockAndDataverse( - metadataBlock, ownerDataverse, printOnlyDisplayedOnCreateDatasetFieldTypes, datasetType); - } else { - datasetFieldTypesList = printOnlyDisplayedOnCreateDatasetFieldTypes - ? datasetFieldService.findAllDisplayedOnCreateInMetadataBlock(metadataBlock) - : metadataBlock.getDatasetFieldTypes(); - } + .add("displayName", metadataBlock.getDisplayName()); + + Boolean displayOnCreate = metadataBlock.isDisplayOnCreate(); + jsonObjectBuilder.add("displayOnCreate", displayOnCreate == null ? false : displayOnCreate); + List datasetFieldTypesList = metadataBlock.getDatasetFieldTypes(); Set datasetFieldTypes = filterOutDuplicateDatasetFieldTypes(datasetFieldTypesList); JsonObjectBuilder fieldsBuilder = Json.createObjectBuilder(); - - Predicate isNoChild = element -> element.isChild() == false; - List childLessList = metadataBlock.getDatasetFieldTypes().stream().filter(isNoChild).toList(); - Set datasetFieldTypesNoChildSorted = new TreeSet<>(childLessList); - - for (DatasetFieldType datasetFieldType : datasetFieldTypesNoChildSorted) { - - Long datasetFieldTypeId = datasetFieldType.getId(); - boolean requiredAsInputLevelInOwnerDataverse = ownerDataverse != null && ownerDataverse.isDatasetFieldTypeRequiredAsInputLevel(datasetFieldTypeId); - boolean includedAsInputLevelInOwnerDataverse = ownerDataverse != null && ownerDataverse.isDatasetFieldTypeIncludedAsInputLevel(datasetFieldTypeId); - boolean isNotInputLevelInOwnerDataverse = ownerDataverse != null && !ownerDataverse.isDatasetFieldTypeInInputLevels(datasetFieldTypeId); - DatasetFieldType parentDatasetFieldType = datasetFieldType.getParentDatasetFieldType(); - boolean isRequired = parentDatasetFieldType == null ? datasetFieldType.isRequired() : parentDatasetFieldType.isRequired(); - boolean displayCondition = printOnlyDisplayedOnCreateDatasetFieldTypes - ? (datasetFieldType.isDisplayOnCreate() || isRequired || requiredAsInputLevelInOwnerDataverse) - : ownerDataverse == null || includedAsInputLevelInOwnerDataverse || isNotInputLevelInOwnerDataverse; - if (displayCondition) { - fieldsBuilder.add(datasetFieldType.getName(), json(datasetFieldType, ownerDataverse)); + for (DatasetFieldType datasetFieldType : datasetFieldTypes) { + if (!datasetFieldType.isChild()) { + Boolean fieldDisplayOnCreate = datasetFieldType.isDisplayOnCreate(); + Boolean fieldRequired = datasetFieldType.isRequired(); + Boolean fieldExcludedDisplayOnCreateCollection = false; + Boolean fieldIncludedDisplayOnCreateCollection = false; + Boolean fieldExcludedCollection = false; + + if (ownerDataverse != null){ + DataverseFieldTypeInputLevel custom = datasetFieldInputLevelService.findByDataverseIdDatasetFieldTypeId(ownerDataverse.getId(), datasetFieldType.getId() ); + if(custom != null){ + fieldIncludedDisplayOnCreateCollection = custom.isDisplayOnCreate(); + fieldExcludedDisplayOnCreateCollection = !custom.isDisplayOnCreate(); + fieldExcludedCollection = !custom.isInclude(); + } + } + + if ((!printOnlyDisplayedOnCreateDatasetFieldTypes && !fieldExcludedCollection) || (fieldDisplayOnCreate != null && fieldDisplayOnCreate && !fieldExcludedDisplayOnCreateCollection) + || fieldRequired || fieldIncludedDisplayOnCreateCollection ) { + fieldsBuilder.add(datasetFieldType.getName(), json(datasetFieldType, ownerDataverse)); + } } } @@ -726,7 +726,8 @@ public static JsonObjectBuilder json(DatasetFieldType fld, Dataverse ownerDatave JsonObjectBuilder fieldsBld = jsonObjectBuilder(); fieldsBld.add("name", fld.getName()); fieldsBld.add("displayName", fld.getDisplayName()); - fieldsBld.add("displayOnCreate", fld.isDisplayOnCreate()); + Boolean displayOnCreate = fld.isDisplayOnCreate(); + fieldsBld.add("displayOnCreate", displayOnCreate == null ? false : displayOnCreate); fieldsBld.add("title", fld.getTitle()); fieldsBld.add("type", fld.getFieldType().toString()); fieldsBld.add("typeClass", typeClassString(fld)); @@ -1459,6 +1460,7 @@ public static JsonArrayBuilder jsonDataverseFieldTypeInputLevels(List
+ jsf:rendered="#{((editMode == 'METADATA' or dsf.datasetFieldType.isDisplayOnCreate() or !dsf.isEmpty() or dsf.required) and dsf.include) or (!datasetPage and dsf.include)}"> diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetTypesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetTypesIT.java index 7c73498dead..9c4ad6ffbbd 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetTypesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetTypesIT.java @@ -14,6 +14,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; +import org.junit.jupiter.api.AfterAll; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -36,6 +37,12 @@ public static void setUpClass() { ensureDatasetTypeIsPresent(INSTRUMENT, apiToken); } + @AfterAll + public static void afterClass() { + // Other tests make assertions about displayOnCreate so revert it back to how it was. + UtilIT.setDisplayOnCreate("astroInstrument", false); + } + private static void ensureDatasetTypeIsPresent(String datasetType, String apiToken) { Response getDatasetType = UtilIT.getDatasetType(datasetType); getDatasetType.prettyPrint(); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index 4bc60302724..1da6707ed2c 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -1082,7 +1082,7 @@ public void testListMetadataBlocks() { // notesText has displayOnCreate=true but has include=false, so should not be retrieved String notesTextCitationMetadataField = listMetadataBlocksResponse.then().extract().path(String.format("data[%d].fields.notesText.name", citationMetadataBlockIndex)); - assertNotNull(notesTextCitationMetadataField); + assertNull(notesTextCitationMetadataField); // producerName is a conditionally required field, so should not be retrieved String producerNameCitationMetadataField = listMetadataBlocksResponse.then().extract().path(String.format("data[%d].fields.producerName.name", citationMetadataBlockIndex)); @@ -1944,4 +1944,119 @@ public void testDeleteFeaturedItems() { .body("message", equalTo("Can't find dataverse with identifier='thisDataverseDoesNotExist'")) .statusCode(NOT_FOUND.getStatusCode()); } + + @Test + public void testUpdateInputLevelDisplayOnCreate() { + Response createUserResponse = UtilIT.createRandomUser(); + String apiToken = UtilIT.getApiTokenFromResponse(createUserResponse); + + Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); + createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode()); + String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + + // Configure metadata blocks - disable inherit from root and set specific blocks + Response setMetadataBlocksResponse = UtilIT.setMetadataBlocks( + dataverseAlias, + Json.createArrayBuilder().add("socialscience"), + apiToken); + setMetadataBlocksResponse.then().assertThat() + .statusCode(OK.getStatusCode()); + + // Verify initial state + Response listMetadataBlocks = UtilIT.listMetadataBlocks(dataverseAlias, false, true, apiToken); + listMetadataBlocks.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.size()", equalTo(1)) + .body("data[0].name", equalTo("socialscience")); + + // Update displayOnCreate for a field + Response updateResponse = UtilIT.updateDataverseInputLevelDisplayOnCreate( + dataverseAlias, "unitOfAnalysis", true, apiToken); + updateResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.inputLevels[0].displayOnCreate", equalTo(true)) + .body("data.inputLevels[0].datasetFieldTypeName", equalTo("unitOfAnalysis")); + } + + @Test + public void testUpdateInputLevelDisplayOnCreateOverride() { + Response createUserResponse = UtilIT.createRandomUser(); + String apiToken = UtilIT.getApiTokenFromResponse(createUserResponse); + + Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); + createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode()); + String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + + // Configure metadata blocks - disable inherit from root and set specific blocks + Response setMetadataBlocksResponse = UtilIT.setMetadataBlocks( + dataverseAlias, + Json.createArrayBuilder().add("citation"), + apiToken); + setMetadataBlocksResponse.then().assertThat() + .statusCode(OK.getStatusCode()); + + + Response listMetadataBlocks = UtilIT.listMetadataBlocks(dataverseAlias, false, true, apiToken); + listMetadataBlocks.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.size()", equalTo(1)) + .body("data[0].name", equalTo("citation")); + + + // Update displayOnCreate for a field + + + Response updateResponse = UtilIT.updateDataverseInputLevelDisplayOnCreate( + dataverseAlias, "notesText", false, apiToken); + updateResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.inputLevels[0].displayOnCreate", equalTo(false)) + .body("data.inputLevels[0].datasetFieldTypeName", equalTo("notesText")); + + Response listMetadataBlocksResponse = UtilIT.listMetadataBlocks(dataverseAlias, true, true, apiToken); + listMetadataBlocksResponse.prettyPrint(); + int expectedNumberOfMetadataFields = 9; // 28 - 18 - notes child duplicates + int expectedOnlyDisplayedOnCreateNumberOfMetadataBlocks = 1; + listMetadataBlocksResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data[0].fields", not(equalTo(null))) + .body("data[0].fields.size()", equalTo(expectedNumberOfMetadataFields)) + .body("data[0].displayName", equalTo("Citation Metadata")) + .body("data.size()", equalTo(expectedOnlyDisplayedOnCreateNumberOfMetadataBlocks)) + .body("data[0].fields.author.childFields.size()", is(4)); + //set it back just in case + updateResponse = UtilIT.updateDataverseInputLevelDisplayOnCreate( + dataverseAlias, "notesText", true, apiToken); + updateResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.inputLevels[0].displayOnCreate", equalTo(true)) + .body("data.inputLevels[0].datasetFieldTypeName", equalTo("notesText")); + + updateResponse = UtilIT.updateDataverseInputLevelDisplayOnCreate( + dataverseAlias, "subtitle", true, apiToken); + updateResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.inputLevels[0].displayOnCreate", equalTo(true)) + .body("data.inputLevels[0].datasetFieldTypeName", equalTo("subtitle")); + + listMetadataBlocksResponse = UtilIT.listMetadataBlocks(dataverseAlias, true, true, apiToken); + listMetadataBlocksResponse.prettyPrint(); + expectedNumberOfMetadataFields = 11; // 28 - 18 + subtitle child duplicates + expectedOnlyDisplayedOnCreateNumberOfMetadataBlocks = 1; + listMetadataBlocksResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data[0].fields", not(equalTo(null))) + .body("data[0].fields.size()", equalTo(expectedNumberOfMetadataFields)) + .body("data[0].displayName", equalTo("Citation Metadata")) + .body("data.size()", equalTo(expectedOnlyDisplayedOnCreateNumberOfMetadataBlocks)) + .body("data[0].fields.author.childFields.size()", is(4)); + + updateResponse = UtilIT.updateDataverseInputLevelDisplayOnCreate( + dataverseAlias, "subtitle", false, apiToken); + updateResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.inputLevels[0].displayOnCreate", equalTo(false)) + .body("data.inputLevels[0].datasetFieldTypeName", equalTo("subtitle")); + + } } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index cecd4397479..db8a0255017 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -4599,7 +4599,7 @@ static Response deleteDataverseFeaturedItems(String dataverseAlias, String apiTo .header(API_TOKEN_HTTP_HEADER, apiToken) .delete("/api/dataverses/" + dataverseAlias + "/featuredItems"); } - + public static Response deleteDatasetFiles(String datasetId, JsonArray fileIds, String apiToken) { String path = String.format("/api/datasets/%s/deleteFiles", datasetId); return given() @@ -4608,4 +4608,21 @@ public static Response deleteDatasetFiles(String datasetId, JsonArray fileIds, S .body(fileIds.toString()) .put(path); } + + public static Response updateDataverseInputLevelDisplayOnCreate(String dataverseAlias, String fieldTypeName, boolean displayOnCreate, String apiToken) { + JsonArrayBuilder inputLevelsArrayBuilder = Json.createArrayBuilder(); + JsonObjectBuilder inputLevel = Json.createObjectBuilder() + .add("datasetFieldTypeName", fieldTypeName) + .add("required", false) + .add("include", true) + .add("displayOnCreate", displayOnCreate); + + inputLevelsArrayBuilder.add(inputLevel); + + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .body(inputLevelsArrayBuilder.build().toString()) + .contentType(ContentType.JSON) + .put("/api/dataverses/" + dataverseAlias + "/inputLevels"); + } } diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseCommandTest.java index 7e84cf19e6b..24c349d34d1 100644 --- a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseCommandTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseCommandTest.java @@ -136,9 +136,23 @@ public Future indexDataverse(Dataverse dataverse) { public void create(DataverseFieldTypeInputLevel dataverseFieldTypeInputLevel) { createdDftils.add( dataverseFieldTypeInputLevel ); } + + @Override + public DataverseFieldTypeInputLevel save(DataverseFieldTypeInputLevel dataverseFieldTypeInputLevel) { + createdDftils.add( dataverseFieldTypeInputLevel ); + return dataverseFieldTypeInputLevel; + } + + @Override + public DataverseFieldTypeInputLevel findByDataverseIdDatasetFieldTypeId(Long dataverseId, Long datasetFieldTypeId) { + DataverseFieldTypeInputLevel dfil = new DataverseFieldTypeInputLevel(); + return dfil; + } + + @Override - public void deleteFacetsFor(Dataverse d) { + public void deleteDataverseFieldTypeInputLevelFor(Dataverse d) { dftilsDeleted = true; } }; diff --git a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java index 1987307637c..9d37a554820 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java @@ -207,7 +207,8 @@ public void testDatasetContactOutOfBoxNoPrivacy() { SettingsServiceBean nullServiceBean = null; DatasetFieldServiceBean nullDFServiceBean = null; - JsonPrinter.injectSettingsService(nullServiceBean, nullDFServiceBean); + DataverseFieldTypeInputLevelServiceBean nullDFILServiceBean = null; + JsonPrinter.injectSettingsService(nullServiceBean, nullDFServiceBean, nullDFILServiceBean); JsonObject jsonObject = JsonPrinter.json(block, fields).build(); assertNotNull(jsonObject); @@ -249,7 +250,8 @@ public void testDatasetContactWithPrivacy() { fields.add(datasetContactField); DatasetFieldServiceBean nullDFServiceBean = null; - JsonPrinter.injectSettingsService(new MockSettingsSvc(), nullDFServiceBean); + DataverseFieldTypeInputLevelServiceBean nullDFILServiceBean = null; + JsonPrinter.injectSettingsService(new MockSettingsSvc(), nullDFServiceBean, nullDFILServiceBean); JsonObject jsonObject = JsonPrinter.json(block, fields).build(); assertNotNull(jsonObject); @@ -300,7 +302,8 @@ public void testDatasetFieldTypesWithChildren() { block.setDatasetFieldTypes(datasetFieldTypes); DatasetFieldServiceBean nullDFServiceBean = null; - JsonPrinter.injectSettingsService(new MockSettingsSvc(), nullDFServiceBean); + DataverseFieldTypeInputLevelServiceBean nullDFILServiceBean = null; + JsonPrinter.injectSettingsService(new MockSettingsSvc(), nullDFServiceBean, nullDFILServiceBean); JsonObject jsonObject = JsonPrinter.json(block).build(); assertNotNull(jsonObject);