Skip to content

Commit dcf5d49

Browse files
authored
Merge pull request #11610 from IQSS/11275-limit-number-of-dataset-files
make limit update a superuser only function
2 parents c000317 + 4163cb5 commit dcf5d49

File tree

11 files changed

+85
-55
lines changed

11 files changed

+85
-55
lines changed

doc/sphinx-guides/source/api/native-api.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,9 +2711,9 @@ The limit can be set via JVM setting :ref:`dataverse.files.default-dataset-file-
27112711

27122712
For Installation wide limit, the limit can be set via JVM. ./asadmin $ASADMIN_OPTS create-jvm-options "-Ddataverse.files.default-dataset-file-count-limit=<limit>"
27132713

2714-
For Collections, the attribute can be controlled by calling the Create or Update Dataverse API and adding ``datasetFileCountLimit=500`` to the Json body.
2714+
For Collections, the attribute can be controlled by calling the Create or Update Dataverse API and adding ``datasetFileCountLimit=500`` to the Json body (Must be a superuser to change this value).
27152715

2716-
For Datasets, the attribute can be set using the `Update Dataset Files Limit <#setting-the-files-count-limit-on-a-dataset>`_ API and passing the qp `fileCountLimit=500`.
2716+
For Datasets, the attribute can be set using the `Update Dataset Files Limit <#setting-the-files-count-limit-on-a-dataset>`_ API and passing the qp `fileCountLimit=500` (Must be a superuser to change this value).
27172717

27182718
Setting a value of -1 will clear the limit for that level. If no limit is found on the Dataset, the hierarchy of parent nodes will be checked until finally the JVM setting is checked.
27192719

@@ -2729,7 +2729,7 @@ Setting the files count limit on a Dataset
27292729
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27302730
In order to update the number of files allowed for a Dataset, without causing a Draft version of the Dataset being created, the following API can be used
27312731

2732-
.. note:: To clear the limit simply set the limit to -1 or call the DELETE API.
2732+
.. note:: To clear the limit simply set the limit to -1 or call the DELETE API (Must be a superuser to change this value).
27332733

27342734
.. code-block:: bash
27352735

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

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,6 +1984,9 @@ public Response updateDatasetFilesLimits(@Context ContainerRequestContext crc,
19841984
} catch (WrappedResponse ex) {
19851985
return error(Status.UNAUTHORIZED, "Authentication is required.");
19861986
}
1987+
if (!authenticatedUser.isSuperuser()) {
1988+
return error(Response.Status.FORBIDDEN, "Superusers only.");
1989+
}
19871990

19881991
Dataset dataset;
19891992
try {
@@ -1992,16 +1995,9 @@ public Response updateDatasetFilesLimits(@Context ContainerRequestContext crc,
19921995
return ex.getResponse();
19931996
}
19941997

1995-
if (authenticatedUser.isSuperuser() || permissionService.hasPermissionsFor(authenticatedUser, dataset,
1996-
EnumSet.of(Permission.EditDataset))) {
1997-
1998-
dataset.setDatasetFileCountLimit(datasetFileCountLimit);
1999-
datasetService.merge(dataset);
2000-
2001-
return ok("ok");
2002-
} else {
2003-
return error(Status.FORBIDDEN, "User is not a superuser or user does not have EditDataset permissions");
2004-
}
1998+
dataset.setDatasetFileCountLimit(datasetFileCountLimit);
1999+
datasetService.merge(dataset);
2000+
return ok("ok");
20052001
}
20062002

20072003
@DELETE
@@ -2016,6 +2012,9 @@ public Response deleteDatasetFilesLimits(@Context ContainerRequestContext crc,
20162012
} catch (WrappedResponse ex) {
20172013
return error(Status.UNAUTHORIZED, "Authentication is required.");
20182014
}
2015+
if (!authenticatedUser.isSuperuser()) {
2016+
return error(Response.Status.FORBIDDEN, "Superusers only.");
2017+
}
20192018

20202019
Dataset dataset;
20212020
try {
@@ -2024,16 +2023,9 @@ public Response deleteDatasetFilesLimits(@Context ContainerRequestContext crc,
20242023
return ex.getResponse();
20252024
}
20262025

2027-
if (authenticatedUser.isSuperuser() || permissionService.hasPermissionsFor(authenticatedUser, dataset,
2028-
EnumSet.of(Permission.EditDataset))) {
2029-
2030-
dataset.setDatasetFileCountLimit(null);
2031-
datasetService.merge(dataset);
2032-
2033-
return ok("ok");
2034-
} else {
2035-
return error(Status.FORBIDDEN, "User is not a superuser or user does not have EditDataset permissions");
2036-
}
2026+
dataset.setDatasetFileCountLimit(null);
2027+
datasetService.merge(dataset);
2028+
return ok("ok");
20372029
}
20382030

20392031
@PUT

src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseCommand.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import edu.harvard.iq.dataverse.engine.command.RequiredPermissions;
1212
import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException;
1313
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
14+
import edu.harvard.iq.dataverse.util.BundleUtil;
1415

1516
import java.sql.Timestamp;
1617
import java.util.ArrayList;
@@ -50,6 +51,9 @@ protected Dataverse innerExecute(CommandContext ctxt) throws IllegalCommandExcep
5051
throw new IllegalCommandException("Root Dataverse already exists. Cannot create another one", this);
5152
}
5253
}
54+
if (!getUser().isSuperuser() && dataverse.isDatasetFileCountLimitSet(dataverse.getDatasetFileCountLimit())) {
55+
throw new IllegalCommandException(BundleUtil.getStringFromBundle("file.dataset.error.set.file.count.limit"), this);
56+
}
5357

5458
if (metadataBlocks != null && !metadataBlocks.isEmpty()) {
5559
dataverse.setMetadataBlockRoot(true);

src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseCommand.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
1212
import edu.harvard.iq.dataverse.engine.command.RequiredPermissions;
1313
import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException;
14+
import edu.harvard.iq.dataverse.util.BundleUtil;
1415

1516
import java.util.ArrayList;
1617
import java.util.List;
@@ -66,6 +67,14 @@ protected Dataverse innerExecute(CommandContext ctxt) throws IllegalCommandExcep
6667
}
6768
}
6869
}
70+
if (!getUser().isSuperuser() && updatedDataverseDTO != null) {
71+
// default if not set
72+
if (updatedDataverseDTO.getDatasetFileCountLimit() == null) {
73+
updatedDataverseDTO.setDatasetFileCountLimit(dataverse.getDatasetFileCountLimit());
74+
} else if (updatedDataverseDTO.getDatasetFileCountLimit() != dataverse.getDatasetFileCountLimit()) {
75+
throw new IllegalCommandException(BundleUtil.getStringFromBundle("file.dataset.error.set.file.count.limit"), this);
76+
}
77+
}
6978

7079
Dataverse oldDv = ctxt.dataverses().find(dataverse.getId());
7180

src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ public Dataverse parseDataverse(JsonObject jobj) throws JsonParseException {
134134
dv.setPermissionRoot(jobj.getBoolean("permissionRoot", false));
135135
dv.setFacetRoot(jobj.getBoolean("facetRoot", false));
136136
dv.setAffiliation(jobj.getString("affiliation", null));
137-
dv.setDatasetFileCountLimit(jobj.getInt("datasetFileCountLimit", -1));
137+
if (jobj.containsKey("datasetFileCountLimit")) {
138+
dv.setDatasetFileCountLimit(jobj.getInt("datasetFileCountLimit", -1));
139+
}
138140

139141
if (jobj.containsKey("dataverseContacts")) {
140142
JsonArray dvContacts = jobj.getJsonArray("dataverseContacts");

src/main/java/propertyFiles/Bundle.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2385,6 +2385,7 @@ file.message.replaceSuccess=The file has been replaced.
23852385

23862386
# File Add/Replace operation messages
23872387
file.add.count_exceeds_limit=Number of files can not exceed the maximum number of files allowed for this Dataset ({0}).
2388+
file.dataset.error.set.file.count.limit=Only Superuser can set the Dataset File Count Limit.
23882389
file.addreplace.file_size_ok=File size is in range.
23892390
file.addreplace.error.byte_abrev=B
23902391
file.addreplace.error.file_exceeds_limit=This file size ({0}) exceeds the size limit of {1}.
@@ -3222,4 +3223,4 @@ updateDatasetFieldsCommand.api.processDatasetUpdate.parseError=Error parsing dat
32223223
abstractApiBean.error.datasetInternalVersionNumberIsOutdated=Dataset internal version number {0} is outdated
32233224

32243225
#RoleAssigneeServiceBean.java
3225-
roleAssigneeServiceBean.error.dataverseRequestCannotBeNull=DataverseRequest cannot be null.
3226+
roleAssigneeServiceBean.error.dataverseRequestCannotBeNull=DataverseRequest cannot be null.

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

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@
1212
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
1313
import edu.harvard.iq.dataverse.util.BundleUtil;
1414
import edu.harvard.iq.dataverse.util.SystemConfig;
15-
import edu.harvard.iq.dataverse.util.json.JSONLDUtil;
16-
import edu.harvard.iq.dataverse.util.json.JsonParseException;
17-
import edu.harvard.iq.dataverse.util.json.JsonParser;
18-
import edu.harvard.iq.dataverse.util.json.JsonUtil;
15+
import edu.harvard.iq.dataverse.util.json.*;
1916
import io.restassured.RestAssured;
2017
import io.restassured.http.ContentType;
2118
import io.restassured.parsing.Parser;
@@ -370,12 +367,16 @@ public void testCreateDataset() {
370367
public void testCreateUpdateDatasetFileCountLimit() throws JsonParseException {
371368
Response createUser = UtilIT.createRandomUser();
372369
String apiToken = UtilIT.getApiTokenFromResponse(createUser);
373-
Response createDataverseResponse = createFileLimitedDataverse(500, apiToken);
370+
String adminApiToken = getSuperuserToken();
371+
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
374372
createDataverseResponse.prettyPrint();
375373
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
376374
JsonObject data = JsonUtil.getJsonObject(createDataverseResponse.getBody().asString());
377375
JsonParser parser = new JsonParser();
378376
Dataverse dv = parser.parseDataverse(data.getJsonObject("data"));
377+
dv.setDatasetFileCountLimit(500);
378+
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, adminApiToken);
379+
updateDataverseResponse.prettyPrint();
379380

380381
JsonArrayBuilder metadataBlocks = Json.createArrayBuilder();
381382
metadataBlocks.add("citation");
@@ -411,7 +412,7 @@ public void testCreateUpdateDatasetFileCountLimit() throws JsonParseException {
411412
String persistentId = JsonPath.from(datasetAsJson.getBody().asString()).getString("data.latestVersion.datasetPersistentId");
412413

413414
// Update dataset with datasetFileCountLimit = 1
414-
Response updateDatasetResponse = UtilIT.updateDatasetFilesLimits(persistentId, 1, apiToken);
415+
Response updateDatasetResponse = UtilIT.updateDatasetFilesLimits(persistentId, 1, adminApiToken);
415416
updateDatasetResponse.prettyPrint();
416417
updateDatasetResponse.then().assertThat()
417418
.statusCode(OK.getStatusCode());
@@ -424,7 +425,7 @@ public void testCreateUpdateDatasetFileCountLimit() throws JsonParseException {
424425
.body("data.datasetFileCountLimit", equalTo(1));
425426

426427
// Update/reset dataset with datasetFileCountLimit = -1 and expect the value from the owner dataverse
427-
updateDatasetResponse = UtilIT.deleteDatasetFilesLimits(persistentId, apiToken);
428+
updateDatasetResponse = UtilIT.deleteDatasetFilesLimits(persistentId, adminApiToken);
428429
updateDatasetResponse.prettyPrint();
429430
updateDatasetResponse.then().assertThat()
430431
.statusCode(OK.getStatusCode());
@@ -438,7 +439,7 @@ public void testCreateUpdateDatasetFileCountLimit() throws JsonParseException {
438439

439440
// test clear limits and test that datasetFileCountLimit is not returned in json
440441
dv.setDatasetFileCountLimit(null);
441-
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, apiToken);
442+
updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, adminApiToken);
442443
updateDataverseResponse.then().assertThat()
443444
.statusCode(OK.getStatusCode());
444445

@@ -451,12 +452,20 @@ public void testCreateUpdateDatasetFileCountLimit() throws JsonParseException {
451452
}
452453

453454
@Test
454-
public void testMultipleFileUploadOverCountLimit() {
455+
public void testMultipleFileUploadOverCountLimit() throws JsonParseException {
455456
Response createUser = UtilIT.createRandomUser();
456457
String apiToken = UtilIT.getApiTokenFromResponse(createUser);
457-
Response createDataverseResponse = createFileLimitedDataverse(1, apiToken);
458+
String adminApiToken = getSuperuserToken();
459+
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
458460
createDataverseResponse.prettyPrint();
459461
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
462+
JsonObject data = JsonUtil.getJsonObject(createDataverseResponse.getBody().asString());
463+
JsonParser parser = new JsonParser();
464+
Dataverse dv = parser.parseDataverse(data.getJsonObject("data"));
465+
dv.setDatasetFileCountLimit(1);
466+
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, adminApiToken);
467+
updateDataverseResponse.prettyPrint();
468+
460469
Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken);
461470
createDatasetResponse.prettyPrint();
462471
Integer datasetId = UtilIT.getDatasetIdFromResponse(createDatasetResponse);
@@ -6769,19 +6778,11 @@ public void testUpdateMultipleFileMetadata() {
67696778
.statusCode(OK.getStatusCode());
67706779
}
67716780

6772-
private Response createFileLimitedDataverse(int datasetFileCountLimit, String apiToken) {
6773-
String dataverseAlias = UtilIT.getRandomDvAlias();
6774-
String emailAddressOfFirstDataverseContact = dataverseAlias + "@mailinator.com";
6775-
JsonObjectBuilder jsonToCreateDataverse = Json.createObjectBuilder()
6776-
.add("name", dataverseAlias)
6777-
.add("alias", dataverseAlias)
6778-
.add("datasetFileCountLimit", datasetFileCountLimit)
6779-
.add("dataverseContacts", Json.createArrayBuilder()
6780-
.add(Json.createObjectBuilder()
6781-
.add("contactEmail", emailAddressOfFirstDataverseContact)
6782-
)
6783-
);
6784-
;
6785-
return UtilIT.createDataverse(jsonToCreateDataverse.build(), apiToken);
6781+
private String getSuperuserToken() {
6782+
Response createResponse = UtilIT.createRandomUser();
6783+
String adminApiToken = UtilIT.getApiTokenFromResponse(createResponse);
6784+
String username = UtilIT.getUsernameFromResponse(createResponse);
6785+
UtilIT.makeSuperUser(username);
6786+
return adminApiToken;
67866787
}
67876788
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,7 @@ public void testAddDataverse() {
13551355

13561356
@Test
13571357
public void testUpdateDataverse() throws JsonParseException {
1358+
String adminApiToken = getSuperuserToken();
13581359
Response createUser = UtilIT.createRandomUser();
13591360
String apiToken = UtilIT.getApiTokenFromResponse(createUser);
13601361
String testAliasSuffix = "-update-dataverse";
@@ -1372,7 +1373,7 @@ public void testUpdateDataverse() throws JsonParseException {
13721373
JsonParser parser = new JsonParser();
13731374
Dataverse dv = parser.parseDataverse(data.getJsonObject("data"));
13741375
dv.setDatasetFileCountLimit(500);
1375-
Response updateDataverseResponse = UtilIT.updateDataverse(testDataverseAlias, dv, apiToken);
1376+
Response updateDataverseResponse = UtilIT.updateDataverse(testDataverseAlias, dv, adminApiToken);
13761377
updateDataverseResponse.prettyPrint();
13771378
updateDataverseResponse.then().assertThat()
13781379
.statusCode(OK.getStatusCode())
@@ -2282,4 +2283,12 @@ public void testUpdateInputLevelDisplayOnCreateOverride() {
22822283
.body("data.inputLevels[0].datasetFieldTypeName", equalTo("subtitle"));
22832284

22842285
}
2286+
2287+
private String getSuperuserToken() {
2288+
Response createResponse = UtilIT.createRandomUser();
2289+
String adminApiToken = UtilIT.getApiTokenFromResponse(createResponse);
2290+
String username = UtilIT.getUsernameFromResponse(createResponse);
2291+
UtilIT.makeSuperUser(username);
2292+
return adminApiToken;
2293+
}
22852294
}

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,7 +3227,7 @@ public void testUploadFilesWithLimits() throws JsonParseException {
32273227
JsonParser parser = new JsonParser();
32283228
Dataverse dv = parser.parseDataverse(data.getJsonObject("data"));
32293229
dv.setDatasetFileCountLimit(1);
3230-
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, apiToken);
3230+
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, adminApiToken);
32313231
updateDataverseResponse.then().assertThat()
32323232
.statusCode(OK.getStatusCode())
32333233
.body("data.effectiveDatasetFileCountLimit", equalTo(1))
@@ -3261,7 +3261,8 @@ public void testUploadFilesWithLimits() throws JsonParseException {
32613261

32623262
// Add 1 to file limit and upload a second file
32633263
dv.setDatasetFileCountLimit(2);
3264-
updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, apiToken);updateDataverseResponse.then().assertThat()
3264+
updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, adminApiToken);
3265+
updateDataverseResponse.then().assertThat()
32653266
.statusCode(OK.getStatusCode())
32663267
.body("data.effectiveDatasetFileCountLimit", equalTo(2))
32673268
.body("data.datasetFileCountLimit", equalTo(2));
@@ -3273,7 +3274,8 @@ public void testUploadFilesWithLimits() throws JsonParseException {
32733274

32743275
// Set limit back to 1 even though the number of files is 2
32753276
dv.setDatasetFileCountLimit(1);
3276-
updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, apiToken);updateDataverseResponse.then().assertThat()
3277+
updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, adminApiToken);
3278+
updateDataverseResponse.then().assertThat()
32773279
.statusCode(OK.getStatusCode())
32783280
.body("data.effectiveDatasetFileCountLimit", equalTo(1))
32793281
.body("data.datasetFileCountLimit", equalTo(1));
@@ -3302,5 +3304,13 @@ public void testUploadFilesWithLimits() throws JsonParseException {
33023304
uploadFileResponse.prettyPrint();
33033305
uploadFileResponse.then().assertThat()
33043306
.statusCode(OK.getStatusCode());
3307+
3308+
// Test changing the limit by a non-superuser
3309+
dv.setDatasetFileCountLimit(100);
3310+
updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, apiToken);
3311+
updateDataverseResponse.prettyPrint();
3312+
updateDataverseResponse.then().assertThat()
3313+
.body("message", containsString(BundleUtil.getStringFromBundle("file.dataset.error.set.file.count.limit")))
3314+
.statusCode(FORBIDDEN.getStatusCode());
33053315
}
33063316
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ public void testDirectUploadWithFileCountLimit() throws JsonParseException {
679679
JsonParser parser = new JsonParser();
680680
Dataverse dv = parser.parseDataverse(data.getJsonObject("data"));
681681
dv.setDatasetFileCountLimit(1);
682-
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, apiToken);
682+
Response updateDataverseResponse = UtilIT.updateDataverse(dataverseAlias, dv, superuserApiToken); // only superuser can update the datasetFileCountLimit
683683
updateDataverseResponse.prettyPrint();
684684
updateDataverseResponse.then().assertThat()
685685
.statusCode(OK.getStatusCode())

0 commit comments

Comments
 (0)