Skip to content

Commit c0848f3

Browse files
committed
add command and API to get reviews #12313
1 parent 172a700 commit c0848f3

4 files changed

Lines changed: 144 additions & 2 deletions

File tree

src/main/java/edu/harvard/iq/dataverse/api/Datasets.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6261,7 +6261,23 @@ public Response updateLicense(@Context ContainerRequestContext crc,
62616261
}
62626262
}, getRequestUser(crc));
62636263
}
6264-
6264+
6265+
@GET
6266+
@AuthRequired
6267+
@Path("{identifier}/reviews")
6268+
@Produces(MediaType.APPLICATION_JSON)
6269+
public Response getReviews(@Context ContainerRequestContext crc, @PathParam("identifier") String id) {
6270+
return response(req -> {
6271+
Dataset dataset = findDatasetOrDie(id);
6272+
try {
6273+
JsonObjectBuilder job = execCommand(new GetDatasetReviewsCommand(req, dataset));
6274+
return ok(job);
6275+
} catch (Exception ex) {
6276+
return error(BAD_REQUEST, ex.getMessage());
6277+
}
6278+
}, getRequestUser(crc));
6279+
}
6280+
62656281
/**
62666282
* Storage quotas and use. Note that these methods replicate the
62676283
* collection-level equivalents 1:1. Both the quotas and the system for
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package edu.harvard.iq.dataverse.engine.command.impl;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Set;
8+
9+
import edu.harvard.iq.dataverse.Dataset;
10+
import edu.harvard.iq.dataverse.Dataverse;
11+
import edu.harvard.iq.dataverse.authorization.Permission;
12+
import edu.harvard.iq.dataverse.engine.command.AbstractCommand;
13+
import edu.harvard.iq.dataverse.engine.command.CommandContext;
14+
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
15+
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
16+
import edu.harvard.iq.dataverse.search.SearchConstants;
17+
import edu.harvard.iq.dataverse.search.SearchException;
18+
import edu.harvard.iq.dataverse.search.SearchFields;
19+
import edu.harvard.iq.dataverse.search.SolrQueryResponse;
20+
import edu.harvard.iq.dataverse.search.SolrSearchResult;
21+
import edu.harvard.iq.dataverse.search.SortBy;
22+
import jakarta.json.Json;
23+
import jakarta.json.JsonArrayBuilder;
24+
import jakarta.json.JsonObject;
25+
import jakarta.json.JsonObjectBuilder;
26+
27+
// No annotations here since permissions are dynamically decided
28+
public class GetDatasetReviewsCommand extends AbstractCommand<JsonObjectBuilder> {
29+
30+
private final Dataset dataset;
31+
32+
public GetDatasetReviewsCommand(DataverseRequest request, Dataset target) {
33+
super(request, target);
34+
dataset = target;
35+
}
36+
37+
@Override
38+
public JsonObjectBuilder execute(CommandContext ctxt) throws CommandException {
39+
JsonObjectBuilder reviews = Json.createObjectBuilder();
40+
List<Dataverse> dataverses = new ArrayList<>();
41+
// Putting PID as URL in quotes to avoid hits we don't want
42+
String query = "itemReviewedUrl:\"" + dataset.getGlobalId().asURL() + "\"";
43+
List<String> filterQueries = new ArrayList<>();
44+
// Limit to datasets (review datasets)
45+
filterQueries.add(SearchFields.TYPE + ":" + SearchConstants.DATASETS);
46+
String sortField = SearchFields.ID;
47+
String sortOrder = SortBy.ASCENDING;
48+
int paginationStart = 0;
49+
boolean dataRelatedToMe = false;
50+
// We only expect a handful of reviews. This should be plenty.
51+
int numResultsPerPage = 100;
52+
try {
53+
SolrQueryResponse solrQueryResponse = ctxt.search().getDefaultSearchService().search(getRequest(),
54+
dataverses, query, filterQueries, sortField, sortOrder, paginationStart, dataRelatedToMe,
55+
numResultsPerPage);
56+
JsonArrayBuilder itemsArrayBuilder = Json.createArrayBuilder();
57+
List<SolrSearchResult> solrSearchResults = solrQueryResponse.getSolrSearchResults();
58+
for (SolrSearchResult solrSearchResult : solrSearchResults) {
59+
// Construct a JSON object intentionally rather than simply returning the
60+
// solrSearchResult. This "get reviews" command may be powered by a
61+
// database query in the future and we'll want to preserve the contract
62+
// we're establishing here if we make the switch from Solr.
63+
JsonObjectBuilder searchResultBuilder = solrSearchResult.json(false, true, false);
64+
JsonObject searchResultObject = searchResultBuilder.build();
65+
String title = searchResultObject.getString("name");
66+
String citation = searchResultObject.getString("citation");
67+
String citationHtml = searchResultObject.getString("citationHtml");
68+
String pid = searchResultObject.getString("global_id");
69+
String pidUrl = searchResultObject.getString("url");
70+
long id = searchResultObject.getJsonNumber("entity_id").longValue();
71+
JsonObjectBuilder review = Json.createObjectBuilder()
72+
.add("title", title)
73+
.add("persistentId", pid)
74+
.add("persistentIdUrl", pidUrl)
75+
.add("id", id)
76+
.add("citation", citation)
77+
.add("citationHtml", citationHtml);
78+
itemsArrayBuilder.add(review);
79+
}
80+
reviews.add("reviews", itemsArrayBuilder);
81+
} catch (SearchException ex) {
82+
throw new CommandException(ex.getMessage(), this);
83+
}
84+
return reviews;
85+
}
86+
87+
@Override
88+
public Map<String, Set<Permission>> getRequiredPermissions() {
89+
return Collections.singletonMap("",
90+
dataset.isReleased() ? Collections.<Permission>emptySet()
91+
: Collections.singleton(Permission.ViewUnpublishedDataset));
92+
}
93+
94+
}

src/test/java/edu/harvard/iq/dataverse/api/ReviewsIT.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,20 @@ public void testLocalReviews() {
553553
publishReview.then().assertThat()
554554
.statusCode(OK.getStatusCode());
555555

556+
// Putting PID as URL in quotes to avoid hits we don't want
557+
Response searchForReviews = UtilIT.search("itemReviewedUrl:\"" + itemReviewedUrl + "\"", null);
558+
searchForReviews.prettyPrint();
559+
searchForReviews.then().assertThat()
560+
.statusCode(OK.getStatusCode())
561+
.body("data.items[0].name", is(reviewTitle));
562+
563+
Response getReviews = UtilIT.getReviews(datasetPid);
564+
getReviews.prettyPrint();
565+
getReviews.then().assertThat()
566+
.statusCode(OK.getStatusCode())
567+
.body("data.reviews[0].title", is(reviewTitle))
568+
.body("data.reviews[0].persistentId", is(reviewPid))
569+
.body("data.reviews[0].id", is(reviewId));
556570
}
557571

558572
}

src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5340,7 +5340,25 @@ public static Response getTemplate(String templateId, String apiToken) {
53405340
.header(API_TOKEN_HTTP_HEADER, apiToken)
53415341
.get("/api/dataverses/" + templateId + "/template");
53425342
}
5343-
5343+
5344+
static Response getReviews(String datasetIdOrPersistentId) {
5345+
return getReviews(datasetIdOrPersistentId, null);
5346+
}
5347+
5348+
static Response getReviews(String datasetIdOrPersistentId, String apiToken) {
5349+
String idInPath = datasetIdOrPersistentId; // Assume it's a number.
5350+
String optionalQueryParam = ""; // If idOrPersistentId is a number we'll just put it in the path.
5351+
if (!NumberUtils.isCreatable(datasetIdOrPersistentId)) {
5352+
idInPath = ":persistentId";
5353+
optionalQueryParam = "?persistentId=" + datasetIdOrPersistentId;
5354+
}
5355+
RequestSpecification responseSpec = given();
5356+
if (apiToken != null) {
5357+
responseSpec.header(API_TOKEN_HTTP_HEADER, apiToken);
5358+
}
5359+
return responseSpec.get("/api/datasets/" + idInPath + "/reviews" + optionalQueryParam);
5360+
}
5361+
53445362
/**
53455363
* Gets the tool URL for a dataset with optional parameters
53465364
* @param datasetId The ID of the dataset

0 commit comments

Comments
 (0)