diff --git a/doc/release-notes/11534-link-permissions.md b/doc/release-notes/11534-link-permissions.md deleted file mode 100644 index 29251c1b7d9..00000000000 --- a/doc/release-notes/11534-link-permissions.md +++ /dev/null @@ -1,3 +0,0 @@ -Linking or unlinking a dataset or dataverse now requires the new "Link Dataset/Dataverse" permission. -Previously, this action was covered by the "Publish Dataset/Dataverse" permission. -Linking and publishing permissions can now be granted separately, allowing for more fine-grained access control. \ No newline at end of file diff --git a/doc/sphinx-guides/source/admin/dataverses-datasets.rst b/doc/sphinx-guides/source/admin/dataverses-datasets.rst index a37819c90e1..c6d325a9651 100644 --- a/doc/sphinx-guides/source/admin/dataverses-datasets.rst +++ b/doc/sphinx-guides/source/admin/dataverses-datasets.rst @@ -118,7 +118,7 @@ Moves a dataset whose id is passed to a Dataverse collection whose alias is pass Link a Dataset ^^^^^^^^^^^^^^ -Creates a link between a dataset and a Dataverse collection (see the :ref:`dataset-linking` section of the User Guide for more information). Accessible to users with Link Dataset permission on the Dataverse collection. :: +Creates a link between a dataset and a Dataverse collection (see the :ref:`dataset-linking` section of the User Guide for more information). :: curl -H "X-Dataverse-key: $API_TOKEN" -X PUT http://$SERVER/api/datasets/$linked-dataset-id/link/$linking-dataverse-alias @@ -155,7 +155,7 @@ It returns a list in the following format (new format as of v6.4): Unlink a Dataset ^^^^^^^^^^^^^^^^ -Removes a link between a dataset and a Dataverse collection. Accessible to users with Link Dataset permission on the Dataverse collection. :: +Removes a link between a dataset and a Dataverse collection. Accessible to users with Publish Dataset permissions. :: curl -H "X-Dataverse-key: $API_TOKEN" -X DELETE http://$SERVER/api/datasets/$linked-dataset-id/deleteLink/$linking-dataverse-alias diff --git a/doc/sphinx-guides/source/user/dataverse-management.rst b/doc/sphinx-guides/source/user/dataverse-management.rst index 96e8522af34..d88d0a45e68 100755 --- a/doc/sphinx-guides/source/user/dataverse-management.rst +++ b/doc/sphinx-guides/source/user/dataverse-management.rst @@ -215,7 +215,7 @@ Dataset linking allows a Dataverse collection owner to "link" their Dataverse co For example, researchers working on a collaborative study across institutions can each link their own individual institutional Dataverse collections to the one collaborative dataset, making it easier for interested parties from each institution to find the study. -In order to link a dataset, you will need your account to have the "Link Dataset" permission on the Dataverse collection that is doing the linking. If you created the Dataverse collection then you should have this permission already, but if not then you will need to ask the admin of that Dataverse collection to assign that permission to your account. You do not need any special permissions on the dataset being linked. +In order to link a dataset, you will need your account to have the "Publish Dataset" permission on the Dataverse collection that is doing the linking. If you created the Dataverse collection then you should have this permission already, but if not then you will need to ask the admin of that Dataverse collection to assign that permission to your account. You do not need any special permissions on the dataset being linked. To link a dataset to your Dataverse collection, you must navigate to that dataset and click the white "Link" button in the upper-right corner of the dataset page. This will open up a window where you can type in the name of the Dataverse collection that you would like to link the dataset to. Select your Dataverse collection and click the save button. This will establish the link, and the dataset will now appear under your Dataverse collection. diff --git a/scripts/api/data/role-curator.json b/scripts/api/data/role-curator.json index 86f18b2ea6a..91cb7ec43e2 100644 --- a/scripts/api/data/role-curator.json +++ b/scripts/api/data/role-curator.json @@ -1,14 +1,13 @@ { "alias":"curator", "name":"Curator", - "description":"For datasets, a person who can edit License + Terms, edit Permissions, and publish and link datasets.", + "description":"For datasets, a person who can edit License + Terms, edit Permissions, and publish datasets.", "permissions":[ "ViewUnpublishedDataset", "EditDataset", "DownloadFile", "DeleteDatasetDraft", "PublishDataset", - "LinkDataset", "ManageDatasetPermissions", "ManageFilePermissions", "AddDataverse", diff --git a/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java index 3879b8a3c81..f89e707cc03 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataverseServiceBean.java @@ -512,7 +512,7 @@ public List filterDataversesForLinking(String query, DataverseRequest for (Dataverse res : results) { if (!remove.contains(res)) { - if (this.permissionService.requestOn(req, res).has(Permission.LinkDataset)) { + if (this.permissionService.requestOn(req, res).has(Permission.PublishDataset)) { dataverseList.add(res); } } @@ -525,7 +525,7 @@ public List filterDataversesForUnLinking(String query, DataverseReque List dataverseList = new ArrayList<>(); if (alreadyLinkeddv_ids != null && !alreadyLinkeddv_ids.isEmpty()) { alreadyLinkeddv_ids.stream().map((testDVId) -> this.find(testDVId)).forEachOrdered((dataverse) -> { - if (this.permissionService.requestOn(req, dataverse).has(Permission.LinkDataset)) { + if (this.permissionService.requestOn(req, dataverse).has(Permission.PublishDataset)) { dataverseList.add(dataverse); } }); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/Permission.java b/src/main/java/edu/harvard/iq/dataverse/authorization/Permission.java index 83dc9965f6f..32937098118 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/Permission.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/Permission.java @@ -48,9 +48,7 @@ public enum Permission implements java.io.Serializable { ManageDatasetPermissions(BundleUtil.getStringFromBundle("permission.managePermissionsDataset"), true, Dataset.class), ManageFilePermissions(BundleUtil.getStringFromBundle("permission.managePermissionsDataFile"), true, DataFile.class), PublishDataverse(BundleUtil.getStringFromBundle("permission.publishDataverse"), true, Dataverse.class), - LinkDataverse(BundleUtil.getStringFromBundle("permission.linkDataverse"), true, Dataverse.class), PublishDataset(BundleUtil.getStringFromBundle("permission.publishDataset"), true, Dataset.class, Dataverse.class), - LinkDataset(BundleUtil.getStringFromBundle("permission.linkDataset"), true, Dataset.class, Dataverse.class), // Delete DeleteDataverse(BundleUtil.getStringFromBundle("permission.deleteDataverse"), true, Dataverse.class), DeleteDatasetDraft(BundleUtil.getStringFromBundle("permission.deleteDataset"), true, Dataset.class); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDatasetLinkingDataverseCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDatasetLinkingDataverseCommand.java index adc973df6a9..7f5672c0cd7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDatasetLinkingDataverseCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDatasetLinkingDataverseCommand.java @@ -23,14 +23,14 @@ * @author sarahferry */ -@RequiredPermissions( Permission.LinkDataset ) +@RequiredPermissions( Permission.PublishDataset ) public class DeleteDatasetLinkingDataverseCommand extends AbstractCommand{ private final DatasetLinkingDataverse doomed; private final Dataset editedDs; private final boolean index; public DeleteDatasetLinkingDataverseCommand(DataverseRequest aRequest, Dataset editedDs , DatasetLinkingDataverse doomed, boolean index) { - super(aRequest, doomed.getLinkingDataverse()); + super(aRequest, editedDs); this.editedDs = editedDs; this.doomed = doomed; this.index = index; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDatasetCommand.java index 166ec3700a0..1225c892ac7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDatasetCommand.java @@ -26,7 +26,7 @@ * * @author skraffmiller */ -@RequiredPermissions(Permission.LinkDataset) +@RequiredPermissions(Permission.PublishDataset) public class LinkDatasetCommand extends AbstractCommand { private final Dataset linkedDataset; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDataverseCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDataverseCommand.java index 2e1aecc9a84..55fe96556a5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDataverseCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/LinkDataverseCommand.java @@ -31,7 +31,7 @@ * * @author skraffmiller */ -@RequiredPermissions(Permission.LinkDataverse) +@RequiredPermissions(Permission.PublishDataverse) public class LinkDataverseCommand extends AbstractCommand { private final Dataverse linkedDataverse; @@ -47,7 +47,7 @@ public LinkDataverseCommand(DataverseRequest aRequest, Dataverse dataverse, Data public DataverseLinkingDataverse execute(CommandContext ctxt) throws CommandException { if ((!(getUser() instanceof AuthenticatedUser) || !getUser().isSuperuser())) { throw new PermissionException("Link Dataverse can only be called by superusers.", - this, Collections.singleton(Permission.LinkDataverse), linkingDataverse); + this, Collections.singleton(Permission.PublishDataverse), linkingDataverse); } if (linkedDataverse.equals(linkingDataverse)) { throw new IllegalCommandException("Can't link a dataverse to itself", this); diff --git a/src/main/java/propertyFiles/BuiltInRoles.properties b/src/main/java/propertyFiles/BuiltInRoles.properties index 50dbb1ba80f..026df600a9c 100644 --- a/src/main/java/propertyFiles/BuiltInRoles.properties +++ b/src/main/java/propertyFiles/BuiltInRoles.properties @@ -3,7 +3,7 @@ role.admin.description=A person who has all permissions for dataverses, datasets role.contributor.name=Contributor role.contributor.description=For datasets, a person who can edit License + Terms, and then submit them for review. role.curator.name=Curator -role.curator.description=For datasets, a person who can edit License + Terms, edit Permissions, and publish and link datasets. +role.curator.description=For datasets, a person who can edit License + Terms, edit Permissions, and publish datasets. role.dscontributor.name=Dataset Creator role.dscontributor.description=A person who can add datasets within a dataverse. role.fullcontributor.name=Dataverse + Dataset Creator diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 6ba73aa3f84..e0f41ae971d 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2563,9 +2563,7 @@ permission.addDataverseDataverse=Add a dataverse within another dataverse permission.deleteDataset=Delete a dataset draft permission.deleteDataverse=Delete an unpublished dataverse permission.publishDataset=Publish a dataset -permission.linkDataset=Link a dataset to a dataverse permission.publishDataverse=Publish a dataverse -permission.linkDataverse=Link a dataverse to another dataverse permission.managePermissionsDataFile=Manage permissions for a file permission.managePermissionsDataset=Manage permissions for a dataset permission.managePermissionsDataverse=Manage permissions for a dataverse @@ -2926,9 +2924,7 @@ permission.EditDataset.label=EditDataset permission.ManageDataversePermissions.label=ManageDataversePermissions permission.ManageDatasetPermissions.label=ManageDatasetPermissions permission.PublishDataverse.label=PublishDataverse -permission.LinkDataverse.label=LinkDataverse permission.PublishDataset.label=PublishDataset -permission.LinkDataset.label=LinkDataset permission.DeleteDataverse.label=DeleteDataverse permission.DeleteDatasetDraft.label=DeleteDatasetDraft permission.ManageFilePermissions.label=ManageFilePermissions 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 c553395cd44..5cb85e124b3 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -2905,19 +2905,13 @@ public void testDcmChecksumValidationMessages() throws IOException, InterruptedE @Test public void testCreateDeleteDatasetLink() { - // Create superuser Response createUser = UtilIT.createRandomUser(); createUser.prettyPrint(); String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); + Response superuserResponse = UtilIT.makeSuperUser(username); - // Create another user that doesn't have permission to create/delete links - Response createUser2 = UtilIT.createRandomUser(); - createUser2.prettyPrint(); - String username2 = UtilIT.getUsernameFromResponse(createUser2); - String apiToken2 = UtilIT.getApiTokenFromResponse(createUser2); - Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); createDataverseResponse.prettyPrint(); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); @@ -2953,31 +2947,28 @@ public void testCreateDeleteDatasetLink() { publishDatasetForLinking.prettyPrint(); publishTargetDataverse.then().assertThat() .statusCode(OK.getStatusCode()); - - // Try to link the dataset to the new dataverse without LinkDataset permissions - createLinkingDatasetResponse = UtilIT.createDatasetLink(datasetId.longValue(), dataverseAlias, apiToken2); - createLinkingDatasetResponse.prettyPrint(); - createLinkingDatasetResponse.then().assertThat() - .body("message", equalTo("User @" + username2 + " is not permitted to perform requested action.")) - .statusCode(UNAUTHORIZED.getStatusCode()); - - // Link the dataset to the new dataverse + + // And link the dataset to this new dataverse: createLinkingDatasetResponse = UtilIT.createDatasetLink(datasetId.longValue(), dataverseAlias, apiToken); createLinkingDatasetResponse.prettyPrint(); createLinkingDatasetResponse.then().assertThat() .body("data.message", equalTo("Dataset " + datasetId +" linked successfully to " + dataverseAlias)) .statusCode(200); - // Try to delete the link without LinkDataset permissions + // Create a new user that doesn't have permission to delete the link + Response createUser2 = UtilIT.createRandomUser(); + createUser2.prettyPrint(); + String username2 = UtilIT.getUsernameFromResponse(createUser2); + String apiToken2 = UtilIT.getApiTokenFromResponse(createUser2); + // Try to delete the link without PublishDataset permissions Response deleteLinkingDatasetResponse = UtilIT.deleteDatasetLink(datasetId.longValue(), dataverseAlias, apiToken2); deleteLinkingDatasetResponse.prettyPrint(); deleteLinkingDatasetResponse.then().assertThat() .body("message", equalTo("User @" + username2 + " is not permitted to perform requested action.")) .statusCode(UNAUTHORIZED.getStatusCode()); - // Give the user curator rights for the target dataverse to show that they can add and delete the link later - // (Timing issues if you try to add or delete right after giving permission) - Response givePermissionResponse = UtilIT.grantRoleOnDataverse(dataverseAlias, "curator", "@" + username2, apiToken); + // Add the Curator role to this user to show that they can delete the link later. (Timing issues if you try to delete right after giving permission) + Response givePermissionResponse = UtilIT.grantRoleOnDataset(datasetPersistentId, "curator", "@" + username2, apiToken); givePermissionResponse.prettyPrint(); givePermissionResponse.then().assertThat() .statusCode(200); @@ -2990,16 +2981,17 @@ public void testCreateDeleteDatasetLink() { .body("data.message", equalTo("Link from Dataset " + datasetId + " to linked Dataverse " + dataverseAlias + " deleted")) .statusCode(200); - // And now test linking the dataset as user2 with new role as curator (link permissions): - createLinkingDatasetResponse = UtilIT.createDatasetLink(datasetId.longValue(), dataverseAlias, apiToken2); + // And re-link the dataset to this new dataverse: + createLinkingDatasetResponse = UtilIT.createDatasetLink(datasetId.longValue(), dataverseAlias, apiToken); createLinkingDatasetResponse.prettyPrint(); createLinkingDatasetResponse.then().assertThat() .body("data.message", equalTo("Dataset " + datasetId +" linked successfully to " + dataverseAlias)) .statusCode(200); - // And now test deleting it as user2 with new role as curator (link permissions): + // And now test deleting it as user2 with new role as curator (Publish permissions): deleteLinkingDatasetResponse = UtilIT.deleteDatasetLink(datasetId.longValue(), dataverseAlias, apiToken2); deleteLinkingDatasetResponse.prettyPrint(); + deleteLinkingDatasetResponse.then().assertThat() .body("data.message", equalTo("Link from Dataset " + datasetId + " to linked Dataverse " + dataverseAlias + " deleted")) .statusCode(200);