Merge branch 'main' into CST-5303-LiveImport-3PR

This commit is contained in:
Mykhaylo
2022-05-25 16:24:57 +02:00
11 changed files with 738 additions and 4 deletions

View File

@@ -41,6 +41,10 @@ jobs:
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
@@ -70,6 +74,7 @@ jobs:
with:
context: .
file: ./Dockerfile.dependencies
platforms: linux/amd64,linux/arm64
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
@@ -95,6 +100,7 @@ jobs:
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
@@ -123,6 +129,7 @@ jobs:
with:
context: .
file: ./Dockerfile.test
platforms: linux/amd64,linux/arm64
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
@@ -148,9 +155,10 @@ jobs:
with:
context: .
file: ./Dockerfile.cli
platforms: linux/amd64,linux/arm64
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build_cli.outputs.tags }}
labels: ${{ steps.meta_build_cli.outputs.labels }}
labels: ${{ steps.meta_build_cli.outputs.labels }}

View File

@@ -119,3 +119,4 @@ org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException.message = Refused
workflow group {1}. Delete the tasks and group first if you want to remove this user.
org.dspace.app.rest.exception.EPersonNameNotProvidedException.message = The eperson.firstname and eperson.lastname values need to be filled in
org.dspace.app.rest.exception.GroupNameNotProvidedException.message = Cannot create group, no group name is provided
org.dspace.app.rest.exception.GroupHasPendingWorkflowTasksException.message = Cannot delete group, the associated workflow role still has pending tasks

View File

@@ -0,0 +1,82 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.ContextUtil.obtainContext;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT;
import static org.dspace.core.Constants.EPERSON;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* This controller will handle all the incoming calls on the/api/authz/resourcepolicies/{id}/eperson endpoint
* where the id corresponds to the ResourcePolicy of which you want to replace the related EPerson.
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
*/
@RestController
@RequestMapping("/api/authz/resourcepolicies" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT + "/eperson")
public class ResourcePolicyEPersonReplaceRestController {
@Autowired
private Utils utils;
@Autowired
private ResourcePolicyService resourcePolicyService;
@PreAuthorize("hasPermission(#id, 'resourcepolicy', 'ADMIN')")
@RequestMapping(method = PUT, consumes = {"text/uri-list"})
public ResponseEntity<RepresentationModel<?>> replaceEPersonOfResourcePolicy(@PathVariable Integer id,
HttpServletResponse response, HttpServletRequest request) throws SQLException, AuthorizeException {
Context context = obtainContext(request);
List<DSpaceObject> dsoList = utils.constructDSpaceObjectList(context, utils.getStringListFromRequest(request));
if (dsoList.size() != 1 || dsoList.get(0).getType() != EPERSON) {
throw new UnprocessableEntityException(
"The EPerson doesn't exist or the data cannot be resolved to an EPerson.");
}
ResourcePolicy resourcePolicy = resourcePolicyService.find(context, id);
if (Objects.isNull(resourcePolicy)) {
throw new ResourceNotFoundException("ResourcePolicy with id: " + id + " not found");
}
if (Objects.isNull(resourcePolicy.getEPerson())) {
throw new UnprocessableEntityException("ResourcePolicy with id:" + id + " doesn't linked to an EPerson");
}
EPerson newEPerson = (EPerson) dsoList.get(0);
resourcePolicy.setEPerson(newEPerson);
context.commit();
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
}
}

View File

@@ -0,0 +1,82 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.ContextUtil.obtainContext;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT;
import static org.dspace.core.Constants.GROUP;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.eperson.Group;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* This controller will handle all the incoming calls on the/api/authz/resourcepolicies/{id}/group endpoint
* where the id corresponds to the ResourcePolicy of which you want to replace the related Group.
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
*/
@RestController
@RequestMapping("/api/authz/resourcepolicies" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT + "/group")
public class ResourcePolicyGroupReplaceRestController {
@Autowired
private Utils utils;
@Autowired
private ResourcePolicyService resourcePolicyService;
@PreAuthorize("hasPermission(#id, 'resourcepolicy', 'ADMIN')")
@RequestMapping(method = PUT, consumes = {"text/uri-list"})
public ResponseEntity<RepresentationModel<?>> replaceGroupOfResourcePolicy(@PathVariable Integer id,
HttpServletResponse response, HttpServletRequest request) throws SQLException, AuthorizeException {
Context context = obtainContext(request);
List<DSpaceObject> dsoList = utils.constructDSpaceObjectList(context, utils.getStringListFromRequest(request));
if (dsoList.size() != 1 || dsoList.get(0).getType() != GROUP) {
throw new UnprocessableEntityException("The Group doesn't exist or the data cannot be resolved to a Group");
}
ResourcePolicy resourcePolicy = resourcePolicyService.find(context, id);
if (Objects.isNull(resourcePolicy)) {
throw new ResourceNotFoundException("ResourcePolicy with id: " + id + " not found!");
}
if (Objects.isNull(resourcePolicy.getGroup())) {
throw new UnprocessableEntityException("ResourcePolicy with id:" + id + " doesn't linked to Group");
}
Group newGroup = (Group) dsoList.get(0);
resourcePolicy.setGroup(newGroup);
context.commit();
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
}
}

View File

@@ -148,6 +148,7 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
RESTEmptyWorkflowGroupException.class,
EPersonNameNotProvidedException.class,
GroupNameNotProvidedException.class,
GroupHasPendingWorkflowTasksException.class,
})
protected void handleCustomUnprocessableEntityException(HttpServletRequest request, HttpServletResponse response,
TranslatableException ex) throws IOException {

View File

@@ -0,0 +1,36 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.exception;
import org.dspace.core.I18nUtil;
/**
* <p>Extend {@link UnprocessableEntityException} to provide a specific error message
* in the REST response. The error message is added to the response in
* {@link DSpaceApiExceptionControllerAdvice#handleCustomUnprocessableEntityException},
* hence it should not contain sensitive or security-compromising info.</p>
*
*/
public class GroupHasPendingWorkflowTasksException
extends UnprocessableEntityException implements TranslatableException {
public static final String MESSAGE_KEY =
"org.dspace.app.rest.exception.GroupHasPendingWorkflowTasksException.message";
public GroupHasPendingWorkflowTasksException() {
super(I18nUtil.getMessage(MESSAGE_KEY));
}
public GroupHasPendingWorkflowTasksException(Throwable cause) {
super(I18nUtil.getMessage(MESSAGE_KEY), cause);
}
public String getMessageKey() {
return MESSAGE_KEY;
}
}

View File

@@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.GroupHasPendingWorkflowTasksException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
@@ -695,8 +696,8 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository<Collect
throws SQLException, WorkflowConfigurationException, AuthorizeException, WorkflowException, IOException {
Group group = workflowService.getWorkflowRoleGroup(context, collection, workflowRole, null);
if (!poolTaskService.findByGroup(context, group).isEmpty()) {
throw new UnprocessableEntityException("The Group that was attempted to be deleted " +
"still has Pooltasks open");
// todo: also handle claimed tasks that would become associated with this group once returned to the pool
throw new GroupHasPendingWorkflowTasksException();
}
if (group == null) {
throw new ResourceNotFoundException("The requested Group was not found");

View File

@@ -70,6 +70,9 @@ server.servlet.encoding.force=true
# However, you may wish to set this to "always" in your 'local.cfg' for development or debugging purposes.
server.error.include-stacktrace = never
# When to include the error message in error responses (introduced in Spring 2.3.x)
server.error.include-message = always
# Spring Boot proxy configuration (can be overridden in local.cfg).
# By default, Spring Boot does not automatically use X-Forwarded-* Headers when generating links (and similar) in the
# DSpace REST API. Three options are currently supported by Spring Boot:

View File

@@ -28,6 +28,7 @@ import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.WorkspaceItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Constants;
@@ -2414,4 +2415,27 @@ public class CollectionGroupRestControllerIT extends AbstractControllerIntegrati
.andExpect(status().isNotFound());
}
@Test
public void deleteCollectionWorkflowGroupWithPooledTaskTest() throws Exception {
context.turnOffAuthorisationSystem();
Group reviewer = workflowService.createWorkflowRoleGroup(context, collection, "reviewer");
// Submit an Item into the workflow -> moves to the "reviewer" step's pool.
// The role must have at least one EPerson, otherwise the WSI gets archived immediately
groupService.addMember(context, reviewer, eperson);
workflowService.start(
context,
WorkspaceItemBuilder.createWorkspaceItem(context, collection)
.withTitle("Dummy Item")
.build()
);
context.restoreAuthSystemState();
String token = getAuthToken(admin.getEmail(), password);
getClient(token).perform(delete("/api/core/collections/" + collection.getID() + "/workflowGroups/reviewer"))
.andExpect(status().isUnprocessableEntity());
}
}

View File

@@ -11,10 +11,13 @@ import static com.jayway.jsonpath.JsonPath.read;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST_VALUE;
import static org.springframework.http.MediaType.parseMediaType;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -29,6 +32,7 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.ws.rs.core.MediaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.matcher.ResourcePolicyMatcher;
import org.dspace.app.rest.model.ResourcePolicyRest;
import org.dspace.app.rest.model.patch.AddOperation;
@@ -2723,4 +2727,495 @@ public class ResourcePolicyRestRepositoryIT extends AbstractControllerIntegratio
.andExpect(jsonPath("$._links.resource.href", Matchers.allOf(
Matchers.containsString("/api/authz/resourcepolicies/search/resource"))));
}
}
@Test
public void patchReplaceEPersonAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson newEPerson = EPersonBuilder.createEPerson(context)
.withEmail("newEPerson@mail.com")
.withPassword(password)
.build();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context)
.withAction(Constants.ADD)
.withDspaceObject(col)
.withUser(eperson)
.withDescription("My Description")
.withPolicyType(ResourcePolicy.TYPE_CUSTOM)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
// verify origin resourcepolicy
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.eperson.id", is(eperson.getID().toString())))
.andExpect(jsonPath("$._embedded.group", nullValue()));
// update eperson of the resourcePolicy
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + resourcePolicy.getID() + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/epersons/" + newEPerson.getID()))
.andExpect(status().isNoContent());
// verify that the resourcePolicy is related to new eperson
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.eperson.id", is(newEPerson.getID().toString())))
.andExpect(jsonPath("$._embedded.group", nullValue()));
}
@Test
public void patchReplaceEPersonForbiddenTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson newEPerson = EPersonBuilder.createEPerson(context)
.withEmail("newEPerson@mail.com")
.withPassword(password)
.build();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context)
.withAction(Constants.ADD)
.withDspaceObject(col)
.withUser(eperson)
.withDescription("My Description")
.withPolicyType(ResourcePolicy.TYPE_CUSTOM)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
// verify origin resourcepolicy
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.eperson.id", is(eperson.getID().toString())))
.andExpect(jsonPath("$._embedded.group", nullValue()));
// try to update eperson of resourcepolicy with normal user
getClient(tokenEPerson).perform(put("/api/authz/resourcepolicies/" + resourcePolicy.getID() + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/epersons/" + newEPerson.getID()))
.andExpect(status().isForbidden());
// verify that resourcepolicy hasn't been changed
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.eperson.id", is(eperson.getID().toString())))
.andExpect(jsonPath("$._embedded.group", nullValue()));
}
@Test
public void patchReplaceEPersonUnauthorizedTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson newEPerson = EPersonBuilder.createEPerson(context)
.withEmail("newEPerson@mail.com")
.withPassword(password)
.build();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context)
.withAction(Constants.ADD)
.withDspaceObject(col)
.withUser(eperson)
.withDescription("My Description")
.withPolicyType(ResourcePolicy.TYPE_CUSTOM)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
// verify origin resourcepolicy
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.eperson.id", is(eperson.getID().toString())))
.andExpect(jsonPath("$._embedded.group", nullValue()));
// try to update eperson of resourcepolicy with anonymous user
getClient().perform(put("/api/authz/resourcepolicies/" + resourcePolicy.getID() + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/epersons/" + newEPerson.getID()))
.andExpect(status().isUnauthorized());
// verify that resourcepolicy hasn't been changed
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.eperson.id", is(eperson.getID().toString())))
.andExpect(jsonPath("$._embedded.group", nullValue()));
}
@Test
public void patchReplaceGroupAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
Group originGroup = GroupBuilder.createGroup(context)
.withName("origin Test Group")
.build();
Group newGroup = GroupBuilder.createGroup(context)
.withName("testGroupName")
.build();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context)
.withAction(Constants.ADD)
.withDspaceObject(col)
.withGroup(originGroup)
.withDescription("My Description")
.withPolicyType(ResourcePolicy.TYPE_CUSTOM)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
// verify origin resourcepolicy
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.group.id", is(originGroup.getID().toString())))
.andExpect(jsonPath("$._embedded.eperson", nullValue()));
// update group of the resourcePolicy
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + resourcePolicy.getID() + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/groups/" + newGroup.getID()))
.andExpect(status().isNoContent());
// verify that the resourcePolicy is related to new group
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.group.id", is(newGroup.getID().toString())))
.andExpect(jsonPath("$._embedded.eperson", nullValue()));
}
@Test
public void patchReplaceGroupForbiddenTest() throws Exception {
context.turnOffAuthorisationSystem();
Group originGroup = GroupBuilder.createGroup(context)
.withName("origin Test Group")
.build();
Group newGroup = GroupBuilder.createGroup(context)
.withName("testGroupName")
.build();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context)
.withAction(Constants.ADD)
.withDspaceObject(col)
.withGroup(originGroup)
.withDescription("My Description")
.withPolicyType(ResourcePolicy.TYPE_CUSTOM)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
// verify origin resourcepolicy
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.group.id", is(originGroup.getID().toString())))
.andExpect(jsonPath("$._embedded.eperson", nullValue()));
// try to update group of resourcepolicy with normal user
getClient(tokenEPerson).perform(put("/api/authz/resourcepolicies/" + resourcePolicy.getID() + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/groups/" + newGroup.getID()))
.andExpect(status().isForbidden());
// verify that resourcepolicy hasn't been changed
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.group.id", is(originGroup.getID().toString())))
.andExpect(jsonPath("$._embedded.eperson", nullValue()));
}
@Test
public void patchReplaceGroupUnauthorizedTest() throws Exception {
context.turnOffAuthorisationSystem();
Group originGroup = GroupBuilder.createGroup(context)
.withName("origin Test Group")
.build();
Group newGroup = GroupBuilder.createGroup(context)
.withName("testGroupName")
.build();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context)
.withAction(Constants.ADD)
.withDspaceObject(col)
.withGroup(originGroup)
.withDescription("My Description")
.withPolicyType(ResourcePolicy.TYPE_CUSTOM)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
// verify origin resourcepolicy
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.group.id", is(originGroup.getID().toString())))
.andExpect(jsonPath("$._embedded.eperson", nullValue()));
// try to update group of resourcepolicy with anonymous user
getClient().perform(put("/api/authz/resourcepolicies/" + resourcePolicy.getID() + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/groups/" + newGroup.getID()))
.andExpect(status().isUnauthorized());
// verify that resourcepolicy hasn't been changed
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/" + resourcePolicy.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.group.id", is(originGroup.getID().toString())))
.andExpect(jsonPath("$._embedded.eperson", nullValue()));
}
@Test
public void updateResourcePolicyOfEPersonToGroupTest() throws Exception {
context.turnOffAuthorisationSystem();
Group group = GroupBuilder.createGroup(context)
.withName("My group")
.build();
Community community = CommunityBuilder.createCommunity(context)
.withName("My community")
.build();
ResourcePolicy resourcePolicyOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context)
.withDspaceObject(community)
.withAction(Constants.READ)
.withUser(eperson)
.build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(get("/api/authz/resourcepolicies/" + resourcePolicyOfEPerson.getID()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", is(ResourcePolicyMatcher.matchResourcePolicy(resourcePolicyOfEPerson))))
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/authz/resourcepolicies/"
+ resourcePolicyOfEPerson.getID())));
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + resourcePolicyOfEPerson.getID() + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/groups/" + group.getID()))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void updateResourcePolicyOfGroupToEPersonTest() throws Exception {
context.turnOffAuthorisationSystem();
Group group = GroupBuilder.createGroup(context)
.withName("My group")
.build();
Community community = CommunityBuilder.createCommunity(context)
.withName("My community")
.build();
ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context)
.withDspaceObject(community)
.withAction(Constants.ADD)
.withGroup(group).build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(get("/api/authz/resourcepolicies/search/group")
.param("uuid", group.getID().toString()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.containsInAnyOrder(
ResourcePolicyMatcher.matchResourcePolicy(resourcePolicyOfGroup))))
.andExpect(jsonPath("$._links.self.href", Matchers.containsString(
"api/authz/resourcepolicies/search/group")))
.andExpect(jsonPath("$.page.totalElements", is(1)));
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + resourcePolicyOfGroup.getID() + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/epersons/" + eperson.getID()))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void updateEPersonOfNotExistingResourcePolicyTest() throws Exception {
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + Integer.MAX_VALUE + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/epersons/" + eperson.getID()))
.andExpect(status().isNotFound());
}
@Test
public void updateGroupOfNotExistingResourcePolicyTest() throws Exception {
context.turnOffAuthorisationSystem();
Group group = GroupBuilder.createGroup(context)
.withName("My group")
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + Integer.MAX_VALUE + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/groups/" + group.getID()))
.andExpect(status().isNotFound());
}
@Test
public void updateResourcePolicyOfGroupWithEmptyTest() throws Exception {
context.turnOffAuthorisationSystem();
Group group = GroupBuilder.createGroup(context)
.withName("My group")
.build();
Community community = CommunityBuilder.createCommunity(context)
.withName("My community")
.build();
ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context)
.withDspaceObject(community)
.withAction(Constants.ADD)
.withGroup(group).build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + resourcePolicyOfGroup.getID() + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content(StringUtils.EMPTY))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void updateResourcePolicyOfGroupWithMultipleGroupsTest() throws Exception {
context.turnOffAuthorisationSystem();
Group group1 = GroupBuilder.createGroup(context).withName("My group").build();
Group group2 = GroupBuilder.createGroup(context).withName("My group2").build();
Community community = CommunityBuilder.createCommunity(context)
.withName("My community")
.build();
ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context)
.withDspaceObject(community)
.withAction(Constants.ADD)
.withGroup(group1).build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + resourcePolicyOfGroup.getID() + "/group")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/groups/" + group1.getID() +
"\n/api/eperson/groups/" + group2.getID()))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void updateResourcePolicyOfEPersonWithEmptyTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = CommunityBuilder.createCommunity(context).withName("My community").build();
ResourcePolicy rpOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context)
.withDspaceObject(community)
.withAction(Constants.READ)
.withUser(eperson)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + rpOfEPerson.getID() + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content(StringUtils.EMPTY))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void updateResourcePolicyOfEPersonWithMultipleEPersonsTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson eperson1 = EPersonBuilder.createEPerson(context)
.withEmail("eperson1@mail.com")
.withPassword(password)
.build();
EPerson eperson2 = EPersonBuilder.createEPerson(context)
.withEmail("eperson2@mail.com")
.withPassword(password)
.build();
Community community = CommunityBuilder.createCommunity(context).withName("My community").build();
ResourcePolicy rpOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context)
.withDspaceObject(community)
.withAction(Constants.READ)
.withUser(eperson)
.build();
context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(put("/api/authz/resourcepolicies/" + rpOfEPerson.getID() + "/eperson")
.contentType(parseMediaType(TEXT_URI_LIST_VALUE))
.content("/api/eperson/epersons/" + eperson1.getID() +
"\n/api/eperson/epersons/" + eperson2.getID()))
.andExpect(status().isUnprocessableEntity());
}
}

View File

@@ -11,3 +11,4 @@ org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException.message = [PL] Ref
workflow group {1}. Delete the tasks and group first if you want to remove this user.
org.dspace.app.rest.exception.EPersonNameNotProvidedException.message = [PL] The eperson.firstname and eperson.lastname values need to be filled in
org.dspace.app.rest.exception.GroupNameNotProvidedException.message = [PL] Cannot create group, no group name is provided
org.dspace.app.rest.exception.GroupHasPendingWorkflowTasksException.message = [PL] Cannot delete group, the associated workflow role still has pending tasks