Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d6404b9
#11387 update command to allow for leaving input levels alone
sekmiller Aug 14, 2025
bf94ed4
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Aug 14, 2025
2788a6d
#11387 update test; cleanup
sekmiller Aug 15, 2025
08dfd98
#11387 fix test
sekmiller Aug 15, 2025
949b617
#11387 source format
sekmiller Aug 15, 2025
b55cc6c
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Aug 18, 2025
22c3b97
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Aug 19, 2025
6dd2309
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Aug 19, 2025
2644fc7
#11387 get actual index for test
sekmiller Aug 19, 2025
a9f7f07
#11387 fix get index for test
sekmiller Aug 19, 2025
04f6534
#11387 guard against differing json array in test
sekmiller Aug 20, 2025
e001ff0
#11387 more array testing fun
sekmiller Aug 20, 2025
7ebf41a
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Aug 25, 2025
8bc2724
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Aug 26, 2025
4cd7635
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 2, 2025
81c1e6b
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 3, 2025
1d5199b
Update native-api.rst
sekmiller Sep 3, 2025
35f2dd4
#11387 update tests from code review
sekmiller Sep 3, 2025
a966923
#11387 add release note.
sekmiller Sep 3, 2025
46a9ac2
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 3, 2025
b8c017f
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 4, 2025
5b4eab3
Update changelog.rst
sekmiller Sep 4, 2025
0f13340
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 4, 2025
079c26f
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 5, 2025
c2f338d
Merge branch 'develop' into 11387-fix-inputLevel-api
stevenwinship Sep 10, 2025
ac935e8
update docs to explain how to delete input levels
stevenwinship Sep 10, 2025
6512eb3
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 26, 2025
7a32126
Merge branch 'develop' into 11387-fix-inputLevel-api
sekmiller Sep 30, 2025
9cc6b8e
Merge branch 'develop' into 11387-fix-inputLevel-api
ofahimIQSS Sep 30, 2025
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
3 changes: 3 additions & 0 deletions doc/release-notes/11387-modify-input-level-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Update Collection Input Level API Changed

- This endpoint will no longer delete the custom input levels previously modified for the given collection. In order to update a previously modified custom input level, it must be included in the JSON provided to the api.
2 changes: 1 addition & 1 deletion doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,7 @@ Update Collection Input Levels

Updates the dataset field type input levels in a collection.

Please note that this endpoint overwrites all the input levels of the collection page, so if you want to keep the existing ones, you will need to add them to the JSON request body.
Please note that this endpoint does not change previously updated input levels of the collection page, so if you want to keep the modify exisitng ones, you will need to include them in the JSON request body.

If one of the input levels corresponds to a dataset field type belonging to a metadata block that does not exist in the collection, the metadata block will be added to the collection.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,14 @@ private void processInputLevels(CommandContext ctxt) {
ctxt.fieldTypeInputLevels().deleteDataverseFieldTypeInputLevelFor(dataverse);
} else {
dataverse.addInputLevelsMetadataBlocksIfNotPresent(inputLevels);
ctxt.fieldTypeInputLevels().deleteDataverseFieldTypeInputLevelFor(dataverse);
//if levels not empty either create or update (handled by save - update when id not null create if null)
inputLevels.forEach(inputLevel -> {
DataverseFieldTypeInputLevel ftil = ctxt.fieldTypeInputLevels().findByDataverseIdDatasetFieldTypeId(dataverse.getId(), inputLevel.getDatasetFieldType().getId());
if(ftil != null){
inputLevel.setId(ftil.getId());
}
inputLevel.setDataverse(dataverse);
ctxt.fieldTypeInputLevels().create(inputLevel);
ctxt.fieldTypeInputLevels().save(inputLevel);
});
}
}
Expand Down
95 changes: 86 additions & 9 deletions src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,77 @@ public void testUpdateInputLevels() {
updateDataverseInputLevelsResponse.then().assertThat()
.body("message", equalTo("Error while updating dataverse input levels: Input level list cannot be null or empty"))
.statusCode(INTERNAL_SERVER_ERROR.getStatusCode());

//Add new types and see that previously changed ones remain as before... #11387
testInputLevelNames = new String[]{"subtitle", "relatedMaterial"};

testRequiredInputLevels = new boolean[] {false, false};
testIncludedInputLevels = new boolean[] {true, true};
boolean [] testDisplayOnCreate = new boolean[] {true, false};
updateDataverseInputLevelsResponse = UtilIT.updateDataverseInputLevels(dataverseAlias, testInputLevelNames, testRequiredInputLevels, testIncludedInputLevels, testDisplayOnCreate, apiToken);
updateDataverseInputLevelsResponse.prettyPrint();
int subtitleInputLevelIndex = -1;
int relatedMaterialInputLevelIndex = -1;
int i = 0;

while (updateDataverseInputLevelsResponse.then().extract().path(String.format("data.inputLevels[%d].datasetFieldTypeName", i)) != null){
actualInputLevelName = updateDataverseInputLevelsResponse.then().extract().path(String.format("data.inputLevels[%d].datasetFieldTypeName", i)).toString();
if (actualInputLevelName.equals("subtitle")){
subtitleInputLevelIndex = i;
}
if (actualInputLevelName.equals("relatedMaterial")){
relatedMaterialInputLevelIndex = i;
}
i++;
}

updateDataverseInputLevelsResponse.then().assertThat()
.body(String.format("data.inputLevels[%d].include", subtitleInputLevelIndex), equalTo(true))
.body(String.format("data.inputLevels[%d].required", subtitleInputLevelIndex), equalTo(false))
.body(String.format("data.inputLevels[%d].displayOnCreate", subtitleInputLevelIndex), equalTo(true))
.body(String.format("data.inputLevels[%d].include", relatedMaterialInputLevelIndex), equalTo(true))
.body(String.format("data.inputLevels[%d].required", relatedMaterialInputLevelIndex), equalTo(false))
.body(String.format("data.inputLevels[%d].displayOnCreate", relatedMaterialInputLevelIndex), equalTo(false))
.statusCode(OK.getStatusCode());

actualFieldTypeName1 = updateDataverseInputLevelsResponse.then().extract().path(String.format("data.inputLevels[%d].datasetFieldTypeName", subtitleInputLevelIndex));
actualFieldTypeName2 = updateDataverseInputLevelsResponse.then().extract().path(String.format("data.inputLevels[%d].datasetFieldTypeName", relatedMaterialInputLevelIndex));
assertNotEquals(actualFieldTypeName1, actualFieldTypeName2);
assertThat(testInputLevelNames, hasItemInArray(actualFieldTypeName1));
assertThat(testInputLevelNames, hasItemInArray(actualFieldTypeName2));


testInputLevelNames = new String[]{"subtitle", "otherReferences"};
testRequiredInputLevels = new boolean[] {false, false};
testIncludedInputLevels = new boolean[] {true, true};
testDisplayOnCreate = new boolean[] {false, true};

updateDataverseInputLevelsResponse = UtilIT.updateDataverseInputLevels(dataverseAlias, testInputLevelNames, testRequiredInputLevels, testIncludedInputLevels, testDisplayOnCreate, apiToken);
updateDataverseInputLevelsResponse.prettyPrint();

subtitleInputLevelIndex = 0;
i = 0;

while (updateDataverseInputLevelsResponse.then().extract().path(String.format("data.inputLevels[%d].datasetFieldTypeName", i)) != null) {
actualInputLevelName = updateDataverseInputLevelsResponse.then().extract().path(String.format("data.inputLevels[%d].datasetFieldTypeName", i)).toString();
if (actualInputLevelName.equals("subtitle")) {
subtitleInputLevelIndex = i;
}
i++;
}

//make sure subtitle got changed to false
updateDataverseInputLevelsResponse.then().assertThat()
.body(String.format("data.inputLevels[%d].displayOnCreate", subtitleInputLevelIndex), equalTo(false))
.statusCode(OK.getStatusCode());

//make superuser for cleanup
String username = UtilIT.getUsernameFromResponse(createUserResponse);
UtilIT.setSuperuserStatus(username, Boolean.TRUE);
Response deleteDataverse1Response = UtilIT.deleteDataverse(dataverseAlias, apiToken);
deleteDataverse1Response.prettyPrint();
assertEquals(200, deleteDataverse1Response.getStatusCode());

}

@Test
Expand Down Expand Up @@ -2256,12 +2327,17 @@ public void testUpdateInputLevelDisplayOnCreateOverride() {
.body("data.inputLevels[0].displayOnCreate", equalTo(true))
.body("data.inputLevels[0].datasetFieldTypeName", equalTo("notesText"));


updateResponse = UtilIT.updateDataverseInputLevelDisplayOnCreate(
dataverseAlias, "subtitle", true, apiToken);

String actualInputLevelName = updateResponse.then().extract().path("data.inputLevels[0].datasetFieldTypeName");
int subtitleInputLevelIndex = actualInputLevelName.equals("subtitle") ? 0 : 1;
updateResponse.prettyPrint();
updateResponse.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.inputLevels[0].displayOnCreate", equalTo(true))
.body("data.inputLevels[0].datasetFieldTypeName", equalTo("subtitle"));
.body(String.format("data.inputLevels[%d].displayOnCreate", subtitleInputLevelIndex), equalTo(true))
.body(String.format("data.inputLevels[%d].datasetFieldTypeName", subtitleInputLevelIndex), equalTo("subtitle"));

listMetadataBlocksResponse = UtilIT.listMetadataBlocks(dataverseAlias, true, true, apiToken);
listMetadataBlocksResponse.prettyPrint();
Expand All @@ -2274,14 +2350,15 @@ public void testUpdateInputLevelDisplayOnCreateOverride() {
.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 = UtilIT.updateDataverseInputLevelDisplayOnCreate(dataverseAlias, "subtitle", false, apiToken);
actualInputLevelName = updateResponse.then().extract().path("data.inputLevels[0].datasetFieldTypeName");
int subtitleIndex = actualInputLevelName.equals("subtitle") ? 0 : 1;
updateResponse.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.inputLevels[0].displayOnCreate", equalTo(false))
.body("data.inputLevels[0].datasetFieldTypeName", equalTo("subtitle"));
.body(String.format("data.inputLevels[%d].displayOnCreate", subtitleIndex), equalTo(false))
.body(String.format("data.inputLevels[%d].datasetFieldTypeName", subtitleIndex), equalTo("subtitle"))
.statusCode(OK.getStatusCode());

}

@Test
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -4582,13 +4582,33 @@ public static Response updateDataverseInputLevels(String dataverseAlias, String[
.contentType(ContentType.JSON)
.put("/api/dataverses/" + dataverseAlias + "/inputLevels");
}

public static Response updateDataverseInputLevels(String dataverseAlias, String[] inputLevelNames, boolean[] requiredInputLevels, boolean[] includedInputLevels, boolean[] displayOnCreate, String apiToken) {
JsonArrayBuilder inputLevelsArrayBuilder = Json.createArrayBuilder();
for (int i = 0; i < inputLevelNames.length; i++) {
inputLevelsArrayBuilder.add(createInputLevelObject(inputLevelNames[i], requiredInputLevels[i], includedInputLevels[i], displayOnCreate[i]));
}
return given()
.header(API_TOKEN_HTTP_HEADER, apiToken)
.body(inputLevelsArrayBuilder.build().toString())
.contentType(ContentType.JSON)
.put("/api/dataverses/" + dataverseAlias + "/inputLevels");
}

private static JsonObjectBuilder createInputLevelObject(String name, boolean required, boolean include) {
return Json.createObjectBuilder()
.add("datasetFieldTypeName", name)
.add("required", required)
.add("include", include);
}

private static JsonObjectBuilder createInputLevelObject(String name, boolean required, boolean include, boolean displayOnCreate) {
return Json.createObjectBuilder()
.add("datasetFieldTypeName", name)
.add("required", required)
.add("include", include)
.add("displayOnCreate", displayOnCreate);
}

public static Response getOpenAPI(String accept, String format) {
Response response = given()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public void testCustomOptions() throws CommandException {
i++;
}

assertTrue( dftilsDeleted );
// assertTrue( dftilsDeleted ); we no longer delete when adding new input levels to preserve previously created
for ( DataverseFieldTypeInputLevel dftil : createdDftils ) {
assertEquals( result, dftil.getDataverse() );
}
Expand Down