From 35aa097b5500fc6bfee572ac897d64cddf96877c Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 4 Mar 2021 11:35:32 -0500 Subject: [PATCH 01/17] #7633 fix named q so delete role works --- src/main/java/edu/harvard/iq/dataverse/RoleAssignment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/RoleAssignment.java b/src/main/java/edu/harvard/iq/dataverse/RoleAssignment.java index 6241f120f80..22d2679efb6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/RoleAssignment.java +++ b/src/main/java/edu/harvard/iq/dataverse/RoleAssignment.java @@ -42,7 +42,7 @@ @NamedQuery( name = "RoleAssignment.listByDefinitionPointId", query = "SELECT r FROM RoleAssignment r WHERE r.definitionPoint.id=:definitionPointId" ), @NamedQuery( name = "RoleAssignment.listByRoleId", - query = "SELECT r FROM RoleAssignment r WHERE r.role=:roleId" ), + query = "SELECT r FROM RoleAssignment r WHERE r.role.id=:roleId" ), @NamedQuery( name = "RoleAssignment.listByPrivateUrlToken", query = "SELECT r FROM RoleAssignment r WHERE r.privateUrlToken=:privateUrlToken" ), @NamedQuery( name = "RoleAssignment.deleteByAssigneeIdentifier_RoleIdDefinition_PointId", From 6fa216bb061bd0d33a993e51afef5cb47e375b5a Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Fri, 5 Mar 2021 13:09:41 -0500 Subject: [PATCH 02/17] #7633 add alias and delete built in --- .../iq/dataverse/api/AbstractApiBean.java | 32 ++++++++++++++++++ .../edu/harvard/iq/dataverse/api/Admin.java | 13 ++++++++ .../edu/harvard/iq/dataverse/api/Roles.java | 33 ++++++++++--------- .../authorization/DataverseRole.java | 24 +++++++------- src/main/java/propertyFiles/Bundle.properties | 4 +++ 5 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java index db0958800f8..b71625a36bd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java @@ -26,6 +26,7 @@ import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; +import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.authorization.RoleAssignee; import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; @@ -86,6 +87,7 @@ public abstract class AbstractApiBean { private static final Logger logger = Logger.getLogger(AbstractApiBean.class.getName()); private static final String DATAVERSE_KEY_HEADER_NAME = "X-Dataverse-key"; private static final String PERSISTENT_ID_KEY=":persistentId"; + private static final String ALIAS_KEY=":alias"; public static final String STATUS_ERROR = "ERROR"; public static final String STATUS_OK = "OK"; public static final String STATUS_WF_IN_PROGRESS = "WORKFLOW_IN_PROGRESS"; @@ -483,6 +485,36 @@ protected DataFile findDataFileOrDie(String id) throws WrappedResponse { } } + + + protected DataverseRole findRoleOrDie(String id) throws WrappedResponse { + DataverseRole role; + if (id.equals(ALIAS_KEY)) { + String alias = getRequestParameter(ALIAS_KEY.substring(1)); + role = em.createNamedQuery("DataverseRole.findDataverseRoleByAlias", DataverseRole.class) + .setParameter("alias", alias) + .getSingleResult(); + } else { + + role = rolesSvc.find(Long.parseLong(id)); + + try { + role = rolesSvc.find(Long.parseLong(id)); + if (role == null) { + throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.id", Collections.singletonList(id)))); + } + + } catch (NumberFormatException nfe) { + throw new WrappedResponse( + badRequest(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.bad.id", Collections.singletonList(id)))); + } + } + + + throw new WrappedResponse(notFound("role with id " + id + " not found")); + + } + protected DatasetLinkingDataverse findDatasetLinkingDataverseOrDie(String datasetId, String linkingDataverseId) throws WrappedResponse { DatasetLinkingDataverse dsld; Dataverse linkingDataverse = findDataverseOrDie(linkingDataverseId); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index b52665a7747..de2f2266761 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -76,6 +76,7 @@ import java.util.List; import edu.harvard.iq.dataverse.authorization.AuthTestDataServiceBean; import edu.harvard.iq.dataverse.authorization.AuthenticationProvidersRegistrationServiceBean; +import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.authorization.RoleAssignee; import edu.harvard.iq.dataverse.authorization.UserRecordIdentifier; import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroupServiceBean; @@ -87,6 +88,7 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.impl.MergeInAccountCommand; import edu.harvard.iq.dataverse.engine.command.impl.ChangeUserIdentifierCommand; +import edu.harvard.iq.dataverse.engine.command.impl.DeleteRoleCommand; import edu.harvard.iq.dataverse.engine.command.impl.RegisterDvObjectCommand; import edu.harvard.iq.dataverse.ingest.IngestServiceBean; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; @@ -890,6 +892,17 @@ public Response listBuiltinRoles() { return error(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage()); } } + + @DELETE + @Path("roles/{id}") + public Response deleteRole(@PathParam("id") String id) { + + return response(req -> { + DataverseRole doomed = findRoleOrDie(id); + execCommand(new DeleteRoleCommand(req, doomed)); + return ok("role " + doomed.getName() + " deleted."); + }); + } @Path("superuser/{identifier}") @POST diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Roles.java b/src/main/java/edu/harvard/iq/dataverse/api/Roles.java index b3f75e00c5a..72add184a24 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Roles.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Roles.java @@ -1,8 +1,10 @@ package edu.harvard.iq.dataverse.api; +import static edu.harvard.iq.dataverse.api.AbstractApiBean.error; import edu.harvard.iq.dataverse.api.dto.RoleDTO; import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.authorization.users.User; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -11,6 +13,9 @@ import static edu.harvard.iq.dataverse.util.json.JsonPrinter.*; import edu.harvard.iq.dataverse.engine.command.impl.CreateRoleCommand; import edu.harvard.iq.dataverse.engine.command.impl.DeleteRoleCommand; +import edu.harvard.iq.dataverse.util.BundleUtil; +import java.util.Arrays; +import java.util.List; import javax.ejb.Stateless; import javax.ws.rs.DELETE; import javax.ws.rs.QueryParam; @@ -26,7 +31,7 @@ public class Roles extends AbstractApiBean { @GET @Path("{id}") - public Response viewRole( @PathParam("id") Long id) { + public Response viewRole( @PathParam("id") String id) { return response( ()-> { final User user = findUserOrDie(); final DataverseRole role = findRoleOrDie(id); @@ -35,14 +40,19 @@ public Response viewRole( @PathParam("id") Long id) { }); } - @DELETE - @Path("{id}") - public Response deleteRole( @PathParam("id") Long id ) { - return response( req -> { - execCommand( new DeleteRoleCommand(req, findRoleOrDie(id)) ); - return ok("role " + id + " deleted."); + @DELETE + @Path("{id}") + public Response deleteRole(@PathParam("id") String id) { + return response(req -> { + DataverseRole role = findRoleOrDie(id); + List args = Arrays.asList(role.getName()); + if (role.getOwner() == null) { + throw new WrappedResponse(forbidden(BundleUtil.getStringFromBundle("find.dataverse.role.error.role.builtin.not.allowed", args))); + } + execCommand(new DeleteRoleCommand(req, role)); + return ok("role " + role.getName() + " deleted."); }); - } + } @POST public Response createNewRole( RoleDTO roleDto, @@ -52,11 +62,4 @@ public Response createNewRole( RoleDTO roleDto, req,findDataverseOrDie(dvoIdtf)))))); } - private DataverseRole findRoleOrDie( long id ) throws WrappedResponse { - DataverseRole role = rolesSvc.find(id); - if ( role != null ) { - return role; - } - throw new WrappedResponse(notFound( "role with id " + id + " not found")); - } } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/DataverseRole.java b/src/main/java/edu/harvard/iq/dataverse/authorization/DataverseRole.java index 8ca72e7e9bc..12ddf817221 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/DataverseRole.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/DataverseRole.java @@ -33,18 +33,20 @@ * @author michael */ @NamedQueries({ - @NamedQuery(name = "DataverseRole.findByOwnerId", - query= "SELECT r FROM DataverseRole r WHERE r.owner.id=:ownerId ORDER BY r.name"), - @NamedQuery(name = "DataverseRole.findBuiltinRoles", - query= "SELECT r FROM DataverseRole r WHERE r.owner is null ORDER BY r.name"), + @NamedQuery(name = "DataverseRole.findByOwnerId", + query = "SELECT r FROM DataverseRole r WHERE r.owner.id=:ownerId ORDER BY r.name"), + @NamedQuery(name = "DataverseRole.findBuiltinRoles", + query = "SELECT r FROM DataverseRole r WHERE r.owner is null ORDER BY r.name"), @NamedQuery(name = "DataverseRole.findBuiltinRoleByAlias", - query= "SELECT r FROM DataverseRole r WHERE r.alias=:alias AND r.owner is null"), - @NamedQuery(name = "DataverseRole.findCustomRoleByAliasAndOwner", - query= "SELECT r FROM DataverseRole r WHERE r.alias=:alias and (r.owner is null or r.owner.id=:ownerId)"), - @NamedQuery(name = "DataverseRole.listAll", - query= "SELECT r FROM DataverseRole r"), - @NamedQuery(name = "DataverseRole.deleteById", - query= "DELETE FROM DataverseRole r WHERE r.id=:id") + query = "SELECT r FROM DataverseRole r WHERE r.alias=:alias AND r.owner is null"), + @NamedQuery(name = "DataverseRole.findDataverseRoleByAlias", + query = "SELECT r FROM DataverseRole r WHERE r.alias=:alias"), + @NamedQuery(name = "DataverseRole.findCustomRoleByAliasAndOwner", + query = "SELECT r FROM DataverseRole r WHERE r.alias=:alias and (r.owner is null or r.owner.id=:ownerId)"), + @NamedQuery(name = "DataverseRole.listAll", + query = "SELECT r FROM DataverseRole r"), + @NamedQuery(name = "DataverseRole.deleteById", + query = "DELETE FROM DataverseRole r WHERE r.id=:id") }) @Entity @Table(indexes = {@Index(columnList="owner_id") diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 8352e66c92d..eddbb905d3c 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -1922,6 +1922,10 @@ find.dataverselinking.error.not.found.bad.ids=Bad dataverse ID number: {0} or da find.datafile.error.datafile.not.found.id=File with ID {0} not found. find.datafile.error.datafile.not.found.bad.id=Bad file ID number: {0}. find.datafile.error.dataset.not.found.persistentId=Datafile with Persistent ID {0} not found. +find.dataverse.role.error.role.not.found.id=Dataverse Role with ID {0} not found. +find.dataverse.role.error.role.not.found.bad.id=Bad Dataverse Role ID number: {0} +find.dataverse.role.error.role.not.found.alias=Dataverse Role with alias {0} not found. +find.dataverse.role.error.role.builtin.not.allowed=May not delete Built In Role {0}. file.addreplace.error.dataset_id_not_found=There was no dataset found for ID: file.addreplace.error.no_edit_dataset_permission=You do not have permission to edit this dataset. file.addreplace.error.filename_undetermined=The file name cannot be determined. From bf05205c1eaab2d517c9175e8499d6932e851eab Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 8 Mar 2021 16:35:11 -0500 Subject: [PATCH 03/17] #7633 Add integration tests --- scripts/api/data/role-test-addRole.json | 10 +++ .../iq/dataverse/api/AbstractApiBean.java | 13 ++-- .../edu/harvard/iq/dataverse/api/RolesIT.java | 69 +++++++++++++++++++ .../edu/harvard/iq/dataverse/api/UtilIT.java | 36 ++++++++++ 4 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 scripts/api/data/role-test-addRole.json create mode 100644 src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java diff --git a/scripts/api/data/role-test-addRole.json b/scripts/api/data/role-test-addRole.json new file mode 100644 index 00000000000..7923eed916b --- /dev/null +++ b/scripts/api/data/role-test-addRole.json @@ -0,0 +1,10 @@ +{ + "alias":"testRole", + "name":"Test Role", + "description":"Test Role for adding/deleting.", + "permissions":[ + "ViewUnpublishedDataset", + "ViewUnpublishedDataverse", + "DownloadFile" + ] +} diff --git a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java index b71625a36bd..7313dde5a35 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java @@ -494,14 +494,20 @@ protected DataverseRole findRoleOrDie(String id) throws WrappedResponse { role = em.createNamedQuery("DataverseRole.findDataverseRoleByAlias", DataverseRole.class) .setParameter("alias", alias) .getSingleResult(); - } else { + if (role == null) { + throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.alias", Collections.singletonList(alias)))); + } else { + return role; + } - role = rolesSvc.find(Long.parseLong(id)); + } else { try { role = rolesSvc.find(Long.parseLong(id)); if (role == null) { throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.id", Collections.singletonList(id)))); + } else { + return role; } } catch (NumberFormatException nfe) { @@ -510,9 +516,6 @@ protected DataverseRole findRoleOrDie(String id) throws WrappedResponse { } } - - throw new WrappedResponse(notFound("role with id " + id + " not found")); - } protected DatasetLinkingDataverse findDatasetLinkingDataverseOrDie(String datasetId, String linkingDataverseId) throws WrappedResponse { diff --git a/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java new file mode 100644 index 00000000000..85df1932a35 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java @@ -0,0 +1,69 @@ + +package edu.harvard.iq.dataverse.api; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.path.json.JsonPath; +import com.jayway.restassured.response.Response; +import edu.harvard.iq.dataverse.authorization.DataverseRole; +import edu.harvard.iq.dataverse.authorization.groups.impl.builtin.AuthenticatedUsers; +import java.util.logging.Logger; +import static javax.ws.rs.core.Response.Status.OK; +import static junit.framework.Assert.assertEquals; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + * @author skraffmi + */ +public class RolesIT { + + private static final Logger logger = Logger.getLogger(AdminIT.class.getCanonicalName()); + + @BeforeClass + public static void setUp() { + RestAssured.baseURI = UtilIT.getRestAssuredBaseUri(); + } + + @Test + public void testCreateDeleteRoles() { + + Response createUser = UtilIT.createRandomUser(); + createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + + Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); + createDataverseResponse.prettyPrint(); + String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + + String pathToJsonFile = "scripts/api/data/role-test-addRole.json"; + Response addBuiltinRoleResponse = UtilIT.addBuiltInRole(pathToJsonFile); + addBuiltinRoleResponse.prettyPrint(); + String body = addBuiltinRoleResponse.getBody().asString(); + String status = JsonPath.from(body).getString("status"); + assertEquals("OK", status); + + //Try to delete from non-admin api - should fail. + + Response deleteBuiltinRoleResponseError = UtilIT.deleteDataverseRole("testRole", apiToken); + deleteBuiltinRoleResponseError.prettyPrint(); + body = deleteBuiltinRoleResponseError.getBody().asString(); + status = JsonPath.from(body).getString("status"); + assertEquals("ERROR", status); + + + Response deleteBuiltinRoleResponseSucceed = UtilIT.deleteBuiltInRole("testRole"); + deleteBuiltinRoleResponseSucceed.prettyPrint(); + body = deleteBuiltinRoleResponseSucceed.getBody().asString(); + status = JsonPath.from(body).getString("status"); + assertEquals("OK", status); + +/* + Response deleteUserResponse = UtilIT.deleteUser(username); + deleteUserResponse.prettyPrint(); + assertEquals(200, deleteUserResponse.getStatusCode()); +*/ + } + +} 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 f3ff8f8fae4..90bad4b81cd 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -2495,6 +2495,42 @@ static Response addBannerMessage(String pathToJsonFile) { return addBannerMessageResponse; } + static Response addBuiltInRole(String pathToJsonFile) { + String jsonIn = getDatasetJson(pathToJsonFile); + + Response addBannerMessageResponse = given() + .body(jsonIn) + .contentType("application/json") + .post("/api/admin/roles"); + return addBannerMessageResponse; + } + + static Response deleteBuiltInRole(String roleAlias) { + + Response addBannerMessageResponse = given() + .delete("/api/admin/roles/:alias?alias=" +roleAlias); + return addBannerMessageResponse; + } + + static Response addDataverseRole(String pathToJsonFile, String dvAlias, String apiToken) { + String jsonIn = getDatasetJson(pathToJsonFile); + + Response addBannerMessageResponse = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .body(jsonIn) + .contentType("application/json") + .post("/api/roles"); + return addBannerMessageResponse; + } + + static Response deleteDataverseRole( String roleAlias, String apiToken) { + + Response addBannerMessageResponse = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .delete("/api/roles/:alias?alias="+roleAlias); + return addBannerMessageResponse; + } + static Response getBannerMessages() { Response getBannerMessagesResponse = given() From ec27d6e97027b92d588b3674adbdbb54a1b5fc0d Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 9 Mar 2021 11:52:55 -0500 Subject: [PATCH 04/17] #7633 add integration tests --- .../iq/dataverse/api/AbstractApiBean.java | 25 +++++++------ .../edu/harvard/iq/dataverse/api/RolesIT.java | 35 ++++++++++++++++--- .../edu/harvard/iq/dataverse/api/UtilIT.java | 26 +++++++++++++- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java index 7313dde5a35..3465cc55039 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java @@ -70,6 +70,7 @@ import javax.json.JsonValue; import javax.json.JsonValue.ValueType; import javax.persistence.EntityManager; +import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Context; @@ -484,20 +485,19 @@ protected DataFile findDataFileOrDie(String id) throws WrappedResponse { } } } - - - + protected DataverseRole findRoleOrDie(String id) throws WrappedResponse { DataverseRole role; if (id.equals(ALIAS_KEY)) { String alias = getRequestParameter(ALIAS_KEY.substring(1)); - role = em.createNamedQuery("DataverseRole.findDataverseRoleByAlias", DataverseRole.class) - .setParameter("alias", alias) - .getSingleResult(); - if (role == null) { - throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.alias", Collections.singletonList(alias)))); - } else { - return role; + try { + return em.createNamedQuery("DataverseRole.findDataverseRoleByAlias", DataverseRole.class) + .setParameter("alias", alias) + .getSingleResult(); + + //Should not be a multiple result exception due to table constraint + } catch (NoResultException nre) { + throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.dataverse.role.error.role.not.found.alias", Collections.singletonList(alias)))); } } else { @@ -505,17 +505,16 @@ protected DataverseRole findRoleOrDie(String id) throws WrappedResponse { try { role = rolesSvc.find(Long.parseLong(id)); if (role == null) { - throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.id", Collections.singletonList(id)))); + throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("find.dataverse.role.error.role.not.found.id", Collections.singletonList(id)))); } else { return role; } } catch (NumberFormatException nfe) { throw new WrappedResponse( - badRequest(BundleUtil.getStringFromBundle("find.datafile.error.datafile.not.found.bad.id", Collections.singletonList(id)))); + badRequest(BundleUtil.getStringFromBundle("find.dataverse.role.error.role.not.found.bad.id", Collections.singletonList(id)))); } } - } protected DatasetLinkingDataverse findDatasetLinkingDataverseOrDie(String datasetId, String linkingDataverseId) throws WrappedResponse { diff --git a/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java index 85df1932a35..d12641ce0c4 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java @@ -30,8 +30,10 @@ public void testCreateDeleteRoles() { Response createUser = UtilIT.createRandomUser(); createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); + UtilIT.makeSuperUser(username); Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); createDataverseResponse.prettyPrint(); @@ -52,6 +54,8 @@ public void testCreateDeleteRoles() { status = JsonPath.from(body).getString("status"); assertEquals("ERROR", status); + // deleteTitleViaNative.then().assertThat().body("message", equalTo("Error parsing dataset update: Empty value for field: Title ")); + Response deleteBuiltinRoleResponseSucceed = UtilIT.deleteBuiltInRole("testRole"); deleteBuiltinRoleResponseSucceed.prettyPrint(); @@ -59,11 +63,32 @@ public void testCreateDeleteRoles() { status = JsonPath.from(body).getString("status"); assertEquals("OK", status); -/* - Response deleteUserResponse = UtilIT.deleteUser(username); - deleteUserResponse.prettyPrint(); - assertEquals(200, deleteUserResponse.getStatusCode()); -*/ + //add as dataverse role + Response addDataverseRoleResponse = UtilIT.addDataverseRole(pathToJsonFile, dataverseAlias, apiToken); + addDataverseRoleResponse.prettyPrint(); + body = addBuiltinRoleResponse.getBody().asString(); + status = JsonPath.from(body).getString("status"); + assertEquals("OK", status); + + Response viewDataverseRoleResponse = UtilIT.viewDataverseRole("testRole", apiToken); + viewDataverseRoleResponse.prettyPrint(); + body = viewDataverseRoleResponse.getBody().asString(); + String idString = JsonPath.from(body).getString("data.id"); + + System.out.print("idString: " + idString); + + Response deleteDataverseRoleResponseBadAlias = UtilIT.deleteDataverseRole("badAlias", apiToken); + deleteDataverseRoleResponseBadAlias.prettyPrint(); + body = deleteDataverseRoleResponseBadAlias.getBody().asString(); + status = JsonPath.from(body).getString("status"); + assertEquals("ERROR", status); + + Response deleteDataverseRoleResponseSucceed = UtilIT.deleteDataverseRole("testRole", apiToken); + deleteDataverseRoleResponseSucceed.prettyPrint(); + body = deleteDataverseRoleResponseSucceed.getBody().asString(); + status = JsonPath.from(body).getString("status"); + assertEquals("OK", status); + } } 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 90bad4b81cd..c1887fafbe6 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -2519,7 +2519,7 @@ static Response addDataverseRole(String pathToJsonFile, String dvAlias, String a .header(API_TOKEN_HTTP_HEADER, apiToken) .body(jsonIn) .contentType("application/json") - .post("/api/roles"); + .post("/api/roles?dvo="+dvAlias); return addBannerMessageResponse; } @@ -2531,6 +2531,30 @@ static Response deleteDataverseRole( String roleAlias, String apiToken) { return addBannerMessageResponse; } + static Response deleteDataverseRoleById( String id, String apiToken) { + + Response addBannerMessageResponse = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .delete("/api/roles/"+id); + return addBannerMessageResponse; + } + + static Response viewDataverseRole( String roleAlias, String apiToken) { + + Response addBannerMessageResponse = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/roles/:alias?alias="+roleAlias); + return addBannerMessageResponse; + } + + static Response viewDataverseRoleById( String id, String apiToken) { + + Response addBannerMessageResponse = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/roles/"+id); + return addBannerMessageResponse; + } + static Response getBannerMessages() { Response getBannerMessagesResponse = given() From 8c5a52b82144216920be7feb436b686fc3e7bc30 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 9 Mar 2021 15:10:41 -0500 Subject: [PATCH 05/17] #7633 add test for delete by id --- .../edu/harvard/iq/dataverse/api/RolesIT.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java index d12641ce0c4..d1e2ffb2426 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/RolesIT.java @@ -4,11 +4,9 @@ import com.jayway.restassured.RestAssured; import com.jayway.restassured.path.json.JsonPath; import com.jayway.restassured.response.Response; -import edu.harvard.iq.dataverse.authorization.DataverseRole; -import edu.harvard.iq.dataverse.authorization.groups.impl.builtin.AuthenticatedUsers; import java.util.logging.Logger; -import static javax.ws.rs.core.Response.Status.OK; import static junit.framework.Assert.assertEquals; +import static org.hamcrest.CoreMatchers.equalTo; import org.junit.BeforeClass; import org.junit.Test; @@ -54,7 +52,7 @@ public void testCreateDeleteRoles() { status = JsonPath.from(body).getString("status"); assertEquals("ERROR", status); - // deleteTitleViaNative.then().assertThat().body("message", equalTo("Error parsing dataset update: Empty value for field: Title ")); + deleteBuiltinRoleResponseError.then().assertThat().body("message", equalTo("May not delete Built In Role Test Role.")); Response deleteBuiltinRoleResponseSucceed = UtilIT.deleteBuiltInRole("testRole"); @@ -81,9 +79,18 @@ public void testCreateDeleteRoles() { deleteDataverseRoleResponseBadAlias.prettyPrint(); body = deleteDataverseRoleResponseBadAlias.getBody().asString(); status = JsonPath.from(body).getString("status"); + assertEquals("ERROR", status); + deleteDataverseRoleResponseBadAlias.then().assertThat().body("message", equalTo("Dataverse Role with alias badAlias not found.")); + + Long idBad = Long.parseLong(idString) + 10; + Response deleteDataverseRoleResponseBadId = UtilIT.deleteDataverseRoleById(idBad.toString(), apiToken); + deleteDataverseRoleResponseBadId.prettyPrint(); + body = deleteDataverseRoleResponseBadId.getBody().asString(); + status = JsonPath.from(body).getString("status"); assertEquals("ERROR", status); + deleteDataverseRoleResponseBadId.then().assertThat().body("message", equalTo("Dataverse Role with ID " + idBad.toString() + " not found.")); - Response deleteDataverseRoleResponseSucceed = UtilIT.deleteDataverseRole("testRole", apiToken); + Response deleteDataverseRoleResponseSucceed = UtilIT.deleteDataverseRoleById(idString, apiToken); deleteDataverseRoleResponseSucceed.prettyPrint(); body = deleteDataverseRoleResponseSucceed.getBody().asString(); status = JsonPath.from(body).getString("status"); From 17a1b01d3a9351e7b3535004b461ccbbe44ecb2b Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 10 Mar 2021 10:17:35 -0500 Subject: [PATCH 06/17] #7633 update doc --- doc/sphinx-guides/source/api/native-api.rst | 32 +++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index d50ef05d87e..d879c2a82fc 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -259,6 +259,8 @@ Where ``roles.json`` looks like this:: ] } +.. note:: Only a Dataverse installation account with superuser permissions is allowed to create roles in a Dataverse Collection. + .. _list-role-assignments-on-a-dataverse-api: List Role Assignments in a Dataverse Collection @@ -2418,9 +2420,35 @@ Roles Create a New Role in a Dataverse Collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Creates a new role in Dataverse collection object whose Id is ``dataverseIdtf`` (that's an id/alias):: +Creates a new role under Dataverse collection ``id``. Needs a json file with the role description: + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ID=root + + curl -H X-Dataverse-key:$API_TOKEN -X POST $SERVER_URL/api/dataverses/$ID/roles --upload-file roles.json + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST https://demo.dataverse.org/api/dataverses/root/roles --upload-file roles.json + +Where ``roles.json`` looks like this:: + + { + "alias": "sys1", + "name": “Restricted System Role”, + "description": “A person who may only add datasets.”, + "permissions": [ + "AddDataset" + ] + } + +.. note:: Only a Dataverse installation account with superuser permissions is allowed to create roles in a Dataverse Collection. - POST http://$SERVER/api/roles?dvo=$dataverseIdtf&key=$apiKey Show Role ~~~~~~~~~ From 4e4f429eacb35abaa599eb63f03571facc62c926 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 10 Mar 2021 10:53:24 -0500 Subject: [PATCH 07/17] #7633 add delete role doc --- doc/sphinx-guides/source/api/native-api.rst | 33 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index d879c2a82fc..6101ce7d312 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2460,9 +2460,38 @@ Shows the role with ``id``:: Delete Role ~~~~~~~~~~~ -Deletes the role with ``id``:: +A curl example using an ``ID`` + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ID=24 + + curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE $SERVER_URL/api/roles/$ID + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE https://demo.dataverse.org/api/roles/24 + +A curl example using a Role alias ``ALIAS`` + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ALIAS=roleAlias + + curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE "$SERVER_URL/api/files/:alias?alias=$ALIAS" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "https://demo.dataverse.org/api/ROLES/:alias?alias=roleAlias" - DELETE http://$SERVER/api/roles/$id Explicit Groups --------------- From 376586bb855a9f1e73eaf35224e5ec5704ba6e69 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 10 Mar 2021 10:57:42 -0500 Subject: [PATCH 08/17] 7633 fix doc typo --- doc/sphinx-guides/source/api/native-api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 6101ce7d312..56cd8d2cad6 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2484,13 +2484,13 @@ A curl example using a Role alias ``ALIAS`` export SERVER_URL=https://demo.dataverse.org export ALIAS=roleAlias - curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE "$SERVER_URL/api/files/:alias?alias=$ALIAS" + curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE "$SERVER_URL/api/roles/:alias?alias=$ALIAS" The fully expanded example above (without environment variables) looks like this: .. code-block:: bash - curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "https://demo.dataverse.org/api/ROLES/:alias?alias=roleAlias" + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE https://demo.dataverse.org/api/roles/:alias?alias=roleAlias Explicit Groups From 807bd80b3d4cdc7a06c488f5f10424e44ecb5b90 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 10 Mar 2021 11:00:57 -0500 Subject: [PATCH 09/17] #7633 add doc for deleting built in "Global" role --- doc/sphinx-guides/source/api/native-api.rst | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 56cd8d2cad6..7bab69bdd53 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2931,6 +2931,41 @@ Create Global Role Creates a global role in the Dataverse installation. The data POSTed are assumed to be a role JSON. :: POST http://$SERVER/api/admin/roles + +Delete Global Role +~~~~~~~~~~~~~~~~~~ + +A curl example using an ``ID`` + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ID=24 + + curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE $SERVER_URL/api/admin/roles/$ID + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE https://demo.dataverse.org/api/admin/roles/24 + +A curl example using a Role alias ``ALIAS`` + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ALIAS=roleAlias + + curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE "$SERVER_URL/api/admin/roles/:alias?alias=$ALIAS" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE https://demo.dataverse.org/api/admin/roles/:alias?alias=roleAlias List Users ~~~~~~~~~~ From 9d872d083b225b792c0ecba9fc9b4d0aeb3d7880 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 16 Mar 2021 16:36:07 -0400 Subject: [PATCH 10/17] #7633 fix duplicate alias error message --- .../iq/dataverse/ManagePermissionsPage.java | 2 +- .../command/impl/CreateRoleCommand.java | 17 +++++++- src/main/java/propertyFiles/Bundle.properties | 2 + .../command/impl/CreateRoleCommandTest.java | 41 +++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/ManagePermissionsPage.java b/src/main/java/edu/harvard/iq/dataverse/ManagePermissionsPage.java index d73aaeb8dbd..79a3ca800e2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/ManagePermissionsPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/ManagePermissionsPage.java @@ -590,7 +590,7 @@ public void updateRole(ActionEvent e) { } catch (PermissionException ex) { JH.addMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("permission.roleNotSaved"), BundleUtil.getStringFromBundle("permission.permissionsMissing", Arrays.asList(ex.getRequiredPermissions().toString()))); } catch (CommandException ex) { - JH.addMessage(FacesMessage.SEVERITY_FATAL, BundleUtil.getStringFromBundle("permission.roleNotSaved")); + JH.addMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("permission.roleNotSaved").concat(" " + ex.getMessage()) ); logger.log(Level.SEVERE, "Error saving role: " + ex.getMessage(), ex); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommand.java index ff28021146d..cb9b0a3c774 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommand.java @@ -1,6 +1,7 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.api.AbstractApiBean; import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; @@ -11,6 +12,8 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; +import edu.harvard.iq.dataverse.util.BundleUtil; +import javax.persistence.NoResultException; /** * Create a new role in a dataverse. @@ -34,9 +37,19 @@ public DataverseRole execute(CommandContext ctxt) throws CommandException { User user = getUser(); //todo: temporary for 4.0 - only superusers can create and edit roles if ((!(user instanceof AuthenticatedUser) || !user.isSuperuser())) { - throw new IllegalCommandException("Roles can only be created or edited by superusers.",this); + throw new IllegalCommandException(BundleUtil.getStringFromBundle("permission.role.must.be.created.by.superuser"),this); + } + //Test to see if the role already exists in DB + try { + DataverseRole testRole = ctxt.em().createNamedQuery("DataverseRole.findDataverseRoleByAlias", DataverseRole.class) + .setParameter("alias", created.getAlias()) + .getSingleResult(); + if (!(testRole == null)) { + throw new IllegalCommandException(BundleUtil.getStringFromBundle("permission.role.not.created.alias.already.exists"), this); + } + } catch (NoResultException nre) { + // we want no results because that meand we can create a role } - dv.addRole(created); return ctxt.roles().save(created); } diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 0c50276ea0d..40b15230f42 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2239,6 +2239,8 @@ permission.permissionsMissing=Permissions {0} missing. permission.CannotAssigntDefaultPermissions=Cannot assign default permissions. permission.default.contributor.role.none.decription=A person who has no permissions on a newly created dataset. Not recommended for dataverses with human contributors. permission.default.contributor.role.none.name=None +permission.role.must.be.created.by.superuser=Roles can only be created or edited by superusers. +permission.role.not.created.alias.already.exists=Role with this alias already exists. #ManageFilePermissionsPage.java permission.roleNotAbleToBeRemoved=The role assignment was not able to be removed. diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommandTest.java index ea39bb1bc77..243285e69ab 100644 --- a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommandTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateRoleCommandTest.java @@ -9,13 +9,19 @@ import edu.harvard.iq.dataverse.authorization.users.GuestUser; import edu.harvard.iq.dataverse.engine.TestCommandContext; import edu.harvard.iq.dataverse.engine.TestDataverseEngine; +import edu.harvard.iq.dataverse.engine.TestEntityManager; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; import edu.harvard.iq.dataverse.mocks.MocksFactory; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import org.mockito.Matchers; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * @@ -36,6 +42,12 @@ public DataverseRole save(DataverseRole aRole) { } }; } + + @Override + public EntityManager em() { + return new LocalTestEntityManager(); + + } }); @Before @@ -94,4 +106,33 @@ public void testGuestUsersCantAddRoles() throws CommandException { engine.submit(sut); } + private class LocalTestEntityManager extends TestEntityManager { + + @Override + public T merge(T entity) { + return entity; + } + + @Override + public void persist(Object entity) { + // + } + + @Override + public void flush() { + //nothing to do here + } + + @Override + public TypedQuery createNamedQuery(String name, Class resultClass) { + //Mocking a query to return no results when + //checking for existing role in DB + TypedQuery mockedQuery = mock(TypedQuery.class); + when(mockedQuery.setParameter(Matchers.anyString(), Matchers.anyObject())).thenReturn(mockedQuery); + when(mockedQuery.getSingleResult()).thenReturn(null); + return mockedQuery; + } + + } + } From e753683babb231a252a3355a5b29bc45873ff5a8 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 17 Mar 2021 09:24:20 -0400 Subject: [PATCH 11/17] #7633 add content type to add roles doc --- doc/sphinx-guides/source/api/native-api.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 910e1b1b63a..32f752ceaec 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -246,7 +246,7 @@ The fully expanded example above (without environment variables) looks like this .. code-block:: bash - curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST https://demo.dataverse.org/api/dataverses/root/roles --upload-file roles.json + curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST -H "Content-type:application/json" https://demo.dataverse.org/api/dataverses/root/roles --upload-file roles.json Where ``roles.json`` looks like this:: @@ -2428,13 +2428,13 @@ Creates a new role under Dataverse collection ``id``. Needs a json file with the export SERVER_URL=https://demo.dataverse.org export ID=root - curl -H X-Dataverse-key:$API_TOKEN -X POST $SERVER_URL/api/dataverses/$ID/roles --upload-file roles.json + curl -H X-Dataverse-key:$API_TOKEN -X POST -H "Content-type:application/json" $SERVER_URL/api/dataverses/$ID/roles --upload-file roles.json The fully expanded example above (without environment variables) looks like this: .. code-block:: bash - curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST https://demo.dataverse.org/api/dataverses/root/roles --upload-file roles.json + curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST -H "Content-type:application/json" https://demo.dataverse.org/api/dataverses/root/roles --upload-file roles.json Where ``roles.json`` looks like this:: From 7625fc2af7bb24a4dc283c9b617a672b2e52e0e8 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 18 Mar 2021 13:57:27 -0400 Subject: [PATCH 12/17] #7634 order dvobjects by display name --- .../engine/command/impl/ListDataverseContentCommand.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java index 26e1e988fac..3c606d35881 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java @@ -7,7 +7,9 @@ import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -32,11 +34,14 @@ public ListDataverseContentCommand(DataverseRequest aRequest, Dataverse anAffect @Override public List execute(CommandContext ctxt) throws CommandException { + List availableObjects = new ArrayList(); if (getRequest().getUser().isSuperuser()) { - return ctxt.dvObjects().findByOwnerId(dvToList.getId()); + availableObjects = ctxt.dvObjects().findByOwnerId(dvToList.getId()); } else { - return ctxt.permissions().whichChildrenHasPermissionsForOrReleased(getRequest(), dvToList, EnumSet.of(Permission.ViewUnpublishedDataverse, Permission.ViewUnpublishedDataset)); + availableObjects = ctxt.permissions().whichChildrenHasPermissionsForOrReleased(getRequest(), dvToList, EnumSet.of(Permission.ViewUnpublishedDataverse, Permission.ViewUnpublishedDataset)); } + availableObjects.sort(Comparator.comparing(DvObject::getDisplayName)); + return availableObjects; } @Override From a306707d7c0ea878b20683ebbb533d60f99f6fda Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Fri, 19 Mar 2021 16:59:37 -0400 Subject: [PATCH 13/17] #7633 give feedback on required fields --- src/main/java/propertyFiles/Bundle.properties | 2 ++ src/main/webapp/roles-edit.xhtml | 22 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 40b15230f42..c085f18edc6 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -967,6 +967,8 @@ dataverse.permissions.roles.add=Add New Role dataverse.permissions.roles.description=All the roles set up in your dataverse, that you can assign to users and groups. dataverse.permissions.roles.edit=Edit Role dataverse.permissions.roles.copy=Copy Role +dataverse.permissions.roles.alias.required=Please enter a unique identifier for this role. +dataverse.permissions.roles.name.required=Please enter a name for this role. # permissions-manage-files.xhtml dataverse.permissionsFiles.title=Restricted File Permissions diff --git a/src/main/webapp/roles-edit.xhtml b/src/main/webapp/roles-edit.xhtml index a59d53bcdae..4748f24df5d 100644 --- a/src/main/webapp/roles-edit.xhtml +++ b/src/main/webapp/roles-edit.xhtml @@ -8,14 +8,18 @@
+
- +
@@ -24,12 +28,17 @@ #{bundle['dataverse.permissions.roles.id']} + + - + +
+
@@ -65,9 +74,12 @@
+ oncomplete="if (args && !args.validationFailed) addRoleCommand();" + update="roleInputTextFragment @([id$=Messages])" + > + + + From 8bb9dec0fc05cc516eda3858eb497292a5a9da25 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 23 Mar 2021 09:15:08 -0400 Subject: [PATCH 14/17] #7634 order by id within type --- src/main/java/edu/harvard/iq/dataverse/DvObject.java | 2 +- .../engine/command/impl/ListDataverseContentCommand.java | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DvObject.java b/src/main/java/edu/harvard/iq/dataverse/DvObject.java index f1041303fdd..09a2ef85893 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DvObject.java +++ b/src/main/java/edu/harvard/iq/dataverse/DvObject.java @@ -33,7 +33,7 @@ @NamedQuery(name = "DvObject.findByProtocolIdentifierAuthority", query = "SELECT o FROM DvObject o WHERE o.identifier=:identifier and o.authority=:authority and o.protocol=:protocol"), @NamedQuery(name = "DvObject.findByOwnerId", - query = "SELECT o FROM DvObject o WHERE o.owner.id=:ownerId"), + query = "SELECT o FROM DvObject o WHERE o.owner.id=:ownerId order by o.dtype desc, o.id"), @NamedQuery(name = "DvObject.findByAuthenticatedUserId", query = "SELECT o FROM DvObject o WHERE o.creator.id=:ownerId or o.releaseUser.id=:releaseUserId") }) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java index 3c606d35881..2e0f969bf0a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java @@ -7,9 +7,7 @@ import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; -import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -34,14 +32,11 @@ public ListDataverseContentCommand(DataverseRequest aRequest, Dataverse anAffect @Override public List execute(CommandContext ctxt) throws CommandException { - List availableObjects = new ArrayList(); if (getRequest().getUser().isSuperuser()) { - availableObjects = ctxt.dvObjects().findByOwnerId(dvToList.getId()); + return ctxt.dvObjects().findByOwnerId(dvToList.getId()); } else { - availableObjects = ctxt.permissions().whichChildrenHasPermissionsForOrReleased(getRequest(), dvToList, EnumSet.of(Permission.ViewUnpublishedDataverse, Permission.ViewUnpublishedDataset)); + return ctxt.permissions().whichChildrenHasPermissionsForOrReleased(getRequest(), dvToList, EnumSet.of(Permission.ViewUnpublishedDataverse, Permission.ViewUnpublishedDataset)); } - availableObjects.sort(Comparator.comparing(DvObject::getDisplayName)); - return availableObjects; } @Override From 5dc0f0dac512db5caecab16328ee8adacbc6b6e1 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 23 Mar 2021 09:30:09 -0400 Subject: [PATCH 15/17] #7634 update doc to reflect collection ordering. --- doc/sphinx-guides/source/api/native-api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 94cb6c720c6..54339d5749b 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -130,7 +130,7 @@ The fully expanded example above (without environment variables) looks like this Show Contents of a Dataverse Collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -|CORS| Lists all the Dataverse collections and datasets directly under a Dataverse collection (direct children only, not recursive) specified by database id or alias. If you pass your API token and have access, unpublished Dataverse collections and datasets will be included in the response. +|CORS| Lists all the Dataverse collections and datasets directly under a Dataverse collection (direct children only, not recursive) specified by database id or alias. If you pass your API token and have access, unpublished Dataverse collections and datasets will be included in the response. The list will be ordered by database id within type of object. That is, all Dataverse collections will be listed first and ordered by database id, then all datasets will be listed ordered by database id. .. note:: See :ref:`curl-examples-and-environment-variables` if you are unfamiliar with the use of ``export`` below. From 82e884ef8fbd13dbf4caf6de2f2cca80d26be33b Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 23 Mar 2021 10:38:15 -0400 Subject: [PATCH 16/17] #7634 fix typo --- .../engine/command/impl/ListDataverseContentCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java index 2e0f969bf0a..26e1e988fac 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListDataverseContentCommand.java @@ -33,7 +33,7 @@ public ListDataverseContentCommand(DataverseRequest aRequest, Dataverse anAffect @Override public List execute(CommandContext ctxt) throws CommandException { if (getRequest().getUser().isSuperuser()) { - return ctxt.dvObjects().findByOwnerId(dvToList.getId()); + return ctxt.dvObjects().findByOwnerId(dvToList.getId()); } else { return ctxt.permissions().whichChildrenHasPermissionsForOrReleased(getRequest(), dvToList, EnumSet.of(Permission.ViewUnpublishedDataverse, Permission.ViewUnpublishedDataset)); } From f28fcba5a15096b6a03d7119c33e7cf039c9f479 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 23 Mar 2021 14:15:42 -0400 Subject: [PATCH 17/17] #7633 reformat required messaging --- src/main/webapp/roles-edit.xhtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/webapp/roles-edit.xhtml b/src/main/webapp/roles-edit.xhtml index 4748f24df5d..e236ef180b3 100644 --- a/src/main/webapp/roles-edit.xhtml +++ b/src/main/webapp/roles-edit.xhtml @@ -12,31 +12,31 @@
- + /> +
- - + +