From ac9c11b840c2696b65ef40e4c30caa9b4afdea55 Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Fri, 24 Jul 2026 10:16:34 -0400 Subject: [PATCH] Fix pagination stats for Guestbook Responses --- ...2523-guestbook-responses-page-stats-fix.md | 2 + scripts/api/data/guestbook-test.json | 2 +- .../harvard/iq/dataverse/api/Guestbooks.java | 4 +- .../edu/harvard/iq/dataverse/api/FilesIT.java | 67 +++++++++++++++++++ .../edu/harvard/iq/dataverse/api/UtilIT.java | 2 +- 5 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 doc/release-notes/12523-guestbook-responses-page-stats-fix.md diff --git a/doc/release-notes/12523-guestbook-responses-page-stats-fix.md b/doc/release-notes/12523-guestbook-responses-page-stats-fix.md new file mode 100644 index 00000000000..53971c323cb --- /dev/null +++ b/doc/release-notes/12523-guestbook-responses-page-stats-fix.md @@ -0,0 +1,2 @@ +## Bug ## +API /api/guestbooks/{id}/responses was returning incorrect stats in the pagination block. This corrects the counts by including the full hierarchy of parent collections. diff --git a/scripts/api/data/guestbook-test.json b/scripts/api/data/guestbook-test.json index b83a130c888..0db6e27905f 100644 --- a/scripts/api/data/guestbook-test.json +++ b/scripts/api/data/guestbook-test.json @@ -1,5 +1,5 @@ { - "name": "my test guestbook", + "name": "my test guestbook {@}", "enabled": true, "emailRequired": true, "nameRequired": true, diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Guestbooks.java b/src/main/java/edu/harvard/iq/dataverse/api/Guestbooks.java index 1867b0b515b..fe74d92932c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Guestbooks.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Guestbooks.java @@ -190,8 +190,8 @@ public Response getResponses(@Context ContainerRequestContext crc, if (!permissionSvc.request(req).on(dataverse).has(Permission.EditDataverse)) { return error(Response.Status.FORBIDDEN, "Not authorized"); } - Long totalUsageCount = guestbookService.findCountUsages(guestbook.getId(), dataverse.getId()); - Long totalResponseCount = guestbookResponseService.findCountByGuestbookId(guestbook.getId(), dataverse.getId()); + Long totalUsageCount = guestbookService.findCountUsages(guestbook.getId(), null); + Long totalResponseCount = guestbookResponseService.findCountByGuestbookId(guestbook.getId(), null); guestbook.setUsageCount(totalUsageCount); guestbook.setResponseCount(totalResponseCount); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index 7bc06f7c92c..89366f63fdc 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -3871,6 +3871,73 @@ public void testUpdateWithEmptyFieldsAndVersionCheck() throws InterruptedExcepti .statusCode(BAD_REQUEST.getStatusCode()); } + @Test + public void testDownloadFileWithParentGuestbookResponse() throws IOException, JsonParseException { + msgt("testDownloadFileWithParentGuestbookResponse"); + // Create superuser + Response createUserResponse = UtilIT.createRandomUser(); + assertEquals(200, createUserResponse.getStatusCode()); + String ownerApiToken = UtilIT.getApiTokenFromResponse(createUserResponse); + String superusername = UtilIT.getUsernameFromResponse(createUserResponse); + UtilIT.makeSuperUser(superusername).then().assertThat().statusCode(200); + + // Create Parent Dataverse + String parentDataverseAlias = createDataverseGetAlias(ownerApiToken); + Response publishResponse = UtilIT.publishDataverseViaNativeApi(parentDataverseAlias, ownerApiToken); + assertEquals(200, publishResponse.getStatusCode()); + + // Create Dataverse + String dataverseAlias = createDataverseGetAlias(ownerApiToken); + UtilIT.moveDataverse(dataverseAlias, parentDataverseAlias, null, ownerApiToken); + publishResponse = UtilIT.publishDataverseViaNativeApi(dataverseAlias, ownerApiToken); + assertEquals(200, publishResponse.getStatusCode()); + + // Create user with no permission + createUserResponse = UtilIT.createRandomUser(); + assertEquals(200, createUserResponse.getStatusCode()); + String apiToken = UtilIT.getApiTokenFromResponse(createUserResponse); + String username = UtilIT.getUsernameFromResponse(createUserResponse); + + // Create Dataset with parent dataverse guestbook + Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, ownerApiToken); + createDatasetResponse.then().assertThat().statusCode(CREATED.getStatusCode()); + Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id"); + String persistentId = JsonPath.from(createDatasetResponse.body().asString()).getString("data.persistentId"); + String directoryLabel = "data/store/" + persistentId.substring(4); + Response getDatasetMetadata = UtilIT.nativeGet(datasetId, ownerApiToken); + getDatasetMetadata.then().assertThat().statusCode(200); + // Create a Parent Guestbook and assign to this dataset + Guestbook parentGuestbook = UtilIT.createRandomGuestbook(parentDataverseAlias, persistentId, ownerApiToken); + + // Upload files + JsonObjectBuilder json1 = Json.createObjectBuilder().add("description", "my description1").add("directoryLabel", directoryLabel).add("categories", Json.createArrayBuilder().add("Data")); + Response uploadResponse = UtilIT.uploadFileViaNative(datasetId.toString(), "src/main/webapp/resources/images/dataverseproject.png", json1.build(), ownerApiToken); + uploadResponse.prettyPrint(); + uploadResponse.then().assertThat().statusCode(OK.getStatusCode()); + Integer fileId1 = JsonPath.from(uploadResponse.body().asString()).getInt("data.files[0].dataFile.id"); + + // Publish dataset + Response publishDataset = UtilIT.publishDatasetViaNativeApi(datasetId, "major", ownerApiToken); + assertEquals(200, publishDataset.getStatusCode()); + + // Generate a guestbook response for the parent guestbook + String guestbookResponse = UtilIT.generateGuestbookResponse(parentGuestbook); + guestbookResponse = guestbookResponse.replace("\"guestbookResponse\": {", + "\"guestbookResponse\": { \"name\":\"My Name\", \"email\":\"myemail@example.com\", \"position\":\"My Position\", \"institution\":\"My Institution\","); + Response downloadResponse = UtilIT.postDownloadFile(fileId1, guestbookResponse); + downloadResponse.prettyPrint(); + String signedUrl = UtilIT.getSignedUrlFromResponse(downloadResponse); + // Download the file using the signed url + Response signedUrlResponse = get(signedUrl); + assertEquals(OK.getStatusCode(), signedUrlResponse.getStatusCode()); + + Response guestbookListResponses = UtilIT.getGuestbooksResponses(parentGuestbook.getId(), 0, 100, ownerApiToken); + guestbookListResponses.prettyPrint(); + int responseListSize = guestbookListResponses.jsonPath().getList("data.responses").size(); + int totalCountFromJson = guestbookListResponses.jsonPath().getInt("data.pagination.totalResponses"); + assertEquals(responseListSize, totalCountFromJson); + } + @Test public void testDownloadFileWithGuestbookResponse() throws IOException, JsonParseException { msgt("testDownloadFileWithGuestbookResponse"); 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 b6f8d66c0af..ce700061ab2 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -5598,7 +5598,7 @@ public static Response setGuestbookEntryOnRequest(String datasetId, String apiTo public static Guestbook createRandomGuestbook(String ownerAlias, String persistentId, String apiToken) throws IOException, JsonParseException { Guestbook gb = new Guestbook(); File guestbookJson = new File("scripts/api/data/guestbook-test.json"); - String guestbookAsJson = new String(Files.readAllBytes(Paths.get(guestbookJson.getAbsolutePath()))); + String guestbookAsJson = new String(Files.readAllBytes(Paths.get(guestbookJson.getAbsolutePath()))).replace("{@}", UUID.randomUUID().toString()); JsonObject jsonObj = JsonUtil.getJsonObject(guestbookAsJson); JsonParser jsonParsor = new JsonParser(); jsonParsor.parseGuestbook(jsonObj, gb);