Skip to content

Commit

Permalink
Merge remote-tracking branch 'IQSS/develop' into DANS_Performance2
Browse files Browse the repository at this point in the history
  • Loading branch information
qqmyers committed Oct 2, 2024
2 parents 7274de6 + 08249f5 commit 10d985d
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
An optional query parameter called 'returnExpiration' has been added to the 'users/token/recreate' endpoint, which, if set to true, returns the expiration time in the response message.
10 changes: 8 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 Expand Up @@ -4412,6 +4412,12 @@ In order to obtain a new token use::
curl -H "X-Dataverse-key:$API_TOKEN" -X POST "$SERVER_URL/api/users/token/recreate"
This endpoint by default will return a response message indicating the user identifier and the new token.
To also include the expiration time in the response message, the query parameter ``returnExpiration`` must be set to true::
curl -H "X-Dataverse-key:$API_TOKEN" -X POST "$SERVER_URL/api/users/token/recreate?returnExpiration=true"
Delete a Token
~~~~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions modules/dataverse-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@
Once the release has been made (tag created), change this back to "${parsedVersion.majorVersion}.${parsedVersion.nextMinorVersion}"
(These properties are provided by the build-helper plugin below.)
-->
<!--<base.image.version>${parsedVersion.majorVersion}.${parsedVersion.nextMinorVersion}</base.image.version>-->
<base.image.version>${revision}</base.image.version>
<base.image.version>${parsedVersion.majorVersion}.${parsedVersion.nextMinorVersion}</base.image.version>
<!--<base.image.version>${revision}</base.image.version>-->
</properties>

<build>
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
16 changes: 7 additions & 9 deletions src/main/java/edu/harvard/iq/dataverse/api/Users.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,7 @@
import jakarta.ejb.Stateless;
import jakarta.json.JsonArray;
import jakarta.json.JsonObjectBuilder;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.*;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
Expand Down Expand Up @@ -157,7 +151,7 @@ public Response getTokenExpirationDate() {
@Path("token/recreate")
@AuthRequired
@POST
public Response recreateToken(@Context ContainerRequestContext crc) {
public Response recreateToken(@Context ContainerRequestContext crc, @QueryParam("returnExpiration") boolean returnExpiration) {
User u = getRequestUser(crc);

AuthenticatedUser au;
Expand All @@ -174,8 +168,12 @@ public Response recreateToken(@Context ContainerRequestContext crc) {
ApiToken newToken = authSvc.generateApiTokenForUser(au);
authSvc.save(newToken);

return ok("New token for " + au.getUserIdentifier() + " is " + newToken.getTokenString());
String message = "New token for " + au.getUserIdentifier() + " is " + newToken.getTokenString();
if (returnExpiration) {
message += " and expires on " + newToken.getExpireTime();
}

return ok(message);
}

@GET
Expand Down
2 changes: 1 addition & 1 deletion src/main/webapp/dataset-license-terms.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
or !empty termsOfUseAndAccess.originalArchive or !empty termsOfUseAndAccess.availabilityStatus
or !empty termsOfUseAndAccess.contactForAccess or !empty termsOfUseAndAccess.sizeOfCollection
or !empty termsOfUseAndAccess.studyCompletion
or termsOfUseAndAccess.fileAccessRequest}"/>
}"/>

<div class="text-right margin-bottom"
jsf:rendered="#{dataverseSession.user.authenticated and empty editMode and !widgetWrapper.widgetView
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
26 changes: 21 additions & 5 deletions src/test/java/edu/harvard/iq/dataverse/api/UsersIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.contains;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -371,23 +373,33 @@ public void testAPITokenEndpoints() {
.body("data.message", containsString(userApiToken))
.body("data.message", containsString("expires on"));

// Recreate given a bad API token
Response recreateToken = UtilIT.recreateToken("BAD-Token-blah-89234");
recreateToken.prettyPrint();
recreateToken.then().assertThat()
.statusCode(UNAUTHORIZED.getStatusCode());

// Recreate given a valid API token
recreateToken = UtilIT.recreateToken(userApiToken);
recreateToken.prettyPrint();
recreateToken.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.message", containsString("New token for"));
.body("data.message", containsString("New token for"))
.body("data.message", CoreMatchers.not(containsString("and expires on")));

// Recreate given a valid API token and returning expiration
createUser = UtilIT.createRandomUser();
createUser.prettyPrint();
assertEquals(200, createUser.getStatusCode());
assertEquals(OK.getStatusCode(), createUser.getStatusCode());

userApiToken = UtilIT.getApiTokenFromResponse(createUser);

recreateToken = UtilIT.recreateToken(userApiToken, true);
recreateToken.prettyPrint();
recreateToken.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.message", containsString("New token for"))
.body("data.message", containsString("and expires on"));

String userApiTokenForDelete = UtilIT.getApiTokenFromResponse(createUser);

/*
Add tests for Private URL
*/
Expand Down Expand Up @@ -418,6 +430,10 @@ public void testAPITokenEndpoints() {
getExpiration.then().assertThat()
.statusCode(NOT_FOUND.getStatusCode());

createUser = UtilIT.createRandomUser();
assertEquals(OK.getStatusCode(), createUser.getStatusCode());

String userApiTokenForDelete = UtilIT.getApiTokenFromResponse(createUser);

Response deleteToken = UtilIT.deleteToken(userApiTokenForDelete);
deleteToken.prettyPrint();
Expand Down
Loading

0 comments on commit 10d985d

Please sign in to comment.