diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 6b11ff46d9e..87a4d3def58 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -3236,6 +3236,147 @@ The fully expanded example above (without the environment variables) looks like Only users with superuser permissions may delete harvesting sets. +Managing Harvesting Clients +--------------------------- + +The following API can be used to create and manage "Harvesting Clients". A Harvesting Client is a configuration entry that allows your Dataverse installation to harvest and index metadata from a specific remote location, either regularly, on a configured schedule, or on a one-off basis. For more information, see the :doc:`/admin/harvestclients` section of the Admin Guide. + +List All Configured Harvesting Clients +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Shows all the Harvesting Clients configured:: + + GET http://$SERVER/api/harvest/clients/ + +Show a Specific Harvesting Client +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Shows a Harvesting Client with a defined nickname:: + + GET http://$SERVER/api/harvest/clients/$nickname + +.. code-block:: bash + + curl "http://localhost:8080/api/harvest/clients/myclient" + + { + "status":"OK", + { + "data": { + "lastDatasetsFailed": "22", + "lastDatasetsDeleted": "0", + "metadataFormat": "oai_dc", + "archiveDescription": "This Dataset is harvested from our partners. Clicking the link will take you directly to the archival source of the data.", + "archiveUrl": "https://dataverse.foo.edu", + "harvestUrl": "https://dataverse.foo.edu/oai", + "style": "dataverse", + "type": "oai", + "dataverseAlias": "fooData", + "nickName": "myClient", + "set": "fooSet", + "schedule": "none", + "status": "inActive", + "lastHarvest": "Thu Oct 13 14:48:57 EDT 2022", + "lastResult": "SUCCESS", + "lastSuccessful": "Thu Oct 13 14:48:57 EDT 2022", + "lastNonEmpty": "Thu Oct 13 14:48:57 EDT 2022", + "lastDatasetsHarvested": "137" + } + } + + +Create a Harvesting Client +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a new harvesting client:: + + POST http://$SERVER/api/harvest/clients/$nickname + +``nickName`` is the name identifying the new client. It should be alpha-numeric and may also contain -, _, or %, but no spaces. Must also be unique in the installation. + +You must supply a JSON file that describes the configuration, similarly to the output of the GET API above. The following fields are mandatory: + +- dataverseAlias: The alias of an existing collection where harvested datasets will be deposited +- harvestUrl: The URL of the remote OAI archive +- archiveUrl: The URL of the remote archive that will be used in the redirect links pointing back to the archival locations of the harvested records. It may or may not be on the same server as the harvestUrl above. If this OAI archive is another Dataverse installation, it will be the same URL as harvestUrl minus the "/oai". For example: https://demo.dataverse.org/ vs. https://demo.dataverse.org/oai +- metadataFormat: A supported metadata format. As of writing this the supported formats are "oai_dc", "oai_ddi" and "dataverse_json". + +The following optional fields are supported: + +- archiveDescription: What the name suggests. If not supplied, will default to "This Dataset is harvested from our partners. Clicking the link will take you directly to the archival source of the data." +- set: The OAI set on the remote server. If not supplied, will default to none, i.e., "harvest everything". +- style: Defaults to "default" - a generic OAI archive. (Make sure to use "dataverse" when configuring harvesting from another Dataverse installation). + +Generally, the API will accept the output of the GET version of the API for an existing client as valid input, but some fields will be ignored. For example, as of writing this there is no way to configure a harvesting schedule via this API. + +An example JSON file would look like this:: + + { + "nickName": "zenodo", + "dataverseAlias": "zenodoHarvested", + "harvestUrl": "https://zenodo.org/oai2d", + "archiveUrl": "https://zenodo.org", + "archiveDescription": "Moissonné depuis la collection LMOPS de l'entrepôt Zenodo. En cliquant sur ce jeu de données, vous serez redirigé vers Zenodo.", + "metadataFormat": "oai_dc", + "set": "user-lmops" + } + +.. note:: See :ref:`curl-examples-and-environment-variables` if you are unfamiliar with the use of export below. + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=http://localhost:8080 + + curl -H X-Dataverse-key:$API_TOKEN -X POST -H "Content-Type: application/json" "$SERVER_URL/api/harvest/clients/zenodo" --upload-file client.json + +The fully expanded example above (without the environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST -H "Content-Type: application/json" "http://localhost:8080/api/harvest/clients/zenodo" --upload-file "client.json" + + { + "status": "OK", + "data": { + "metadataFormat": "oai_dc", + "archiveDescription": "Moissonné depuis la collection LMOPS de l'entrepôt Zenodo. En cliquant sur ce jeu de données, vous serez redirigé vers Zenodo.", + "archiveUrl": "https://zenodo.org", + "harvestUrl": "https://zenodo.org/oai2d", + "style": "default", + "type": "oai", + "dataverseAlias": "zenodoHarvested", + "nickName": "zenodo", + "set": "user-lmops", + "schedule": "none", + "status": "inActive", + "lastHarvest": "N/A", + "lastSuccessful": "N/A", + "lastNonEmpty": "N/A", + "lastDatasetsHarvested": "N/A", + "lastDatasetsDeleted": "N/A" + } + } + +Only users with superuser permissions may create or configure harvesting clients. + +Modify a Harvesting Client +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to the API above, using the same JSON format, but run on an existing client and using the PUT method instead of POST. + +Delete a Harvesting Client +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Self-explanatory: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "http://localhost:8080/api/harvest/clients/$nickName" + +Only users with superuser permissions may delete harvesting clients. + + PIDs ---- diff --git a/src/main/java/edu/harvard/iq/dataverse/api/HarvestingClients.java b/src/main/java/edu/harvard/iq/dataverse/api/HarvestingClients.java index d17e76c499a..42534514b68 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/HarvestingClients.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/HarvestingClients.java @@ -5,12 +5,15 @@ import edu.harvard.iq.dataverse.harvest.client.HarvestingClient; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.authorization.users.User; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.impl.CreateHarvestingClientCommand; import edu.harvard.iq.dataverse.engine.command.impl.GetHarvestingClientCommand; import edu.harvard.iq.dataverse.engine.command.impl.UpdateHarvestingClientCommand; import edu.harvard.iq.dataverse.harvest.client.HarvesterServiceBean; import edu.harvard.iq.dataverse.harvest.client.HarvestingClientServiceBean; +import edu.harvard.iq.dataverse.util.BundleUtil; +import edu.harvard.iq.dataverse.util.StringUtil; import edu.harvard.iq.dataverse.util.json.JsonParseException; import javax.json.JsonObjectBuilder; import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder; @@ -20,10 +23,10 @@ import java.util.List; import java.util.logging.Logger; import javax.ejb.EJB; -import javax.ejb.Stateless; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; @@ -32,13 +35,10 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; -@Stateless @Path("harvest/clients") public class HarvestingClients extends AbstractApiBean { - @EJB - DataverseServiceBean dataverseService; @EJB HarvesterServiceBean harvesterService; @EJB @@ -111,6 +111,10 @@ public Response harvestingClient(@PathParam("nickName") String nickName, @QueryP return error(Response.Status.NOT_FOUND, "Harvesting client " + nickName + " not found."); } + // See the comment in the harvestingClients() (plural) above for the explanation + // of why we are looking up the client twice (tl;dr: to utilize the + // authorization logic in the command) + HarvestingClient retrievedHarvestingClient = null; try { @@ -118,7 +122,7 @@ public Response harvestingClient(@PathParam("nickName") String nickName, @QueryP // exception, that already has a proper HTTP response in it. retrievedHarvestingClient = execCommand(new GetHarvestingClientCommand(createDataverseRequest(findUserOrDie()), harvestingClient)); - logger.info("retrieved Harvesting Client " + retrievedHarvestingClient.getName() + " with the GetHarvestingClient command."); + logger.fine("retrieved Harvesting Client " + retrievedHarvestingClient.getName() + " with the GetHarvestingClient command."); } catch (WrappedResponse wr) { return wr.getResponse(); } catch (Exception ex) { @@ -143,29 +147,76 @@ public Response harvestingClient(@PathParam("nickName") String nickName, @QueryP @POST @Path("{nickName}") public Response createHarvestingClient(String jsonBody, @PathParam("nickName") String nickName, @QueryParam("key") String apiKey) throws IOException, JsonParseException { - + // Per the discussion during the QA of PR #9174, we decided to make + // the create/edit APIs superuser-only (the delete API was already so) + try { + User u = findUserOrDie(); + if ((!(u instanceof AuthenticatedUser) || !u.isSuperuser())) { + throw new WrappedResponse(error(Response.Status.UNAUTHORIZED, "Only superusers can create harvesting clients.")); + } + } catch (WrappedResponse wr) { + return wr.getResponse(); + } + try ( StringReader rdr = new StringReader(jsonBody) ) { JsonObject json = Json.createReader(rdr).readObject(); + // Check that the client with this name doesn't exist yet: + // (we could simply let the command fail, but that does not result + // in a pretty report to the end user) + + HarvestingClient lookedUpClient = null; + try { + lookedUpClient = harvestingClientService.findByNickname(nickName); + } catch (Exception ex) { + logger.warning("Exception caught looking up harvesting client " + nickName + ": " + ex.getMessage()); + // let's hope that this was a fluke of some kind; we'll proceed + // with the attempt to create a new client and report an error + // if that fails too. + } + + if (lookedUpClient != null) { + return error(Response.Status.BAD_REQUEST, "Harvesting client " + nickName + " already exists"); + } + HarvestingClient harvestingClient = new HarvestingClient(); - // TODO: check that it doesn't exist yet... - harvestingClient.setName(nickName); + String dataverseAlias = jsonParser().parseHarvestingClient(json, harvestingClient); - Dataverse ownerDataverse = dataverseService.findByAlias(dataverseAlias); + if (dataverseAlias == null) { + return error(Response.Status.BAD_REQUEST, "dataverseAlias must be supplied"); + } + + // Check if the dataverseAlias supplied is valid, i.e. corresponds + // to an existing dataverse (collection): + Dataverse ownerDataverse = dataverseSvc.findByAlias(dataverseAlias); if (ownerDataverse == null) { return error(Response.Status.BAD_REQUEST, "No such dataverse: " + dataverseAlias); } + // The nickname supplied as part of the Rest path takes precedence: + harvestingClient.setName(nickName); + + // Populate the description field, if none is supplied: + if (harvestingClient.getArchiveDescription() == null) { + harvestingClient.setArchiveDescription(BundleUtil.getStringFromBundle("harvestclients.viewEditDialog.archiveDescription.default.generic")); + } + + if (StringUtil.isEmpty(harvestingClient.getArchiveUrl()) + || StringUtil.isEmpty(harvestingClient.getHarvestingUrl()) + || StringUtil.isEmpty(harvestingClient.getMetadataPrefix())) { + return error(Response.Status.BAD_REQUEST, "Required fields harvestUrl, archiveUrl and metadataFormat must be supplied"); + } + harvestingClient.setDataverse(ownerDataverse); if (ownerDataverse.getHarvestingClientConfigs() == null) { ownerDataverse.setHarvestingClientConfigs(new ArrayList<>()); } ownerDataverse.getHarvestingClientConfigs().add(harvestingClient); - + DataverseRequest req = createDataverseRequest(findUserOrDie()); - HarvestingClient managedHarvestingClient = execCommand( new CreateHarvestingClientCommand(req, harvestingClient)); - return created( "/harvest/clients/" + nickName, harvestingConfigAsJson(managedHarvestingClient)); + harvestingClient = execCommand(new CreateHarvestingClientCommand(req, harvestingClient)); + return created( "/harvest/clients/" + nickName, harvestingConfigAsJson(harvestingClient)); } catch (JsonParseException ex) { return error( Response.Status.BAD_REQUEST, "Error parsing harvesting client: " + ex.getMessage() ); @@ -180,6 +231,15 @@ public Response createHarvestingClient(String jsonBody, @PathParam("nickName") S @PUT @Path("{nickName}") public Response modifyHarvestingClient(String jsonBody, @PathParam("nickName") String nickName, @QueryParam("key") String apiKey) throws IOException, JsonParseException { + try { + User u = findUserOrDie(); + if ((!(u instanceof AuthenticatedUser) || !u.isSuperuser())) { + throw new WrappedResponse(error(Response.Status.UNAUTHORIZED, "Only superusers can modify harvesting clients.")); + } + } catch (WrappedResponse wr) { + return wr.getResponse(); + } + HarvestingClient harvestingClient = null; try { harvestingClient = harvestingClientService.findByNickname(nickName); @@ -198,15 +258,39 @@ public Response modifyHarvestingClient(String jsonBody, @PathParam("nickName") S DataverseRequest req = createDataverseRequest(findUserOrDie()); JsonObject json = Json.createReader(rdr).readObject(); - String newDataverseAlias = jsonParser().parseHarvestingClient(json, harvestingClient); + HarvestingClient newHarvestingClient = new HarvestingClient(); + String newDataverseAlias = jsonParser().parseHarvestingClient(json, newHarvestingClient); if (newDataverseAlias != null && !newDataverseAlias.equals("") && !newDataverseAlias.equals(ownerDataverseAlias)) { return error(Response.Status.BAD_REQUEST, "Bad \"dataverseAlias\" supplied. Harvesting client "+nickName+" belongs to the dataverse "+ownerDataverseAlias); } - HarvestingClient managedHarvestingClient = execCommand( new UpdateHarvestingClientCommand(req, harvestingClient)); - return created( "/datasets/" + nickName, harvestingConfigAsJson(managedHarvestingClient)); + + // Go through the supported editable fields and update the client accordingly: + + if (newHarvestingClient.getHarvestingUrl() != null) { + harvestingClient.setHarvestingUrl(newHarvestingClient.getHarvestingUrl()); + } + if (newHarvestingClient.getHarvestingSet() != null) { + harvestingClient.setHarvestingSet(newHarvestingClient.getHarvestingSet()); + } + if (newHarvestingClient.getMetadataPrefix() != null) { + harvestingClient.setMetadataPrefix(newHarvestingClient.getMetadataPrefix()); + } + if (newHarvestingClient.getArchiveUrl() != null) { + harvestingClient.setArchiveUrl(newHarvestingClient.getArchiveUrl()); + } + if (newHarvestingClient.getArchiveDescription() != null) { + harvestingClient.setArchiveDescription(newHarvestingClient.getArchiveDescription()); + } + if (newHarvestingClient.getHarvestStyle() != null) { + harvestingClient.setHarvestStyle(newHarvestingClient.getHarvestStyle()); + } + // TODO: Make schedule configurable via this API too. + + harvestingClient = execCommand( new UpdateHarvestingClientCommand(req, harvestingClient)); + return ok( "/harvest/clients/" + nickName, harvestingConfigAsJson(harvestingClient)); } catch (JsonParseException ex) { return error( Response.Status.BAD_REQUEST, "Error parsing harvesting client: " + ex.getMessage() ); @@ -218,9 +302,58 @@ public Response modifyHarvestingClient(String jsonBody, @PathParam("nickName") S } - // TODO: - // add a @DELETE method - // (there is already a DeleteHarvestingClient command) + @DELETE + @Path("{nickName}") + public Response deleteHarvestingClient(@PathParam("nickName") String nickName) throws IOException { + // Deleting a client can take a while (if there's a large amnount of + // harvested content associated with it). So instead of calling the command + // directly, we will be calling an async. service bean method. + + + try { + User u = findUserOrDie(); + if ((!(u instanceof AuthenticatedUser) || !u.isSuperuser())) { + throw new WrappedResponse(error(Response.Status.UNAUTHORIZED, "Only superusers can delete harvesting clients.")); + } + } catch (WrappedResponse wr) { + return wr.getResponse(); + } + + HarvestingClient harvestingClient = null; + + try { + harvestingClient = harvestingClientService.findByNickname(nickName); + } catch (Exception ex) { + logger.warning("Exception caught looking up harvesting client " + nickName + ": " + ex.getMessage()); + return error( Response.Status.BAD_REQUEST, "Internal error: failed to look up harvesting client " + nickName); + } + + if (harvestingClient == null) { + return error(Response.Status.NOT_FOUND, "Harvesting client " + nickName + " not found."); + } + + // Check if the client is in a state where it can be safely deleted: + + if (harvestingClient.isDeleteInProgress()) { + return error( Response.Status.BAD_REQUEST, "Harvesting client " + nickName + " is already being deleted (in progress)"); + } + + if (harvestingClient.isHarvestingNow()) { + return error( Response.Status.BAD_REQUEST, "It is not safe to delete client " + nickName + " while a harvesting job is in progress"); + } + + // Finally, delete it (asynchronously): + + try { + harvestingClientService.deleteClient(harvestingClient.getId()); + } catch (Exception ex) { + return error( Response.Status.BAD_REQUEST, "Internal error: failed to delete harvesting client " + nickName); + } + + + return ok("Harvesting Client " + nickName + ": delete in progress"); + } + // Methods for managing harvesting runs (jobs): @@ -296,6 +429,7 @@ public static JsonObjectBuilder harvestingConfigAsJson(HarvestingClient harvesti return jsonObjectBuilder().add("nickName", harvestingConfig.getName()). add("dataverseAlias", harvestingConfig.getDataverse().getAlias()). add("type", harvestingConfig.getHarvestType()). + add("style", harvestingConfig.getHarvestStyle()). add("harvestUrl", harvestingConfig.getHarvestingUrl()). add("archiveUrl", harvestingConfig.getArchiveUrl()). add("archiveDescription",harvestingConfig.getArchiveDescription()). diff --git a/src/main/java/edu/harvard/iq/dataverse/harvest/client/HarvestingClient.java b/src/main/java/edu/harvard/iq/dataverse/harvest/client/HarvestingClient.java index 32365e17852..aeb010fad6d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/harvest/client/HarvestingClient.java +++ b/src/main/java/edu/harvard/iq/dataverse/harvest/client/HarvestingClient.java @@ -188,7 +188,9 @@ public String getHarvestingUrl() { } public void setHarvestingUrl(String harvestingUrl) { - this.harvestingUrl = harvestingUrl.trim(); + if (harvestingUrl != null) { + this.harvestingUrl = harvestingUrl.trim(); + } } private String archiveUrl; diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java index 4ecdc73ae6e..905479c4e0d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java @@ -902,10 +902,10 @@ public String parseHarvestingClient(JsonObject obj, HarvestingClient harvestingC String dataverseAlias = obj.getString("dataverseAlias",null); harvestingClient.setName(obj.getString("nickName",null)); - harvestingClient.setHarvestType(obj.getString("type",null)); + harvestingClient.setHarvestStyle(obj.getString("style", "default")); harvestingClient.setHarvestingUrl(obj.getString("harvestUrl",null)); harvestingClient.setArchiveUrl(obj.getString("archiveUrl",null)); - harvestingClient.setArchiveDescription(obj.getString("archiveDescription")); + harvestingClient.setArchiveDescription(obj.getString("archiveDescription", null)); harvestingClient.setMetadataPrefix(obj.getString("metadataFormat",null)); harvestingClient.setHarvestingSet(obj.getString("set",null)); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/HarvestingClientsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/HarvestingClientsIT.java new file mode 100644 index 00000000000..9eac3545e54 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/api/HarvestingClientsIT.java @@ -0,0 +1,122 @@ +package edu.harvard.iq.dataverse.api; + +import java.util.logging.Logger; +import com.jayway.restassured.RestAssured; +import static com.jayway.restassured.RestAssured.given; +import org.junit.Test; +import com.jayway.restassured.response.Response; +import static org.hamcrest.CoreMatchers.equalTo; +import static junit.framework.Assert.assertEquals; +import org.junit.BeforeClass; + +/** + * extremely minimal (for now) API tests for creating OAI clients. + */ +public class HarvestingClientsIT { + + private static final Logger logger = Logger.getLogger(HarvestingClientsIT.class.getCanonicalName()); + + private static final String harvestClientsApi = "/api/harvest/clients/"; + private static final String harvestCollection = "root"; + private static final String harvestUrl = "https://demo.dataverse.org/oai"; + private static final String archiveUrl = "https://demo.dataverse.org"; + private static final String harvestMetadataFormat = "oai_dc"; + private static final String archiveDescription = "RestAssured harvesting client test"; + + @BeforeClass + public static void setUpClass() { + RestAssured.baseURI = UtilIT.getRestAssuredBaseUri(); + } + + private void setupUsers() { + Response cu0 = UtilIT.createRandomUser(); + normalUserAPIKey = UtilIT.getApiTokenFromResponse(cu0); + Response cu1 = UtilIT.createRandomUser(); + String un1 = UtilIT.getUsernameFromResponse(cu1); + Response u1a = UtilIT.makeSuperUser(un1); + adminUserAPIKey = UtilIT.getApiTokenFromResponse(cu1); + } + + private String normalUserAPIKey; + private String adminUserAPIKey; + + @Test + public void testCreateEditDeleteClient() { + setupUsers(); + String nickName = UtilIT.getRandomString(6); + + + String clientApiPath = String.format(harvestClientsApi+"%s", nickName); + String clientJson = String.format("{\"dataverseAlias\":\"%s\"," + + "\"type\":\"oai\"," + + "\"harvestUrl\":\"%s\"," + + "\"archiveUrl\":\"%s\"," + + "\"metadataFormat\":\"%s\"}", + harvestCollection, harvestUrl, archiveUrl, harvestMetadataFormat); + + + // Try to create a client as normal user, should fail: + + Response rCreate = given() + .header(UtilIT.API_TOKEN_HTTP_HEADER, normalUserAPIKey) + .body(clientJson) + .post(clientApiPath); + assertEquals(401, rCreate.getStatusCode()); + + + // Try to create the same as admin user, should succeed: + + rCreate = given() + .header(UtilIT.API_TOKEN_HTTP_HEADER, adminUserAPIKey) + .body(clientJson) + .post(clientApiPath); + assertEquals(201, rCreate.getStatusCode()); + + // Try to update the client we have just created: + + String updateJson = String.format("{\"archiveDescription\":\"%s\"}", archiveDescription); + + Response rUpdate = given() + .header(UtilIT.API_TOKEN_HTTP_HEADER, adminUserAPIKey) + .body(updateJson) + .put(clientApiPath); + assertEquals(200, rUpdate.getStatusCode()); + + // Now let's retrieve the client we've just created and edited: + + Response getClientResponse = given() + .get(clientApiPath); + + logger.info("getClient.getStatusCode(): " + getClientResponse.getStatusCode()); + logger.info("getClient printresponse: " + getClientResponse.prettyPrint()); + assertEquals(200, getClientResponse.getStatusCode()); + + // ... and validate the values: + + getClientResponse.then().assertThat() + .body("status", equalTo(AbstractApiBean.STATUS_OK)) + .body("data.type", equalTo("oai")) + .body("data.nickName", equalTo(nickName)) + .body("data.archiveDescription", equalTo(archiveDescription)) + .body("data.dataverseAlias", equalTo(harvestCollection)) + .body("data.harvestUrl", equalTo(harvestUrl)) + .body("data.archiveUrl", equalTo(archiveUrl)) + .body("data.metadataFormat", equalTo(harvestMetadataFormat)); + + // Try to delete the client as normal user should fail: + + Response rDelete = given() + .header(UtilIT.API_TOKEN_HTTP_HEADER, normalUserAPIKey) + .delete(clientApiPath); + logger.info("rDelete.getStatusCode(): " + rDelete.getStatusCode()); + assertEquals(401, rDelete.getStatusCode()); + + // Try to delete as admin user should work: + + rDelete = given() + .header(UtilIT.API_TOKEN_HTTP_HEADER, adminUserAPIKey) + .delete(clientApiPath); + logger.info("rDelete.getStatusCode(): " + rDelete.getStatusCode()); + assertEquals(200, rDelete.getStatusCode()); + } +} diff --git a/tests/integration-tests.txt b/tests/integration-tests.txt index 85b37c79835..85670e8324a 100644 --- a/tests/integration-tests.txt +++ b/tests/integration-tests.txt @@ -1 +1 @@ -DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT,DuplicateFilesIT,DownloadFilesIT,LinkIT,DeleteUsersIT,DeactivateUsersIT,AuxiliaryFilesIT,InvalidCharactersIT,LicensesIT,NotificationsIT,BagIT +DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,HarvestingClientsIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT,DuplicateFilesIT,DownloadFilesIT,LinkIT,DeleteUsersIT,DeactivateUsersIT,AuxiliaryFilesIT,InvalidCharactersIT,LicensesIT,NotificationsIT,BagIT