From b9e8183c03a7076ce28b4b9140929e9484c675b0 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Thu, 22 Dec 2016 12:02:09 -0500 Subject: [PATCH] Native API publish: POST, no 0.1, DOIs #2431 #2461 #3483 #3547 --- doc/sphinx-guides/source/api/native-api.rst | 2 + .../harvard/iq/dataverse/api/Datasets.java | 69 +++++++++++-------- .../command/impl/PublishDatasetCommand.java | 5 ++ .../harvard/iq/dataverse/api/DatasetsIT.java | 23 ++++++- .../harvard/iq/dataverse/api/SearchIT.java | 4 -- .../edu/harvard/iq/dataverse/api/UtilIT.java | 23 +++++-- 6 files changed, 85 insertions(+), 41 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index c7f15c43e2b..1f115f831aa 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -169,6 +169,8 @@ Publishes the dataset whose id is passed. The new dataset version number is dete POST http://$SERVER/api/datasets/$id/actions/:publish?type=$type&key=$apiKey +.. note:: POST should be used to publish a dataset. GET is supported for backward compatibility but is deprecated and may be removed: https://github.com/IQSS/dataverse/issues/2431 + Deletes the draft version of dataset ``$id``. Only the draft version can be deleted:: DELETE http://$SERVER/api/datasets/$id/versions/:draft?key=$apiKey diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index 5e5670ab57a..d7218757aec 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -68,7 +68,7 @@ @Path("datasets") public class Datasets extends AbstractApiBean { - private static final Logger LOGGER = Logger.getLogger(Datasets.class.getName()); + private static final Logger logger = Logger.getLogger(Datasets.class.getCanonicalName()); private static final String PERSISTENT_ID_KEY=":persistentId"; @@ -148,7 +148,7 @@ public Response exportDataset(@QueryParam("persistentId") String persistentId, @ // (the way Access API streams its output). // -- L.A., 4.5 - LOGGER.fine("xml to return: " + xml); + logger.fine("xml to return: " + xml); String mediaType = MediaType.TEXT_PLAIN; if (instance.isXMLFormat(exporter)){ mediaType = MediaType.APPLICATION_XML; @@ -334,7 +334,7 @@ public Response updateDraftVersion( String jsonBody, @PathParam("id") String id, return ok( json(managedVersion) ); } catch (JsonParseException ex) { - LOGGER.log(Level.SEVERE, "Semantic error parsing dataset version Json: " + ex.getMessage(), ex); + logger.log(Level.SEVERE, "Semantic error parsing dataset version Json: " + ex.getMessage(), ex); return error( Response.Status.BAD_REQUEST, "Error parsing dataset version: " + ex.getMessage() ); } catch (WrappedResponse ex) { @@ -343,36 +343,45 @@ public Response updateDraftVersion( String jsonBody, @PathParam("id") String id, } } + /** + * @deprecated This was shipped as a GET but should have been a POST, see https://github.com/IQSS/dataverse/issues/2431 + */ @GET - @Path("{id}/actions/:publish") - public Response publishDataset( @PathParam("id") String id, @QueryParam("type") String type ) { + @Path("{id}/actions/:publish") + @Deprecated + public Response publishDataseUsingGetDeprecated( @PathParam("id") String id, @QueryParam("type") String type ) { + logger.info("publishDataseUsingGetDeprecated called on id " + id + ". Encourage use of POST rather than GET, which is deprecated."); + return publishDataset(id, type); + } + + @POST + @Path("{id}/actions/:publish") + public Response publishDataset(@PathParam("id") String id, @QueryParam("type") String type) { try { - if ( type == null ) { - return error( Response.Status.BAD_REQUEST, "Missing 'type' parameter (either 'major' or 'minor')."); + if (type == null) { + return error(Response.Status.BAD_REQUEST, "Missing 'type' parameter (either 'major' or 'minor')."); } - + type = type.toLowerCase(); boolean isMinor; - switch ( type ) { - case "minor": isMinor = true; break; - case "major": isMinor = false; break; - default: return error( Response.Status.BAD_REQUEST, "Illegal 'type' parameter value '" + type + "'. It needs to be either 'major' or 'minor'."); + switch (type) { + case "minor": + isMinor = true; + break; + case "major": + isMinor = false; + break; + default: + return error(Response.Status.BAD_REQUEST, "Illegal 'type' parameter value '" + type + "'. It needs to be either 'major' or 'minor'."); } - long dsId; - try { - dsId = Long.parseLong(id); - } catch ( NumberFormatException nfe ) { - return error( Response.Status.BAD_REQUEST, "Bad dataset id. Please provide a number."); - } - - Dataset ds = datasetService.find(dsId); - - return ( ds == null ) ? notFound("Can't find dataset with id '" + id + "'") - : ok( json(execCommand(new PublishDatasetCommand(ds, - createDataverseRequest(findAuthenticatedUserOrDie()), - isMinor))) ); - - } catch (WrappedResponse ex) { + + Dataset ds = findDatasetOrDie(id); + + return ok(json(execCommand(new PublishDatasetCommand(ds, + createDataverseRequest(findAuthenticatedUserOrDie()), + isMinor)))); + + } catch (WrappedResponse ex) { return ex.getResponse(); } } @@ -420,7 +429,7 @@ public Response getDdi(@QueryParam("id") long id, @QueryParam("persistentId") St return error(Response.Status.FORBIDDEN, "Not a superuser"); } - LOGGER.fine("looking up " + persistentId); + logger.fine("looking up " + persistentId); Dataset dataset = datasetService.findByGlobalId(persistentId); if (dataset == null) { return error(Response.Status.NOT_FOUND, "A dataset with the persistentId " + persistentId + " could not be found."); @@ -439,7 +448,7 @@ public Response getDdi(@QueryParam("id") long id, @QueryParam("persistentId") St ddiExportService.exportDataset(dataset.getId(), outputStream, null, null); xml = outputStream.toString(); } - LOGGER.fine("xml to return: " + xml); + logger.fine("xml to return: " + xml); return Response.ok() .entity(xml) @@ -473,7 +482,7 @@ public Response createAssignment(String userOrGroup, @PathParam("identifier") St return ok( json(execCommand(new AssignRoleCommand(assignee, theRole, dataset, createDataverseRequest(findUserOrDie()), privateUrlToken)))); } catch (WrappedResponse ex) { - LOGGER.log(Level.WARNING, "Can''t create assignment: {0}", ex.getMessage()); + logger.log(Level.WARNING, "Can''t create assignment: {0}", ex.getMessage()); return ex.getResponse(); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java index 43d24095396..ef5f54c279a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java @@ -77,6 +77,11 @@ public Dataset execute(CommandContext ctxt) throws CommandException { throw new IllegalCommandException("Latest version of dataset " + theDataset.getIdentifier() + " is already released. Only draft versions can be released.", this); } + // prevent publishing of 0.1 version + if (minorRelease && theDataset.getVersions().size() == 1 && theDataset.getLatestVersion().isDraft()) { + throw new IllegalCommandException("Cannot publish as minor version. Re-try as major release.", this); + } + if (minorRelease && !theDataset.getLatestVersion().isMinorUpdate()) { throw new IllegalCommandException("Cannot release as minor version. Re-try as major release.", this); } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index e392f0cf7ab..16c7fffe8db 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -26,7 +26,6 @@ import java.util.UUID; import static javax.ws.rs.core.Response.Status.NO_CONTENT; import static junit.framework.Assert.assertEquals; -import org.hamcrest.CoreMatchers; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.nullValue; @@ -91,11 +90,31 @@ public void testCreatePublishDestroyDataset() { createDatasetResponse.prettyPrint(); Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id"); + Response getDatasetJsonBeforePublishing = UtilIT.nativeGet(datasetId, apiToken); + getDatasetJsonBeforePublishing.prettyPrint(); + String protocol = JsonPath.from(getDatasetJsonBeforePublishing.getBody().asString()).getString("data.protocol"); + String authority = JsonPath.from(getDatasetJsonBeforePublishing.getBody().asString()).getString("data.authority"); + String identifier = JsonPath.from(getDatasetJsonBeforePublishing.getBody().asString()).getString("data.identifier"); + String datasetPersistentId = protocol + ":" + authority + "/" + identifier; + Response publishDataverse = UtilIT.publishDataverseViaSword(dataverseAlias, apiToken); assertEquals(200, publishDataverse.getStatusCode()); - Response publishDataset = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken); + Response attemptToPublishZeroDotOne = UtilIT.publishDatasetViaNativeApiDeprecated(datasetPersistentId, "minor", apiToken); + attemptToPublishZeroDotOne.prettyPrint(); + attemptToPublishZeroDotOne.then().assertThat() + .body("message", equalTo("Cannot publish as minor version. Re-try as major release.")) + .statusCode(403); + + Response publishDataset = UtilIT.publishDatasetViaNativeApi(datasetPersistentId, "major", apiToken); assertEquals(200, publishDataset.getStatusCode()); + Response getDatasetJsonAfterPublishing = UtilIT.nativeGet(datasetId, apiToken); + getDatasetJsonAfterPublishing.prettyPrint(); + getDatasetJsonAfterPublishing.then().assertThat() + .body("data.latestVersion.versionNumber", equalTo(1)) + .body("data.latestVersion.versionMinorNumber", equalTo(0)) + .statusCode(OK.getStatusCode()); + Response deleteDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); deleteDatasetResponse.prettyPrint(); assertEquals(200, deleteDatasetResponse.getStatusCode()); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java b/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java index ae5f8ec7182..9c78b005e30 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java @@ -1165,10 +1165,6 @@ private Response publishDatasetViaNative(long datasetId, String apiToken) { /** * This should probably be a POST rather than a GET: * https://github.com/IQSS/dataverse/issues/2431 - * - * Allows version less than v1.0 to be published (i.e. v0.1): - * https://github.com/IQSS/dataverse/issues/2461 - * */ return given() .header(keyString, apiToken) 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 ee651ecab64..286ed5884fc 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -20,9 +20,7 @@ import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import static com.jayway.restassured.RestAssured.given; import static com.jayway.restassured.path.xml.XmlPath.from; -import java.math.BigDecimal; import java.util.List; -import javax.json.JsonValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -426,13 +424,28 @@ static Response publishDatasetViaSword(String persistentId, String apiToken) { .post(swordConfiguration.getBaseUrlPathCurrent() + "/edit/study/" + persistentId); } + static Response publishDatasetViaNativeApi(String persistentId, String majorOrMinor, String apiToken) { + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .urlEncodingEnabled(false) + .post("/api/datasets/:persistentId/actions/:publish?type=" + majorOrMinor + "&persistentId=" + persistentId); + } + + static Response publishDatasetViaNativeApiDeprecated(String persistentId, String majorOrMinor, String apiToken) { + /** + * @todo This should be a POST rather than a GET: + * https://github.com/IQSS/dataverse/issues/2431 + */ + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .urlEncodingEnabled(false) + .get("/api/datasets/:persistentId/actions/:publish?type=" + majorOrMinor + "&persistentId=" + persistentId); + } + static Response publishDatasetViaNativeApi(Integer datasetId, String majorOrMinor, String apiToken) { /** * @todo This should be a POST rather than a GET: * https://github.com/IQSS/dataverse/issues/2431 - * - * @todo Prevent version less than v1.0 to be published (i.e. v0.1): - * https://github.com/IQSS/dataverse/issues/2461 */ return given() .header(API_TOKEN_HTTP_HEADER, apiToken)