Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/release-notes/12313-local-reviews.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Local Reviews

Datasets can have reviews. Specifically, if a review dataset points at (using the itemReviewedUrl field) the URL form of a persistent ID of a dataset (e.g. https://doi.org/10.5072/FK2/ABCDEF) that is in the same Dataverse installation as the review dataset, the review dataset will be included in the list of reviews for the dataset. It is considered a local review.

See [the guides](https://dataverse-guide--12327.org.readthedocs.build/en/12327/api/native-api.html#list-reviews), #12313 and #12327.
23 changes: 23 additions & 0 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4752,6 +4752,29 @@ The fully expanded example above (without environment variables) looks like this

curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT "https://demo.dataverse.org/api/datasets/3/license" -H "Content-type:application/json" --upload-file license.json

.. _api-list-reviews:

List Reviews
~~~~~~~~~~~~

Datasets can have reviews. Specifically, if a :ref:`review dataset <review-datasets-user>` points at (using the ``itemReviewedUrl`` field) the URL form of a persistent ID of a dataset (e.g. https://doi.org/10.5072/FK2/ABCDEF) that is in the same Dataverse installation as the review dataset, the review dataset will be included in the list of reviews for the dataset. It is considered a local review.

An API token is optional if the review dataset has been published.

.. code-block:: bash

export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/ABCDEF

curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/datasets/:persistentId/reviews?persistentId=$PERSISTENT_IDENTIFIER"

The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash

curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/datasets/:persistentId/reviews?persistentId=doi:10.5072/FK2/ABCDEF"

Files
-----

Expand Down
2 changes: 2 additions & 0 deletions doc/sphinx-guides/source/user/dataset-management.rst
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,8 @@ Review Datasets can only be created via API. You have the following options:

When creating a review dataset you will likely need to fill in required fields like ``itemReviewedUrl`` as well as fields from one or more "rubric" metadata blocks, as described above under :ref:`review-datasets-overview`.

If you point ``itemReviewedUrl`` at the URL form of a dataset (e.g. https://doi.org/10.5072/FK2/ABCDEF) that is in the same Dataverse installation as the review dataset, the review dataset is considered a local review and can be listed using the :ref:`api-list-reviews` API endpoint.

.. _dataset-types-datacite:

Dataset Types and DataCite
Expand Down
18 changes: 17 additions & 1 deletion src/main/java/edu/harvard/iq/dataverse/api/Datasets.java
Original file line number Diff line number Diff line change
Expand Up @@ -6261,7 +6261,23 @@ public Response updateLicense(@Context ContainerRequestContext crc,
}
}, getRequestUser(crc));
}


@GET
@AuthRequired
@Path("{identifier}/reviews")
@Produces(MediaType.APPLICATION_JSON)
public Response getReviews(@Context ContainerRequestContext crc, @PathParam("identifier") String id) {
return response(req -> {
Dataset dataset = findDatasetOrDie(id);
try {
JsonObjectBuilder job = execCommand(new GetDatasetReviewsCommand(req, dataset));
return ok(job);
} catch (Exception ex) {
return error(BAD_REQUEST, ex.getMessage());
}
}, getRequestUser(crc));
}

/**
* Storage quotas and use. Note that these methods replicate the
* collection-level equivalents 1:1. Both the quotas and the system for
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package edu.harvard.iq.dataverse.engine.command.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.harvard.iq.dataverse.Dataset;
import edu.harvard.iq.dataverse.Dataverse;
import edu.harvard.iq.dataverse.authorization.Permission;
import edu.harvard.iq.dataverse.engine.command.AbstractCommand;
import edu.harvard.iq.dataverse.engine.command.CommandContext;
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.search.SearchConstants;
import edu.harvard.iq.dataverse.search.SearchException;
import edu.harvard.iq.dataverse.search.SearchFields;
import edu.harvard.iq.dataverse.search.SolrQueryResponse;
import edu.harvard.iq.dataverse.search.SolrSearchResult;
import edu.harvard.iq.dataverse.search.SortBy;
import jakarta.json.Json;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;

// No annotations here since permissions are dynamically decided
public class GetDatasetReviewsCommand extends AbstractCommand<JsonObjectBuilder> {

private final Dataset dataset;

public GetDatasetReviewsCommand(DataverseRequest request, Dataset target) {
super(request, target);
dataset = target;
}

@Override
public JsonObjectBuilder execute(CommandContext ctxt) throws CommandException {
JsonObjectBuilder reviews = Json.createObjectBuilder();
List<Dataverse> dataverses = new ArrayList<>();
// Putting PID as URL in quotes to avoid hits we don't want
String query = "itemReviewedUrl:\"" + dataset.getGlobalId().asURL() + "\"";
List<String> filterQueries = new ArrayList<>();
// Limit to datasets (review datasets)
filterQueries.add(SearchFields.TYPE + ":" + SearchConstants.DATASETS);
String sortField = SearchFields.ID;
String sortOrder = SortBy.ASCENDING;
int paginationStart = 0;
boolean dataRelatedToMe = false;
// We only expect a handful of reviews. This should be plenty.
int numResultsPerPage = 100;
try {
SolrQueryResponse solrQueryResponse = ctxt.search().getDefaultSearchService().search(getRequest(),
dataverses, query, filterQueries, sortField, sortOrder, paginationStart, dataRelatedToMe,
numResultsPerPage);
JsonArrayBuilder itemsArrayBuilder = Json.createArrayBuilder();
List<SolrSearchResult> solrSearchResults = solrQueryResponse.getSolrSearchResults();
for (SolrSearchResult solrSearchResult : solrSearchResults) {
// Construct a JSON object intentionally rather than simply returning the
// solrSearchResult. This "get reviews" command may be powered by a
// database query in the future and we'll want to preserve the contract
// we're establishing here if we make the switch from Solr.
JsonObjectBuilder searchResultBuilder = solrSearchResult.json(false, true, false);
JsonObject searchResultObject = searchResultBuilder.build();
String title = searchResultObject.getString("name");
String citation = searchResultObject.getString("citation");
String citationHtml = searchResultObject.getString("citationHtml");
String pid = searchResultObject.getString("global_id");
String pidUrl = searchResultObject.getString("url");
long id = searchResultObject.getJsonNumber("entity_id").longValue();
JsonObjectBuilder review = Json.createObjectBuilder()
.add("title", title)
.add("persistentId", pid)
.add("persistentIdUrl", pidUrl)
.add("id", id)
.add("citation", citation)
.add("citationHtml", citationHtml);
itemsArrayBuilder.add(review);
}
reviews.add("reviews", itemsArrayBuilder);
} catch (SearchException ex) {
throw new CommandException(ex.getMessage(), this);
}
return reviews;
}

@Override
public Map<String, Set<Permission>> getRequiredPermissions() {
return Collections.singletonMap("",
dataset.isReleased() ? Collections.<Permission>emptySet()
: Collections.singleton(Permission.ViewUnpublishedDataset));
}

}
Loading
Loading