From 8b559c6bc4289d1f16ba80d4625e9f927c5ae8b5 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Wed, 26 Nov 2025 15:39:39 +0100 Subject: [PATCH 1/9] feat: add "isInReviewState" to API responses about dataset versions --- .../java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 654154c5b64..0f8042cc021 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -533,6 +533,7 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List anonymized .add("internalVersionNumber", dsv.getVersion()) .add("versionMinorNumber", dsv.getMinorVersionNumber()) .add("versionState", dsv.getVersionState().name()) + .add("isInReviewState", dsv.isInReview()) .add("latestVersionPublishingState", dataset.getLatestVersion().getVersionState().name()) .add("deaccessionNote", dsv.getDeaccessionNote()) .add("deaccessionLink", dsv.getDeaccessionLink()) From 046d9698955a213b2fd909399a6ec032fe74d97a Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Thu, 27 Nov 2025 16:36:02 +0100 Subject: [PATCH 2/9] test: add "isInReviewState" to API responses about dataset versions --- .../harvard/iq/dataverse/api/DatasetsIT.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) 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 39c66f9888f..91e5f436d7b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1176,6 +1176,7 @@ public void testDatasetVersionsAPI() { datasetVersion.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.latestVersionPublishingState", equalTo("RELEASED")); // Upload another file: @@ -1189,6 +1190,7 @@ public void testDatasetVersionsAPI() { datasetVersion.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.latestVersionPublishingState", equalTo("DRAFT")); datasetVersion = UtilIT.getDatasetVersion(datasetPid, DS_VERSION_LATEST, apiTokenNoPerms, excludeFiles, includeDeaccessioned); @@ -1196,6 +1198,7 @@ public void testDatasetVersionsAPI() { datasetVersion.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.latestVersionPublishingState", equalTo("DRAFT")); // We should now have a published version, and a draft. @@ -1222,6 +1225,7 @@ public void testDatasetVersionsAPI() { .statusCode(OK.getStatusCode()) .body("data.size()", equalTo(1)) .body("data.versionState[0]", equalTo("DRAFT")) + .body("data[0].isInReviewState", equalTo(false)) .body("data[0].files.size()", equalTo(2)); // And now call it with an un-privileged token, to make sure only one @@ -1231,6 +1235,7 @@ public void testDatasetVersionsAPI() { versionsResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState[0]", not("DRAFT")) + .body("data[0].isInReviewState", equalTo(false)) .body("data.size()", equalTo(1)); // And now call the "short", no-files version of the same api @@ -1253,6 +1258,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest published unauthorized token @@ -1261,6 +1267,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest authorized token @@ -1269,6 +1276,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest unauthorized token @@ -1277,6 +1285,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version authorized token @@ -1285,6 +1294,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version unauthorized token @@ -1293,6 +1303,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); excludeFiles = false; @@ -1303,6 +1314,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Latest published unauthorized token @@ -1311,6 +1323,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Latest authorized token, user is authenticated should get the Draft version @@ -1319,6 +1332,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(2)); //Latest unauthorized token, user has no permissions should get the latest Published version @@ -1327,6 +1341,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Specific version authorized token @@ -1335,6 +1350,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Specific version unauthorized token @@ -1343,6 +1359,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //We deaccession the dataset @@ -1359,6 +1376,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Latest published requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1371,6 +1389,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(2)); //Latest unauthorized token requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1383,6 +1402,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Specific version unauthorized token requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets. @@ -1398,6 +1418,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest published exclude files, should get the DEACCESSIONED version @@ -1406,6 +1427,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest authorized token should get the DRAFT version with no files @@ -1414,6 +1436,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest unauthorized token excluding files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1422,6 +1445,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version authorized token @@ -1430,6 +1454,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version unauthorized token requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets. @@ -1438,6 +1463,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Set of test when we have a deaccessioned dataset but we don't include deaccessioned @@ -1460,6 +1486,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(2)); //Latest unauthorized token one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1494,6 +1521,7 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest unauthorized token one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1510,6 +1538,28 @@ public void testDatasetVersionsAPI() { datasetVersion = UtilIT.getDatasetVersion(datasetPid, specificVersion, apiTokenNoPerms, excludeFiles, includeDeaccessioned); datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(NOT_FOUND.getStatusCode()); + + // Now we request review for the dataset, and check that this is reflected in the API responses + + Response submitForReview = UtilIT.submitDatasetForReview(datasetPid, apiToken); + submitForReview.prettyPrint(); + submitForReview.then().assertThat() + .statusCode(OK.getStatusCode()); + + datasetVersion = UtilIT.getDatasetVersion(datasetPid, DS_VERSION_LATEST, apiToken); + datasetVersion.prettyPrint(); + datasetVersion.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.versionState", equalTo("DRAFT")) + .body("data.isInReviewState", equalTo(true)) + .body("data.latestVersionPublishingState", equalTo("DRAFT")); + + versionsResponse = UtilIT.getDatasetVersions(datasetPid, apiToken); + versionsResponse.prettyPrint(); + versionsResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.versionState[0]", equalTo("DRAFT")) + .body("data[0].isInReviewState", equalTo(true)); } From 76026b1bf328a5777a0b801e45b5b5fd081325a1 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Thu, 27 Nov 2025 16:41:07 +0100 Subject: [PATCH 3/9] docs: add "isInReviewState" to API responses about dataset versions --- doc/release-notes/12008-is-in-review-state.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/release-notes/12008-is-in-review-state.md diff --git a/doc/release-notes/12008-is-in-review-state.md b/doc/release-notes/12008-is-in-review-state.md new file mode 100644 index 00000000000..f0162c328c4 --- /dev/null +++ b/doc/release-notes/12008-is-in-review-state.md @@ -0,0 +1 @@ +The APIs returning information about dataset versions (`/api/datasets/{id}/versions` and `/api/datasets/{id}/versions/{vid}`) now include an `isInReviewState` field indicating whether a specific version is currently under review. \ No newline at end of file From 335a40418520c7bda4c6a10a89fe2841074eb993 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Fri, 23 Jan 2026 15:44:40 +0100 Subject: [PATCH 4/9] Revert "docs: add "isInReviewState" to API responses about dataset versions" This reverts commit 76026b1bf328a5777a0b801e45b5b5fd081325a1. --- doc/release-notes/12008-is-in-review-state.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 doc/release-notes/12008-is-in-review-state.md diff --git a/doc/release-notes/12008-is-in-review-state.md b/doc/release-notes/12008-is-in-review-state.md deleted file mode 100644 index f0162c328c4..00000000000 --- a/doc/release-notes/12008-is-in-review-state.md +++ /dev/null @@ -1 +0,0 @@ -The APIs returning information about dataset versions (`/api/datasets/{id}/versions` and `/api/datasets/{id}/versions/{vid}`) now include an `isInReviewState` field indicating whether a specific version is currently under review. \ No newline at end of file From 5f76efc416d8333420e90b34599fe500a5a48d75 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Fri, 23 Jan 2026 15:44:40 +0100 Subject: [PATCH 5/9] Revert "test: add "isInReviewState" to API responses about dataset versions" This reverts commit 046d9698955a213b2fd909399a6ec032fe74d97a. --- .../harvard/iq/dataverse/api/DatasetsIT.java | 50 ------------------- 1 file changed, 50 deletions(-) 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 e424fed4ebd..b7cbb37480c 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1169,7 +1169,6 @@ public void testDatasetVersionsAPI() { datasetVersion.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.latestVersionPublishingState", equalTo("RELEASED")); // Upload another file: @@ -1183,7 +1182,6 @@ public void testDatasetVersionsAPI() { datasetVersion.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.latestVersionPublishingState", equalTo("DRAFT")); datasetVersion = UtilIT.getDatasetVersion(datasetPid, DS_VERSION_LATEST, apiTokenNoPerms, excludeFiles, includeDeaccessioned); @@ -1191,7 +1189,6 @@ public void testDatasetVersionsAPI() { datasetVersion.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.latestVersionPublishingState", equalTo("DRAFT")); // We should now have a published version, and a draft. @@ -1218,7 +1215,6 @@ public void testDatasetVersionsAPI() { .statusCode(OK.getStatusCode()) .body("data.size()", equalTo(1)) .body("data.versionState[0]", equalTo("DRAFT")) - .body("data[0].isInReviewState", equalTo(false)) .body("data[0].files.size()", equalTo(2)); // And now call it with an un-privileged token, to make sure only one @@ -1228,7 +1224,6 @@ public void testDatasetVersionsAPI() { versionsResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.versionState[0]", not("DRAFT")) - .body("data[0].isInReviewState", equalTo(false)) .body("data.size()", equalTo(1)); // And now call the "short", no-files version of the same api @@ -1251,7 +1246,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest published unauthorized token @@ -1260,7 +1254,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest authorized token @@ -1269,7 +1262,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest unauthorized token @@ -1278,7 +1270,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version authorized token @@ -1287,7 +1278,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version unauthorized token @@ -1296,7 +1286,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); excludeFiles = false; @@ -1307,7 +1296,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Latest published unauthorized token @@ -1316,7 +1304,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Latest authorized token, user is authenticated should get the Draft version @@ -1325,7 +1312,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(2)); //Latest unauthorized token, user has no permissions should get the latest Published version @@ -1334,7 +1320,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Specific version authorized token @@ -1343,7 +1328,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Specific version unauthorized token @@ -1352,7 +1336,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("RELEASED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //We deaccession the dataset @@ -1369,7 +1352,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Latest published requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1382,7 +1364,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(2)); //Latest unauthorized token requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1395,7 +1376,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(1)); //Specific version unauthorized token requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets. @@ -1411,7 +1391,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest published exclude files, should get the DEACCESSIONED version @@ -1420,7 +1399,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest authorized token should get the DRAFT version with no files @@ -1429,7 +1407,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest unauthorized token excluding files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1438,7 +1415,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version authorized token @@ -1447,7 +1423,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Specific version unauthorized token requesting files, one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets. @@ -1456,7 +1431,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DEACCESSIONED")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Set of test when we have a deaccessioned dataset but we don't include deaccessioned @@ -1479,7 +1453,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.files.size()", equalTo(2)); //Latest unauthorized token one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1514,7 +1487,6 @@ public void testDatasetVersionsAPI() { datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(OK.getStatusCode()) .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(false)) .body("data.files", equalTo(null)); //Latest unauthorized token one version is DEACCESSIONED the second is DRAFT so shouldn't get any datasets @@ -1531,28 +1503,6 @@ public void testDatasetVersionsAPI() { datasetVersion = UtilIT.getDatasetVersion(datasetPid, specificVersion, apiTokenNoPerms, excludeFiles, includeDeaccessioned); datasetVersion.prettyPrint(); datasetVersion.then().assertThat().statusCode(NOT_FOUND.getStatusCode()); - - // Now we request review for the dataset, and check that this is reflected in the API responses - - Response submitForReview = UtilIT.submitDatasetForReview(datasetPid, apiToken); - submitForReview.prettyPrint(); - submitForReview.then().assertThat() - .statusCode(OK.getStatusCode()); - - datasetVersion = UtilIT.getDatasetVersion(datasetPid, DS_VERSION_LATEST, apiToken); - datasetVersion.prettyPrint(); - datasetVersion.then().assertThat() - .statusCode(OK.getStatusCode()) - .body("data.versionState", equalTo("DRAFT")) - .body("data.isInReviewState", equalTo(true)) - .body("data.latestVersionPublishingState", equalTo("DRAFT")); - - versionsResponse = UtilIT.getDatasetVersions(datasetPid, apiToken); - versionsResponse.prettyPrint(); - versionsResponse.then().assertThat() - .statusCode(OK.getStatusCode()) - .body("data.versionState[0]", equalTo("DRAFT")) - .body("data[0].isInReviewState", equalTo(true)); } From 14f10772626079690cc254831c3009e31a5092d2 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Fri, 23 Jan 2026 15:44:40 +0100 Subject: [PATCH 6/9] Revert "feat: add "isInReviewState" to API responses about dataset versions" This reverts commit 8b559c6bc4289d1f16ba80d4625e9f927c5ae8b5. --- .../java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 67788e8a15c..27b7a122c93 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -534,7 +534,6 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List anonymized .add("internalVersionNumber", dsv.getVersion()) .add("versionMinorNumber", dsv.getMinorVersionNumber()) .add("versionState", dsv.getVersionState().name()) - .add("isInReviewState", dsv.isInReview()) .add("latestVersionPublishingState", dataset.getLatestVersion().getVersionState().name()) .add("deaccessionNote", dsv.getDeaccessionNote()) .add("deaccessionLink", dsv.getDeaccessionLink()) From 606515300d6d6f13fe88aacf0c167db66e42cbad Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Fri, 23 Jan 2026 15:47:26 +0100 Subject: [PATCH 7/9] feat: add "locks" to API responses for GET /api/datasets/$ID --- .../edu/harvard/iq/dataverse/util/json/JsonPrinter.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 27b7a122c93..11a3e7b53d8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -486,6 +486,13 @@ public static JsonObjectBuilder json(Dataset ds, Boolean returnOwners) { bld.add("isPartOf", getOwnersFromDvObject(ds)); } bld.add("datasetType", ds.getDatasetType().getName()); + + JsonArrayBuilder locksArrayBuilder = Json.createArrayBuilder(); + for (DatasetLock lock : ds.getLocks()) { + locksArrayBuilder.add(lock.getReason().toString()); + } + bld.add("locks", locksArrayBuilder); + return bld; } From f14863a66fa77b0b93222084f1aed56626226d27 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Fri, 23 Jan 2026 15:48:06 +0100 Subject: [PATCH 8/9] test: add "locks" to API responses for GET /api/datasets/$ID --- .../edu/harvard/iq/dataverse/api/DatasetsIT.java | 16 +++++++++++++++- .../iq/dataverse/api/InReviewWorkflowIT.java | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) 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 b7cbb37480c..d9e21d9fdc7 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -3077,12 +3077,19 @@ public void testDatasetLocksApi() { .statusCode(200); // Check again: - // This should return an empty list, as the dataset should have no locks just yet: + // This should no longer return an empty list, as the dataset now has a lock: checkDatasetLocks = UtilIT.checkDatasetLocks(datasetId.longValue(), "Ingest", apiToken); checkDatasetLocks.prettyPrint(); checkDatasetLocks.then().assertThat() .body("data[0].lockType", equalTo("Ingest")) .statusCode(200); + + // Confirm that when getting the dataset, the lock is also listed + Response getDatasetJson = UtilIT.nativeGet(datasetId, apiToken); + getDatasetJson.prettyPrint(); + getDatasetJson.then().assertThat() + .body("data.locks[0]", equalTo("Ingest")) + .statusCode(200); // Try to lock the dataset with the same type lock, AGAIN // (this should fail, of course!) @@ -3197,6 +3204,13 @@ public void testDatasetLocksApi() { checkDatasetLocks.then().assertThat() .body("data", equalTo(emptyArray)) .statusCode(200); + + // Confirm that when getting the dataset, the lock is also no longer listed + getDatasetJson = UtilIT.nativeGet(datasetId, apiToken); + getDatasetJson.prettyPrint(); + getDatasetJson.then().assertThat() + .body("data.locks", equalTo(emptyArray)) + .statusCode(200); } /** diff --git a/src/test/java/edu/harvard/iq/dataverse/api/InReviewWorkflowIT.java b/src/test/java/edu/harvard/iq/dataverse/api/InReviewWorkflowIT.java index a2bef649c72..77fa9a64f2e 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/InReviewWorkflowIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/InReviewWorkflowIT.java @@ -6,6 +6,7 @@ import io.restassured.response.Response; import edu.harvard.iq.dataverse.authorization.DataverseRole; import jakarta.json.Json; +import jakarta.json.JsonArray; import jakarta.json.JsonObjectBuilder; import static edu.harvard.iq.dataverse.UserNotification.Type.*; @@ -120,6 +121,13 @@ public void testCuratorSendsCommentsToAuthor() { .body("message", equalTo("You cannot submit this dataset for review because it is already in review.")) .statusCode(FORBIDDEN.getStatusCode()); + // Confirm that when getting the dataset, the "InReview" lock is listed + Response getDatasetJson = UtilIT.nativeGet(datasetId, authorApiToken); + getDatasetJson.prettyPrint(); + getDatasetJson.then().assertThat() + .body("data.locks[0]", equalTo("InReview")) + .statusCode(200); + Response authorsChecksForCommentsPrematurely = UtilIT.getNotifications(authorApiToken); authorsChecksForCommentsPrematurely.prettyPrint(); authorsChecksForCommentsPrematurely.then().assertThat() @@ -429,6 +437,14 @@ public void testCuratorSendsCommentsToAuthor() { // .body("data[3].reasonsForReturn", equalTo(null)) .statusCode(OK.getStatusCode()); + // Confirm that when getting the dataset, the "InReview" lock is no longer listed + JsonArray emptyArray = Json.createArrayBuilder().build(); + getDatasetJson = UtilIT.nativeGet(datasetId, authorApiToken); + getDatasetJson.prettyPrint(); + getDatasetJson.then().assertThat() + .body("data.locks", equalTo(emptyArray)) + .statusCode(200); + // These println's are here in case you want to log into the GUI to see what notifications look like. System.out.println("Curator username/password: " + curatorUsername); System.out.println("Author username/password: " + authorUsername); From ce64b0120cb0a2ac9a839cd8d662feb2c7a85065 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Fri, 23 Jan 2026 15:48:11 +0100 Subject: [PATCH 9/9] docs: add "locks" to API responses for GET /api/datasets/$ID --- doc/release-notes/12008-dataset-api-locks.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/release-notes/12008-dataset-api-locks.md diff --git a/doc/release-notes/12008-dataset-api-locks.md b/doc/release-notes/12008-dataset-api-locks.md new file mode 100644 index 00000000000..4eeba82b7af --- /dev/null +++ b/doc/release-notes/12008-dataset-api-locks.md @@ -0,0 +1 @@ +The API returning information about datasets (`/api/datasets/{id}`) now includes a `locks` field containing a list of the types of all existing locks, e.g. `"locks": ["InReview"]`.