Skip to content

Commit

Permalink
Merge branch '9852-files-api-deaccessioned-datasets' of github.com:IQ…
Browse files Browse the repository at this point in the history
…SS/dataverse into 9958-dataset-files-size
  • Loading branch information
GPortas committed Oct 3, 2023
2 parents 47da5a4 + 122bbd6 commit b76576d
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 21 deletions.
13 changes: 8 additions & 5 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1020,9 +1020,9 @@ Usage example:
Please note that both filtering and ordering criteria values are case sensitive and must be correctly typed for the endpoint to recognize them.

By default, deaccessioned dataset versions are not supported by this endpoint and will be ignored in the search when applying the :latest or :latest-published identifiers. Additionally, when filtering by a specific version tag, you will get a not found error if the version is deaccessioned and you do not enable the option described below.
By default, deaccessioned dataset versions are not included in the search when applying the :latest or :latest-published identifiers. Additionally, when filtering by a specific version tag, you will get a "not found" error if the version is deaccessioned and you do not enable the ``includeDeaccessioned`` option described below.

If you want to consider deaccessioned dataset versions, you must specify this through the ``includeDeaccessioned`` query parameter.
If you want to include deaccessioned dataset versions, you must set ``includeDeaccessioned`` query parameter to ``true``.

Usage example:

Expand Down Expand Up @@ -1060,7 +1060,7 @@ The fully expanded example above (without environment variables) looks like this
By default, deaccessioned dataset versions are not supported by this endpoint and will be ignored in the search when applying the :latest or :latest-published identifiers. Additionally, when filtering by a specific version tag, you will get a not found error if the version is deaccessioned and you do not enable the option described below.

If you want to consider deaccessioned dataset versions, you must specify this through the ``includeDeaccessioned`` query parameter.
If you want to include deaccessioned dataset versions, you must specify this through the ``includeDeaccessioned`` query parameter.

Usage example:

Expand Down Expand Up @@ -1375,14 +1375,17 @@ Given a version of a dataset, updates its status to deaccessioned.
export SERVER_URL=https://demo.dataverse.org
export ID=24
export VERSIONID=1.0
export JSON='{"deaccessionReason":"Description of the deaccession reason.", "deaccessionForwardURL":"https://demo.dataverse.org"}'
curl -H "X-Dataverse-key:$API_TOKEN" -X PUT "$SERVER_URL/api/datasets/$ID/versions/$VERSIONID/deaccession"
curl -H "X-Dataverse-key:$API_TOKEN" -X POST "$SERVER_URL/api/datasets/$ID/versions/$VERSIONID/deaccession" -d "$JSON"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT "https://demo.dataverse.org/api/datasets/24/versions/1.0/deaccession"
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST "https://demo.dataverse.org/api/datasets/24/versions/1.0/deaccession" -d '{"deaccessionReason":"Description of the deaccession reason.", "deaccessionForwardURL":"https://demo.dataverse.org"}'
.. note:: You cannot deaccession a dataset more than once. If you call this endpoint twice for the same dataset version, you will get a not found error on the second call, since the dataset you are looking for will no longer be published since it is already deaccessioned.

Set Citation Date Field Type for a Dataset
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/edu/harvard/iq/dataverse/api/Datasets.java
Original file line number Diff line number Diff line change
Expand Up @@ -3939,12 +3939,12 @@ public Response getDatasetVersionCitation(@Context ContainerRequestContext crc,
getDatasetVersionOrDie(req, versionId, findDatasetOrDie(datasetId), uriInfo, headers).getCitation(true, false)), getRequestUser(crc));
}

@PUT
@POST
@AuthRequired
@Path("{id}/versions/{versionId}/deaccession")
public Response deaccessionDataset(@Context ContainerRequestContext crc, @PathParam("id") String datasetId, @PathParam("versionId") String versionId, String jsonBody, @Context UriInfo uriInfo, @Context HttpHeaders headers) {
if (DS_VERSION_DRAFT.equals(versionId) || DS_VERSION_LATEST.equals(versionId)) {
return badRequest("Only " + DS_VERSION_LATEST_PUBLISHED + " or a specific version can be deaccessioned");
return badRequest(BundleUtil.getStringFromBundle("datasets.api.deaccessionDataset.invalid.version.identifier.error", List.of(DS_VERSION_LATEST_PUBLISHED)));
}
return response(req -> {
DatasetVersion datasetVersion = getDatasetVersionOrDie(req, versionId, findDatasetOrDie(datasetId), uriInfo, headers, false);
Expand All @@ -3956,7 +3956,7 @@ public Response deaccessionDataset(@Context ContainerRequestContext crc, @PathPa
try {
datasetVersion.setArchiveNote(deaccessionForwardURL);
} catch (IllegalArgumentException iae) {
return error(Response.Status.BAD_REQUEST, "Invalid deaccession forward URL: " + iae.getMessage());
return badRequest(BundleUtil.getStringFromBundle("datasets.api.deaccessionDataset.invalid.forward.url", List.of(iae.getMessage())));
}
}
execCommand(new DeaccessionDatasetVersionCommand(req, datasetVersion, false));
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/propertyFiles/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2623,7 +2623,8 @@ datasets.api.privateurl.anonymized.error.released=Can't create a URL for anonymi
datasets.api.creationdate=Date Created
datasets.api.modificationdate=Last Modified Date
datasets.api.curationstatus=Curation Status

datasets.api.deaccessionDataset.invalid.version.identifier.error=Only {0} or a specific version can be deaccessioned
datasets.api.deaccessionDataset.invalid.forward.url=Invalid deaccession forward URL: {0}

#Dataverses.java
dataverses.api.update.default.contributor.role.failure.role.not.found=Role {0} not found.
Expand Down
48 changes: 39 additions & 9 deletions src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import edu.harvard.iq.dataverse.DatasetVersionFilesServiceBean;
import io.restassured.RestAssured;

import static edu.harvard.iq.dataverse.DatasetVersion.ARCHIVE_NOTE_MAX_LENGTH;
import static edu.harvard.iq.dataverse.api.ApiConstants.*;
import static io.restassured.RestAssured.given;

Expand All @@ -15,6 +16,7 @@
import java.util.*;
import java.util.logging.Logger;

import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -3608,27 +3610,55 @@ public void deaccessionDataset() {
createDatasetResponse.then().assertThat().statusCode(CREATED.getStatusCode());
int datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id");

// Test that draft and latest version constants are not allowed
Response deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_DRAFT, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(BAD_REQUEST.getStatusCode());
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(BAD_REQUEST.getStatusCode());
String testDeaccessionReason = "Test deaccession reason.";
String testDeaccessionForwardURL = "http://demo.dataverse.org";

// Test that draft and latest version constants are not allowed and a bad request error is received
String expectedInvalidVersionIdentifierError = BundleUtil.getStringFromBundle("datasets.api.deaccessionDataset.invalid.version.identifier.error", List.of(DS_VERSION_LATEST_PUBLISHED));

Response deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_DRAFT, testDeaccessionReason, testDeaccessionForwardURL, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(BAD_REQUEST.getStatusCode())
.body("message", equalTo(expectedInvalidVersionIdentifierError));

deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST, testDeaccessionReason, testDeaccessionForwardURL, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(BAD_REQUEST.getStatusCode())
.body("message", equalTo(expectedInvalidVersionIdentifierError));

// Test that a not found error occurs when there is no published version available
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, apiToken);
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, testDeaccessionReason, testDeaccessionForwardURL, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(NOT_FOUND.getStatusCode());

// Test that the dataset is successfully deaccessioned when published
// Publish test dataset
Response publishDataverseResponse = UtilIT.publishDataverseViaNativeApi(dataverseAlias, apiToken);
publishDataverseResponse.then().assertThat().statusCode(OK.getStatusCode());
Response publishDatasetResponse = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken);
publishDatasetResponse.then().assertThat().statusCode(OK.getStatusCode());
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, apiToken);

// Test that a bad request error is received when the forward URL exceeds ARCHIVE_NOTE_MAX_LENGTH
String testInvalidDeaccessionForwardURL = RandomStringUtils.randomAlphabetic(ARCHIVE_NOTE_MAX_LENGTH + 1);

deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, testDeaccessionReason, testInvalidDeaccessionForwardURL, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(BAD_REQUEST.getStatusCode())
.body("message", containsString(testInvalidDeaccessionForwardURL));

// Test that the dataset is successfully deaccessioned when published and valid deaccession params are sent
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, testDeaccessionReason, testDeaccessionForwardURL, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(OK.getStatusCode());

// Test that a not found error occurs when the only published version has already been deaccessioned
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, apiToken);
deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, testDeaccessionReason, testDeaccessionForwardURL, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(NOT_FOUND.getStatusCode());

// Test that a dataset can be deaccessioned without forward URL
createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken);
createDatasetResponse.then().assertThat().statusCode(CREATED.getStatusCode());
datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id");

publishDatasetResponse = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken);
publishDatasetResponse.then().assertThat().statusCode(OK.getStatusCode());

deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, DS_VERSION_LATEST_PUBLISHED, testDeaccessionReason, null, apiToken);
deaccessionDatasetResponse.then().assertThat().statusCode(OK.getStatusCode());
}

@Test
Expand Down
9 changes: 6 additions & 3 deletions src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -3400,14 +3400,17 @@ static Response getHasBeenDeleted(String dataFileId, String apiToken) {
.get("/api/files/" + dataFileId + "/hasBeenDeleted");
}

static Response deaccessionDataset(Integer datasetId, String version, String apiToken) {
static Response deaccessionDataset(Integer datasetId, String version, String deaccessionReason, String deaccessionForwardURL, String apiToken) {
JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
jsonObjectBuilder.add("deaccessionReason", "Test deaccession.");
jsonObjectBuilder.add("deaccessionReason", deaccessionReason);
if (deaccessionForwardURL != null) {
jsonObjectBuilder.add("deaccessionForwardURL", deaccessionForwardURL);
}
String jsonString = jsonObjectBuilder.build().toString();
return given()
.header(API_TOKEN_HTTP_HEADER, apiToken)
.body(jsonString)
.put("/api/datasets/" + datasetId + "/versions/" + version + "/deaccession");
.post("/api/datasets/" + datasetId + "/versions/" + version + "/deaccession");
}

static Response getDownloadSize(Integer datasetId, String version, String mode, String apiToken) {
Expand Down

0 comments on commit b76576d

Please sign in to comment.