Skip to content

Commit

Permalink
Importing unmanaged pids (#10805)
Browse files Browse the repository at this point in the history
* fix: send proper error response when trying to import dataset with unmanaged PID

* test: add tests for importing datasets as JSON

* docs: state that importing datasets with unmanaged PIDs is not supported
  • Loading branch information
vera authored Sep 30, 2024
1 parent 8325053 commit c59746d
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 2 deletions.
4 changes: 2 additions & 2 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ Before calling the API, make sure the data files referenced by the ``POST``\ ed

* This API does not cover staging files (with correct contents, checksums, sizes, etc.) in the corresponding places in the Dataverse installation's filestore.
* This API endpoint does not support importing *files'* persistent identifiers.
* A Dataverse installation can import datasets with a valid PID that uses a different protocol or authority than said server is configured for. However, the server will not update the PID metadata on subsequent update and publish actions.
* A Dataverse installation can only import datasets with a valid PID that is managed by one of the PID providers that said installation is configured for.

.. _import-dataset-with-type:

Expand Down Expand Up @@ -935,7 +935,7 @@ Note that DDI XML does not have a field that corresponds to the "Subject" field
.. warning::

* This API does not handle files related to the DDI file.
* A Dataverse installation can import datasets with a valid PID that uses a different protocol or authority than said server is configured for. However, the server will not update the PID metadata on subsequent update and publish actions.
* A Dataverse installation can only import datasets with a valid PID that is managed by one of the PID providers that said installation is configured for.

.. _publish-dataverse-api:

Expand Down
6 changes: 6 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ public Response importDataset(@Context ContainerRequestContext crc, String jsonB
if (ds.getIdentifier() == null) {
return badRequest("Please provide a persistent identifier, either by including it in the JSON, or by using the pid query parameter.");
}

PidProvider pidProvider = PidUtil.getPidProvider(ds.getGlobalId().getProviderId());
if (pidProvider == null || !pidProvider.canManagePID()) {
return badRequest("Cannot import a dataset that has a PID that doesn't match the server's settings");
}

boolean shouldRelease = StringUtil.isTrue(releaseParam);
DataverseRequest request = createDataverseRequest(u);

Expand Down
173 changes: 173 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,179 @@ public void testImportDDI() throws IOException, InterruptedException {
Response deleteUserResponse = UtilIT.deleteUser(username);
assertEquals(200, deleteUserResponse.getStatusCode());
}

@Test
public void testImport() throws IOException, InterruptedException {

Response createUser = UtilIT.createRandomUser();
String username = UtilIT.getUsernameFromResponse(createUser);
Response makeSuperUser = UtilIT.makeSuperUser(username);
assertEquals(200, makeSuperUser.getStatusCode());
String apiToken = UtilIT.getApiTokenFromResponse(createUser);

Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);

Response publishDataverse = UtilIT.publishDataverseViaNativeApi(dataverseAlias, apiToken);
assertEquals(200, publishDataverse.getStatusCode());

JsonObjectBuilder datasetJson = Json.createObjectBuilder()
.add("datasetVersion", Json.createObjectBuilder()
.add("license", Json.createObjectBuilder()
.add("name", "CC0 1.0")
)
.add("metadataBlocks", Json.createObjectBuilder()
.add("citation", Json.createObjectBuilder()
.add("fields", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("typeName", "title")
.add("value", "Test Dataset")
.add("typeClass", "primitive")
.add("multiple", false)
)
.add(Json.createObjectBuilder()
.add("value", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("authorName",
Json.createObjectBuilder()
.add("value", "Simpson, Homer")
.add("typeClass", "primitive")
.add("multiple", false)
.add("typeName", "authorName"))
)
)
.add("typeClass", "compound")
.add("multiple", true)
.add("typeName", "author")
)
.add(Json.createObjectBuilder()
.add("value", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("datasetContactEmail",
Json.createObjectBuilder()
.add("value", "hsimpson@mailinator.com")
.add("typeClass", "primitive")
.add("multiple", false)
.add("typeName", "datasetContactEmail"))
)
)
.add("typeClass", "compound")
.add("multiple", true)
.add("typeName", "datasetContact")
)
.add(Json.createObjectBuilder()
.add("value", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("dsDescriptionValue",
Json.createObjectBuilder()
.add("value", "This a test dataset.")
.add("typeClass", "primitive")
.add("multiple", false)
.add("typeName", "dsDescriptionValue"))
)
)
.add("typeClass", "compound")
.add("multiple", true)
.add("typeName", "dsDescription")
)
.add(Json.createObjectBuilder()
.add("value", Json.createArrayBuilder()
.add("Other")
)
.add("typeClass", "controlledVocabulary")
.add("multiple", true)
.add("typeName", "subject")
)
)
)
));

String json = datasetJson.build().toString();

Response importJSONNoPid = UtilIT.importDatasetViaNativeApi(apiToken, dataverseAlias, json, null, "no");
logger.info(importJSONNoPid.prettyPrint());
assertEquals(400, importJSONNoPid.getStatusCode());

String body = importJSONNoPid.getBody().asString();
String status = JsonPath.from(body).getString("status");
assertEquals("ERROR", status);

String message = JsonPath.from(body).getString("message");
assertEquals(
"Please provide a persistent identifier, either by including it in the JSON, or by using the pid query parameter.",
message
);

Response importJSONNoPidRelease = UtilIT.importDatasetViaNativeApi(apiToken, dataverseAlias, json, null, "yes");
logger.info( importJSONNoPidRelease.prettyPrint());
assertEquals(400, importJSONNoPidRelease.getStatusCode());

body = importJSONNoPidRelease.getBody().asString();
status = JsonPath.from(body).getString("status");
assertEquals("ERROR", status);

message = JsonPath.from(body).getString("message");
assertEquals(
"Please provide a persistent identifier, either by including it in the JSON, or by using the pid query parameter.",
message
);

Response importJSONUnmanagedPid = UtilIT.importDatasetViaNativeApi(apiToken, dataverseAlias, json, "doi:10.5073/FK2/ABCD11", "no");
logger.info(importJSONUnmanagedPid.prettyPrint());
assertEquals(400, importJSONUnmanagedPid.getStatusCode());

body = importJSONUnmanagedPid.getBody().asString();
status = JsonPath.from(body).getString("status");
assertEquals("ERROR", status);

message = JsonPath.from(body).getString("message");
assertEquals(
"Cannot import a dataset that has a PID that doesn't match the server's settings",
message
);

// Under normal conditions, you shouldn't need to destroy these datasets.
// Uncomment if they're still around from a previous failed run.
// Response destroy1 = UtilIT.destroyDataset("doi:10.5072/FK2/ABCD11", apiToken);
// destroy1.prettyPrint();
// Response destroy2 = UtilIT.destroyDataset("doi:10.5072/FK2/ABCD22", apiToken);
// destroy2.prettyPrint();

Response importJSONPid = UtilIT.importDatasetViaNativeApi(apiToken, dataverseAlias, json, "doi:10.5072/FK2/ABCD11", "no");
logger.info(importJSONPid.prettyPrint());
assertEquals(201, importJSONPid.getStatusCode());

Response importJSONPidRel = UtilIT.importDatasetViaNativeApi(apiToken, dataverseAlias, json, "doi:10.5072/FK2/ABCD22", "yes");
logger.info(importJSONPidRel.prettyPrint());
assertEquals(201, importJSONPidRel.getStatusCode());

Integer datasetIdInt = JsonPath.from(importJSONPid.body().asString()).getInt("data.id");

Response search1 = UtilIT.search("id:dataset_" + datasetIdInt + "_draft", apiToken); // santity check, can find it
search1.prettyPrint();
search1.then().assertThat()
.body("data.total_count", CoreMatchers.is(1))
.body("data.count_in_response", CoreMatchers.is(1))
.body("data.items[0].name", CoreMatchers.is("Test Dataset"))
.statusCode(OK.getStatusCode());

//cleanup

Response destroyDatasetResponse = UtilIT.destroyDataset(datasetIdInt, apiToken);
assertEquals(200, destroyDatasetResponse.getStatusCode());

Integer datasetIdIntPidRel = JsonPath.from(importJSONPidRel.body().asString()).getInt("data.id");
Response destroyDatasetResponsePidRel = UtilIT.destroyDataset(datasetIdIntPidRel, apiToken);
assertEquals(200, destroyDatasetResponsePidRel.getStatusCode());

UtilIT.sleepForDeadlock(UtilIT.MAXIMUM_IMPORT_DURATION);

Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, apiToken);
assertEquals(200, deleteDataverseResponse.getStatusCode());

Response deleteUserResponse = UtilIT.deleteUser(username);
assertEquals(200, deleteUserResponse.getStatusCode());
}

@Test
public void testAttributesApi() throws Exception {
Expand Down
29 changes: 29 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 @@ -3672,6 +3672,35 @@ static Response importDatasetDDIViaNativeApi(String apiToken, String dataverseAl
return importDDI.post(postString);
}


static Response importDatasetViaNativeApi(String apiToken, String dataverseAlias, String json, String pid, String release) {
String postString = "/api/dataverses/" + dataverseAlias + "/datasets/:import";
if (pid != null || release != null ) {
//postString = postString + "?";
if (pid != null) {
postString = postString + "?pid=" + pid;
if (release != null && release.compareTo("yes") == 0) {
postString = postString + "&release=" + release;
}
} else {
if (release != null && release.compareTo("yes") == 0) {
postString = postString + "?release=" + release;
}
}
}
logger.info("Here importDatasetViaNativeApi");
logger.info(postString);

RequestSpecification importJSON = given()
.header(API_TOKEN_HTTP_HEADER, apiToken)
.urlEncodingEnabled(false)
.body(json)
.contentType("application/json");

return importJSON.post(postString);
}


static Response retrieveMyDataAsJsonString(String apiToken, String userIdentifier, ArrayList<Long> roleIds) {
Response response = given()
.header(API_TOKEN_HTTP_HEADER, apiToken)
Expand Down

0 comments on commit c59746d

Please sign in to comment.