From aaf613a4b996de2702fc53ec641220e248796e82 Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Thu, 20 Mar 2025 11:12:31 -0400 Subject: [PATCH 1/3] allow for tag replacement --- .../11292-update-tabular-tags-with-replace.md | 4 ++++ doc/sphinx-guides/source/api/native-api.rst | 11 +++++++++++ .../java/edu/harvard/iq/dataverse/api/Files.java | 6 +++++- .../edu/harvard/iq/dataverse/api/FilesIT.java | 16 ++++++++++++++++ .../edu/harvard/iq/dataverse/api/UtilIT.java | 6 +++++- 5 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 doc/release-notes/11292-update-tabular-tags-with-replace.md diff --git a/doc/release-notes/11292-update-tabular-tags-with-replace.md b/doc/release-notes/11292-update-tabular-tags-with-replace.md new file mode 100644 index 00000000000..5eb518233e0 --- /dev/null +++ b/doc/release-notes/11292-update-tabular-tags-with-replace.md @@ -0,0 +1,4 @@ +### File Categories and Tabular Tags can now be replaced + +Previously the API Post /files/{id}/metadata/tabularTags could only add new tags to the tabular tags list. Now with the query parameter ?replace=true the list of tags will be replaced. + diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index e4fc2e1baff..17e77e3b132 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -4605,6 +4605,8 @@ Updating File Tabular Tags Updates the tabular tags for an existing tabular file where ``ID`` is the database id of the file to update or ``PERSISTENT_ID`` is the persistent id (DOI or Handle) of the file. Requires a ``jsonString`` expressing the tabular tag names. +The list of "tabularTags" will be added to the existing list unless the optional ``replace=true`` query parameter is included. The inclusion of this parameter will cause the pre-existing tags to be deleted and the "tabularTags" to be added. Sending an empty list will remove all of the pre-existing tags. + The JSON representation of tabular tags (``tags.json``) looks like this:: { @@ -4634,6 +4636,9 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST \ "http://demo.dataverse.org/api/files/24/metadata/tabularTags" \ -H "Content-type:application/json" --upload-file tags.json + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST \ + "http://demo.dataverse.org/api/files/24/metadata/tabularTags?replace=true" \ + -H "Content-type:application/json" --upload-file tags.json A curl example using a ``PERSISTENT_ID`` @@ -4647,6 +4652,9 @@ A curl example using a ``PERSISTENT_ID`` curl -H "X-Dataverse-key:$API_TOKEN" -X POST \ "$SERVER_URL/api/files/:persistentId/metadata/tabularTags?persistentId=$PERSISTENT_ID" \ -H "Content-type:application/json" --upload-file $FILE_PATH + curl -H "X-Dataverse-key:$API_TOKEN" -X POST \ + "$SERVER_URL/api/files/:persistentId/metadata/tabularTags?persistentId=$PERSISTENT_ID&replace=true" \ + -H "Content-type:application/json" --upload-file $FILE_PATH The fully expanded example above (without environment variables) looks like this: @@ -4655,6 +4663,9 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST \ "https://demo.dataverse.org/api/files/:persistentId/metadata/tabularTags?persistentId=doi:10.5072/FK2/AAA000" \ -H "Content-type:application/json" --upload-file tags.json + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST \ + "https://demo.dataverse.org/api/files/:persistentId/metadata/tabularTags?persistentId=doi:10.5072/FK2/AAA000&replace=true" \ + -H "Content-type:application/json" --upload-file tags.json Note that the specified tabular tags must be valid. The supported tags are: diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 89e4e6d7f97..f6b906fb421 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -1,5 +1,6 @@ package edu.harvard.iq.dataverse.api; +import com.google.api.client.util.Lists; import com.google.gson.Gson; import com.google.gson.JsonObject; import edu.harvard.iq.dataverse.*; @@ -918,7 +919,7 @@ public Response setFileCategories(@Context ContainerRequestContext crc, @PathPar @AuthRequired @Path("{id}/metadata/tabularTags") @Produces(MediaType.APPLICATION_JSON) - public Response setFileTabularTags(@Context ContainerRequestContext crc, @PathParam("id") String dataFileId, String jsonBody) { + public Response setFileTabularTags(@Context ContainerRequestContext crc, @PathParam("id") String dataFileId, String jsonBody, @QueryParam("replace") boolean replaceData) { return response(req -> { DataFile dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(dataFileId))); if (!dataFile.isTabularData()) { @@ -928,6 +929,9 @@ public Response setFileTabularTags(@Context ContainerRequestContext crc, @PathPa try (StringReader stringReader = new StringReader(jsonBody)) { jsonObject = Json.createReader(stringReader).readObject(); JsonArray requestedTabularTagsJson = jsonObject.getJsonArray("tabularTags"); + if (replaceData) { + dataFile.setTags(Lists.newArrayList()); + } for (JsonValue jsonValue : requestedTabularTagsJson) { JsonString jsonString = (JsonString) jsonValue; try { diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index d7b07f4497c..530fea9511f 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -8,6 +8,7 @@ import java.util.logging.Logger; import edu.harvard.iq.dataverse.api.auth.ApiKeyAuthMechanism; +import org.assertj.core.util.Lists; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; import io.restassured.path.json.JsonPath; @@ -2717,6 +2718,21 @@ public void testSetFileTabularTags() throws InterruptedException { setFileTabularTagsResponse = UtilIT.setFileTabularTags(nonTabularFileId, apiToken, List.of(testInvalidTabularTag)); setFileTabularTagsResponse.then().assertThat().statusCode(BAD_REQUEST.getStatusCode()); + + // Test set with replaceData = true to show that the list is replaced and not added to + setFileTabularTagsResponse = UtilIT.setFileTabularTags(tabularFileId, apiToken, List.of("Geospatial"), true); + setFileTabularTagsResponse.then().assertThat().statusCode(OK.getStatusCode()); + getFileDataResponse = UtilIT.getFileData(tabularFileId, apiToken); + actualTabularTagsCount = getFileDataResponse.jsonPath().getList("data.dataFile.tabularTags").size(); + assertEquals(1, actualTabularTagsCount); + // Test clear all tags by passing empty list + setFileTabularTagsResponse = UtilIT.setFileTabularTags(tabularFileId, apiToken, Lists.emptyList(), true); + setFileTabularTagsResponse.then().assertThat().statusCode(OK.getStatusCode()); + getFileDataResponse = UtilIT.getFileData(tabularFileId, apiToken); + getFileDataResponse.prettyPrint(); + getFileDataResponse.then().assertThat() + .body("data.dataFile", not(hasItem("tabularTags"))) + .statusCode(OK.getStatusCode()); } @Test 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 5ee78a29582..973ee5b11e8 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -4191,17 +4191,21 @@ static Response setFileCategories(String dataFileId, String apiToken, List tabularTags) { + return setFileTabularTags(dataFileId, apiToken, tabularTags, null); + } + static Response setFileTabularTags(String dataFileId, String apiToken, List tabularTags, Boolean replaceData) { JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder(); for (String tabularTag : tabularTags) { jsonArrayBuilder.add(tabularTag); } + String replace = replaceData != null ? "?replace=" + replaceData : ""; JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder(); jsonObjectBuilder.add("tabularTags", jsonArrayBuilder); String jsonString = jsonObjectBuilder.build().toString(); return given() .header(API_TOKEN_HTTP_HEADER, apiToken) .body(jsonString) - .post("/api/files/" + dataFileId + "/metadata/tabularTags"); + .post("/api/files/" + dataFileId + "/metadata/tabularTags" + replace); } static Response deleteFileInDataset(Integer fileId, String apiToken) { From 4ae708957c916e0d0823f5b7c4570964774689bf Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:06:33 -0400 Subject: [PATCH 2/3] Update doc/release-notes/11292-update-tabular-tags-with-replace.md Co-authored-by: Philip Durbin --- doc/release-notes/11292-update-tabular-tags-with-replace.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/release-notes/11292-update-tabular-tags-with-replace.md b/doc/release-notes/11292-update-tabular-tags-with-replace.md index 5eb518233e0..88565ad4ae8 100644 --- a/doc/release-notes/11292-update-tabular-tags-with-replace.md +++ b/doc/release-notes/11292-update-tabular-tags-with-replace.md @@ -1,4 +1,5 @@ ### File Categories and Tabular Tags can now be replaced -Previously the API Post /files/{id}/metadata/tabularTags could only add new tags to the tabular tags list. Now with the query parameter ?replace=true the list of tags will be replaced. +Previously the API POST /files/{id}/metadata/tabularTags could only add new tags to the tabular tags list. Now with the query parameter ?replace=true the list of tags will be replaced. +See also [the guides](https://dataverse-guide--11359.org.readthedocs.build/en/11359/api/native-api.html#updating-file-tabular-tags), #11292, and #11359. From d519a088c630dc5534814a8e0734fc92c8eb581f Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:07:53 -0400 Subject: [PATCH 3/3] Update doc/release-notes/11292-update-tabular-tags-with-replace.md Co-authored-by: Philip Durbin --- doc/release-notes/11292-update-tabular-tags-with-replace.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release-notes/11292-update-tabular-tags-with-replace.md b/doc/release-notes/11292-update-tabular-tags-with-replace.md index 88565ad4ae8..12068b8bfb5 100644 --- a/doc/release-notes/11292-update-tabular-tags-with-replace.md +++ b/doc/release-notes/11292-update-tabular-tags-with-replace.md @@ -1,4 +1,4 @@ -### File Categories and Tabular Tags can now be replaced +### Tabular Tags can now be replaced Previously the API POST /files/{id}/metadata/tabularTags could only add new tags to the tabular tags list. Now with the query parameter ?replace=true the list of tags will be replaced.