[CST-7754] LYRASIS: Supervisor orders (REST).

This commit is contained in:
Mohamed Saber Eskander
2022-12-22 17:40:43 +02:00
committed by eskander
parent ec0853ddad
commit dea4b5e17f
39 changed files with 3210 additions and 2 deletions

View File

@@ -0,0 +1,39 @@
/**
* 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.exception;
/**
* This class provides an exception to be used when a conflict on a resource
* occurs.
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*
*/
public class ResourceConflictException extends RuntimeException {
private static final long serialVersionUID = 1L;
private final Object resource;
/**
* Create a ResourceConflictException with a message and the conflicting
* resource.
*
* @param message the error message
* @param resource the resource that caused the conflict
*/
public ResourceConflictException(String message, Object resource) {
super(message);
this.resource = resource;
}
public Object getResource() {
return resource;
}
}

View File

@@ -0,0 +1,72 @@
/**
* 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.discovery;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.content.Item;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.Context;
import org.dspace.discovery.indexobject.IndexableInProgressSubmission;
import org.dspace.discovery.indexobject.IndexableWorkflowItem;
import org.dspace.discovery.indexobject.IndexableWorkspaceItem;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.supervision.service.SupervisionOrderService;
import org.dspace.workflow.WorkflowItemService;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public class SolrServiceSupervisionOrderIndexingPlugin implements SolrServiceIndexPlugin {
@Autowired(required = true)
private WorkspaceItemService workspaceItemService;
@Autowired(required = true)
private WorkflowItemService workflowItemService;
@Autowired(required = true)
private SupervisionOrderService supervisionOrderService;
@Override
public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) {
try {
if (!(indexableObject instanceof IndexableWorkspaceItem) &&
!(indexableObject instanceof IndexableWorkflowItem)) {
return;
}
Item item =
(((IndexableInProgressSubmission) indexableObject).getIndexedObject()).getItem();
if (Objects.isNull(item)) {
return;
}
addSupervisedField(context, item, document);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private void addSupervisedField(Context context, Item item, SolrInputDocument document) throws SQLException {
List<SupervisionOrder> supervisionOrders = supervisionOrderService.findByItem(context, item);
if (CollectionUtils.isNotEmpty(supervisionOrders)) {
document.addField("supervised", true);
} else {
document.addField("supervised", false);
}
}
}

View File

@@ -40,6 +40,11 @@ public class SolrServiceWorkspaceWorkflowRestrictionPlugin implements SolrServic
*/
public static final String DISCOVER_WORKFLOW_ADMIN_CONFIGURATION_NAME = "workflowAdmin";
/**
* The name of the discover configuration used by administrators to search for workspace and workflow tasks
*/
public static final String DISCOVER_SUPERVISION_CONFIGURATION_NAME = "supervision";
@Autowired(required = true)
protected GroupService groupService;
@@ -60,18 +65,22 @@ public class SolrServiceWorkspaceWorkflowRestrictionPlugin implements SolrServic
);
boolean isWorkflowAdmin = isAdmin(context)
&& DISCOVER_WORKFLOW_ADMIN_CONFIGURATION_NAME.equals(discoveryQuery.getDiscoveryConfigurationName());
boolean isSupervision =
DISCOVER_SUPERVISION_CONFIGURATION_NAME.equals(discoveryQuery.getDiscoveryConfigurationName());
EPerson currentUser = context.getCurrentUser();
// extra security check to avoid the possibility that an anonymous user
// get access to workspace or workflow
if (currentUser == null && (isWorkflow || isWorkspace)) {
if (currentUser == null && (isWorkflow || isWorkspace || isSupervision)) {
throw new IllegalStateException(
"An anonymous user cannot perform a workspace or workflow search");
}
if (isWorkspace) {
// insert filter by submitter
solrQuery.addFilterQuery("submitter_authority:(" + currentUser.getID() + ")");
} else if (isWorkflow && !isWorkflowAdmin) {
} else if ((isWorkflow && !isWorkflowAdmin) || (isSupervision && !isAdmin(context))) {
// Retrieve all the groups the current user is a member of !
Set<Group> groups;
try {

View File

@@ -22,6 +22,8 @@ import org.dspace.discovery.indexobject.factory.CollectionIndexFactory;
import org.dspace.discovery.indexobject.factory.InprogressSubmissionIndexFactory;
import org.dspace.discovery.indexobject.factory.ItemIndexFactory;
import org.dspace.eperson.EPerson;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.supervision.service.SupervisionOrderService;
import org.dspace.util.SolrUtils;
import org.dspace.workflow.WorkflowItem;
import org.springframework.beans.factory.annotation.Autowired;
@@ -39,6 +41,9 @@ public abstract class InprogressSubmissionIndexFactoryImpl
@Autowired
protected ItemIndexFactory indexableItemService;
@Autowired
protected SupervisionOrderService supervisionOrderService;
@Override
public SolrInputDocument buildDocument(Context context, T indexableObject) throws SQLException, IOException {
@@ -60,6 +65,8 @@ public abstract class InprogressSubmissionIndexFactoryImpl
submitter.getFullName());
}
addSupervisedByFacetIndex(context, item, doc);
doc.addField("inprogress.item", new IndexableItem(inProgressSubmission.getItem()).getUniqueIndexID());
// get the location string (for searching by collection & community)
@@ -82,4 +89,13 @@ public abstract class InprogressSubmissionIndexFactoryImpl
indexableItemService.addDiscoveryFields(doc, context, item, discoveryConfigurations);
indexableCollectionService.storeCommunityCollectionLocations(doc, locations);
}
private void addSupervisedByFacetIndex(Context context, Item item, SolrInputDocument doc) throws SQLException {
List<SupervisionOrder> supervisionOrders = supervisionOrderService.findByItem(context, item);
for (SupervisionOrder supervisionOrder : supervisionOrders) {
addFacetIndex(doc, "supervisedBy", supervisionOrder.getGroup().getID().toString(),
supervisionOrder.getGroup().getName());
}
}
}

View File

@@ -0,0 +1,78 @@
/**
* 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.supervision;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.core.ReloadableEntity;
import org.dspace.eperson.Group;
import org.dspace.supervision.service.SupervisionOrderService;
/**
* Database entity representation of the supervision_orders table
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
@Entity
@Table(name = "supervision_orders")
public class SupervisionOrder implements ReloadableEntity<Integer> {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "supervision_orders_seq")
@SequenceGenerator(name = "supervision_orders_seq", sequenceName = "supervision_orders_seq", allocationSize = 1)
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "eperson_group_id")
private Group group;
/**
* Protected constructor, create object using:
* {@link SupervisionOrderService#create(Context, Item, Group)}
*/
protected SupervisionOrder() {
}
@Override
public Integer getID() {
return id;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}

View File

@@ -0,0 +1,126 @@
/**
* 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.supervision;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.dspace.event.Event;
import org.dspace.supervision.dao.SupervisionOrderDao;
import org.dspace.supervision.service.SupervisionOrderService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Implementation of {@link SupervisionOrderService}
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public class SupervisionOrderServiceImpl implements SupervisionOrderService {
@Autowired(required = true)
private SupervisionOrderDao supervisionDao;
@Autowired(required = true)
private GroupService groupService;
@Autowired(required = true)
private ItemService itemService;
protected SupervisionOrderServiceImpl() {
}
@Override
public SupervisionOrder create(Context context) throws SQLException, AuthorizeException {
return supervisionDao.create(context, new SupervisionOrder());
}
@Override
public SupervisionOrder find(Context context, int id) throws SQLException {
return supervisionDao.findByID(context, SupervisionOrder.class, id);
}
@Override
public void update(Context context, SupervisionOrder supervisionOrder)
throws SQLException, AuthorizeException {
supervisionDao.save(context, supervisionOrder);
}
@Override
public void update(Context context, List<SupervisionOrder> supervisionOrders)
throws SQLException, AuthorizeException {
if (CollectionUtils.isNotEmpty(supervisionOrders)) {
for (SupervisionOrder supervisionOrder : supervisionOrders) {
supervisionDao.save(context, supervisionOrder);
}
}
}
@Override
public void delete(Context context, SupervisionOrder supervisionOrder) throws SQLException, AuthorizeException {
supervisionDao.delete(context, supervisionOrder);
}
@Override
public SupervisionOrder create(Context context, Item item, Group group) throws SQLException {
SupervisionOrder supervisionOrder = new SupervisionOrder();
supervisionOrder.setItem(item);
supervisionOrder.setGroup(group);
SupervisionOrder supOrder = supervisionDao.create(context, supervisionOrder);
context.addEvent(new Event(Event.MODIFY, Constants.ITEM, item.getID(), null,
itemService.getIdentifiers(context, item)));
return supOrder;
}
@Override
public List<SupervisionOrder> findAll(Context context) throws SQLException {
return supervisionDao.findAll(context, SupervisionOrder.class);
}
@Override
public List<SupervisionOrder> findByItem(Context context, Item item) throws SQLException {
return supervisionDao.findByItem(context, item);
}
@Override
public SupervisionOrder findByItemAndGroup(Context context, Item item, Group group) throws SQLException {
return supervisionDao.findByItemAndGroup(context, item, group);
}
@Override
public boolean isSupervisor(Context context, EPerson ePerson, Item item) throws SQLException {
List<SupervisionOrder> supervisionOrders = findByItem(context, item);
if (CollectionUtils.isEmpty(supervisionOrders)) {
return false;
}
return supervisionOrders
.stream()
.map(SupervisionOrder::getGroup)
.anyMatch(group -> isMember(context, ePerson, group));
}
private boolean isMember(Context context, EPerson ePerson, Group group) {
try {
return groupService.isMember(context, ePerson, group);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,32 @@
/**
* 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.supervision.dao;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
import org.dspace.eperson.Group;
import org.dspace.supervision.SupervisionOrder;
/**
* Database Access Object interface class for the SupervisionOrder object.
*
* The implementation of this class is responsible for all database calls for the SupervisionOrder object
* and is autowired by spring
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public interface SupervisionOrderDao extends GenericDAO<SupervisionOrder> {
List<SupervisionOrder> findByItem(Context context, Item item) throws SQLException;
SupervisionOrder findByItemAndGroup(Context context, Item item, Group group) throws SQLException;
}

View File

@@ -0,0 +1,59 @@
/**
* 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.supervision.dao.impl;
import java.sql.SQLException;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.content.Item;
import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context;
import org.dspace.eperson.Group;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.supervision.SupervisionOrder_;
import org.dspace.supervision.dao.SupervisionOrderDao;
/**
* Hibernate implementation of the Database Access Object interface class for the SupervisionOrder object.
* This class is responsible for all database calls for the SupervisionOrder object
* and is autowired by spring
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public class SupervisionOrderDaoImpl extends AbstractHibernateDAO<SupervisionOrder> implements SupervisionOrderDao {
@Override
public List<SupervisionOrder> findByItem(Context context, Item item) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, SupervisionOrder.class);
Root<SupervisionOrder> supervisionOrderRoot = criteriaQuery.from(SupervisionOrder.class);
criteriaQuery.select(supervisionOrderRoot);
criteriaQuery.where(criteriaBuilder.equal(supervisionOrderRoot.get(SupervisionOrder_.item), item));
return list(context, criteriaQuery, false, SupervisionOrder.class, -1, -1);
}
@Override
public SupervisionOrder findByItemAndGroup(Context context, Item item, Group group) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, SupervisionOrder.class);
Root<SupervisionOrder> supervisionOrderRoot = criteriaQuery.from(SupervisionOrder.class);
criteriaQuery.select(supervisionOrderRoot);
criteriaQuery.where(criteriaBuilder.and(
criteriaBuilder.equal(supervisionOrderRoot.get(SupervisionOrder_.item), item),
criteriaBuilder.equal(supervisionOrderRoot.get(SupervisionOrder_.group), group)
));
return singleResult(context, criteriaQuery);
}
}

View File

@@ -0,0 +1,17 @@
/**
* 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.supervision.enumeration;
/**
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public enum SupervisionOrderType {
OBSERVER,
EDITOR
}

View File

@@ -0,0 +1,29 @@
/**
* 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.supervision.factory;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.supervision.service.SupervisionOrderService;
/**
* Abstract factory to get services for the supervision package,
* use SupervisionOrderServiceFactory.getInstance() to retrieve an implementation
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public abstract class SupervisionOrderServiceFactory {
public abstract SupervisionOrderService getSupervisionOrderService();
public static SupervisionOrderServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance()
.getServiceManager()
.getServiceByName("supervisionOrderServiceFactory",
SupervisionOrderServiceFactory.class);
}
}

View File

@@ -0,0 +1,28 @@
/**
* 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.supervision.factory;
import org.dspace.supervision.service.SupervisionOrderService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Factory implementation to get services for the supervision package,
* use SupervisionOrderServiceFactory.getInstance() to retrieve an implementation
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public class SupervisionOrderServiceFactoryImpl extends SupervisionOrderServiceFactory {
@Autowired(required = true)
private SupervisionOrderService supervisionOrderService;
@Override
public SupervisionOrderService getSupervisionOrderService() {
return supervisionOrderService;
}
}

View File

@@ -0,0 +1,32 @@
/**
* 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.supervision.service;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.service.DSpaceCRUDService;
import org.dspace.supervision.SupervisionOrder;
/**
* Service interface class for the SupervisionOrder object.
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public interface SupervisionOrderService extends DSpaceCRUDService<SupervisionOrder> {
SupervisionOrder create(Context context, Item item, Group group) throws SQLException;
List<SupervisionOrder> findAll(Context context) throws SQLException;
List<SupervisionOrder> findByItem(Context context, Item item) throws SQLException;
SupervisionOrder findByItemAndGroup(Context context, Item item, Group group) throws SQLException;
boolean isSupervisor(Context context, EPerson ePerson, Item item) throws SQLException;
}

View File

@@ -0,0 +1,20 @@
--
-- 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/
--
-------------------------------------------------------------------------------
-- Table to store supervision orders
-------------------------------------------------------------------------------
CREATE TABLE supervision_orders
(
id INTEGER PRIMARY KEY,
item_id UUID REFERENCES Item(uuid) ON DELETE CASCADE,
eperson_group_id UUID REFERENCES epersongroup(uuid) ON DELETE CASCADE
);
CREATE SEQUENCE supervision_orders_seq;

View File

@@ -0,0 +1,20 @@
--
-- 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/
--
-------------------------------------------------------------------------------
-- Table to store supervision orders
-------------------------------------------------------------------------------
CREATE TABLE supervision_orders
(
id INTEGER PRIMARY KEY,
item_id UUID REFERENCES Item(uuid) ON DELETE CASCADE,
eperson_group_id UUID REFERENCES epersongroup(uuid) ON DELETE CASCADE
);
CREATE SEQUENCE supervision_orders_seq;

View File

@@ -0,0 +1,20 @@
--
-- 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/
--
-------------------------------------------------------------------------------
-- Table to store supervision orders
-------------------------------------------------------------------------------
CREATE TABLE supervision_orders
(
id INTEGER PRIMARY KEY,
item_id UUID REFERENCES Item(uuid) ON DELETE CASCADE,
eperson_group_id UUID REFERENCES epersongroup(uuid) ON DELETE CASCADE
);
CREATE SEQUENCE supervision_orders_seq;

View File

@@ -49,6 +49,8 @@ import org.dspace.orcid.service.OrcidTokenService;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.service.ProcessService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.supervision.factory.SupervisionOrderServiceFactory;
import org.dspace.supervision.service.SupervisionOrderService;
import org.dspace.versioning.factory.VersionServiceFactory;
import org.dspace.versioning.service.VersionHistoryService;
import org.dspace.versioning.service.VersioningService;
@@ -102,6 +104,8 @@ public abstract class AbstractBuilder<T, S> {
static OrcidHistoryService orcidHistoryService;
static OrcidQueueService orcidQueueService;
static OrcidTokenService orcidTokenService;
static SupervisionOrderService supervisionOrderService;
protected Context context;
@@ -161,6 +165,7 @@ public abstract class AbstractBuilder<T, S> {
orcidHistoryService = OrcidServiceFactory.getInstance().getOrcidHistoryService();
orcidQueueService = OrcidServiceFactory.getInstance().getOrcidQueueService();
orcidTokenService = OrcidServiceFactory.getInstance().getOrcidTokenService();
supervisionOrderService = SupervisionOrderServiceFactory.getInstance().getSupervisionOrderService();
}
@@ -194,6 +199,7 @@ public abstract class AbstractBuilder<T, S> {
requestItemService = null;
versioningService = null;
orcidTokenService = null;
supervisionOrderService = null;
}

View File

@@ -0,0 +1,94 @@
/**
* 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.builder;
import java.sql.SQLException;
import java.util.Objects;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.eperson.Group;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.supervision.service.SupervisionOrderService;
/**
* Abstract builder to construct SupervisionOrder Objects
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public class SupervisionOrderBuilder
extends AbstractBuilder<SupervisionOrder, SupervisionOrderService> {
private static final Logger log = LogManager.getLogger(SupervisionOrderBuilder.class);
private SupervisionOrder supervisionOrder;
protected SupervisionOrderBuilder(Context context) {
super(context);
}
public static SupervisionOrderBuilder createSupervisionOrder(Context context, Item item, Group group) {
SupervisionOrderBuilder builder = new SupervisionOrderBuilder(context);
return builder.create(context, item, group);
}
private SupervisionOrderBuilder create(Context context, Item item, Group group) {
try {
this.context = context;
this.supervisionOrder = getService().create(context, item, group);
} catch (Exception e) {
log.error("Error in SupervisionOrderBuilder.create(..), error: ", e);
}
return this;
}
@Override
public void cleanup() throws Exception {
delete(supervisionOrder);
}
@Override
public SupervisionOrder build() throws SQLException, AuthorizeException {
try {
getService().update(context, supervisionOrder);
context.dispatchEvents();
indexingService.commit();
} catch (Exception e) {
log.error("Error in SupervisionOrderBuilder.build(), error: ", e);
}
return supervisionOrder;
}
@Override
public void delete(Context context, SupervisionOrder supervisionOrder) throws Exception {
if (Objects.nonNull(supervisionOrder)) {
getService().delete(context, supervisionOrder);
}
}
@Override
protected SupervisionOrderService getService() {
return supervisionOrderService;
}
private void delete(SupervisionOrder supervisionOrder) throws Exception {
try (Context context = new Context()) {
context.turnOffAuthorisationSystem();
context.setDispatcher("noindex");
SupervisionOrder attached = context.reloadEntity(supervisionOrder);
if (attached != null) {
getService().delete(context, attached);
}
context.complete();
indexingService.commit();
}
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.converter;
import java.util.Objects;
import org.dspace.app.rest.model.SupervisionOrderRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.content.Item;
import org.dspace.eperson.Group;
import org.dspace.supervision.SupervisionOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
/**
* This class is responsible to convert SupervisionOrder to its rest model
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
@Component
public class SupervisionOrderConverter
implements DSpaceConverter<SupervisionOrder, SupervisionOrderRest> {
@Lazy
@Autowired
private ConverterService converter;
@Override
public SupervisionOrderRest convert(SupervisionOrder modelObject, Projection projection) {
SupervisionOrderRest rest = new SupervisionOrderRest();
Item item = modelObject.getItem();
Group group = modelObject.getGroup();
rest.setId(modelObject.getID());
if (Objects.nonNull(item)) {
rest.setItem(converter.toRest(item, projection));
}
if (Objects.nonNull(group)) {
rest.setGroup(converter.toRest(group, projection));
}
rest.setProjection(projection);
return rest;
}
@Override
public Class<SupervisionOrder> getModelClass() {
return SupervisionOrder.class;
}
}

View File

@@ -22,13 +22,19 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.exception.ResourceAlreadyExistsException;
import org.dspace.app.exception.ResourceConflictException;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.model.RestModel;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.dspace.eperson.InvalidReCaptchaException;
import org.dspace.orcid.exception.OrcidValidationException;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.repository.support.QueryMethodParameterConversionException;
import org.springframework.http.HttpHeaders;
@@ -60,6 +66,13 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionHandler {
private static final Logger log = LogManager.getLogger();
@Autowired
@Lazy
private ConverterService converterService;
@Autowired
private Utils utils;
/**
* Default collection of HTTP error codes to log as ERROR with full stack trace.
*/
@@ -235,6 +248,12 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
}
@ExceptionHandler(ResourceConflictException.class)
protected ResponseEntity<? extends RestModel> resourceConflictException(ResourceConflictException ex) {
RestModel resource = converterService.toRest(ex.getResource(), utils.obtainProjection());
return new ResponseEntity<RestModel>(resource, HttpStatus.CONFLICT);
}
/**
* Send the error to the response.
* 5xx errors will be logged as ERROR with a full stack trace. 4xx errors

View File

@@ -0,0 +1,72 @@
/**
* 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.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.dspace.app.rest.RestResourceController;
import org.dspace.supervision.SupervisionOrder;
/**
* The REST Resource of {@link SupervisionOrder}.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*/
public class SupervisionOrderRest extends BaseObjectRest<Integer> {
public static final String NAME = "supervisionorder";
public static final String CATEGORY = RestAddressableModel.CORE;
private Integer id;
@JsonIgnore
private ItemRest item;
@JsonIgnore
private GroupRest group;
@Override
public Integer getId() {
return id;
}
@Override
public void setId(Integer id) {
this.id = id;
}
public ItemRest getItem() {
return item;
}
public void setItem(ItemRest item) {
this.item = item;
}
public GroupRest getGroup() {
return group;
}
public void setGroup(GroupRest group) {
this.group = group;
}
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public Class getController() {
return RestResourceController.class;
}
@Override
public String getType() {
return NAME;
}
}

View File

@@ -14,10 +14,18 @@ import org.dspace.app.rest.RestResourceController;
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
@LinksRest(links = {
@LinkRest(
name = WorkspaceItemRest.SUPERVISION_ORDERS,
method = "getSupervisionOrders"
)
})
public class WorkspaceItemRest extends AInprogressSubmissionRest {
public static final String NAME = "workspaceitem";
public static final String CATEGORY = RestAddressableModel.SUBMISSION;
public static final String SUPERVISION_ORDERS = "supervisionOrders";
@Override
public String getCategory() {
return CATEGORY;

View File

@@ -0,0 +1,25 @@
/**
* 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.model.hateoas;
import org.dspace.app.rest.model.SupervisionOrderRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
import org.dspace.app.rest.utils.Utils;
/**
* SupervisionOrder Rest HAL Resource. The HAL Resource wraps the REST Resource
* adding support for the links and embedded resources
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
@RelNameDSpaceResource(SupervisionOrderRest.NAME)
public class SupervisionOrderResource extends DSpaceResource<SupervisionOrderRest> {
public SupervisionOrderResource(SupervisionOrderRest data, Utils utils) {
super(data, utils);
}
}

View File

@@ -0,0 +1,219 @@
/**
* 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.repository;
import static org.dspace.authorize.ResourcePolicy.TYPE_SUBMISSION;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.exception.ResourceConflictException;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.MissingParameterException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.SupervisionOrderRest;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.supervision.enumeration.SupervisionOrderType;
import org.dspace.supervision.service.SupervisionOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
* This is the repository responsible to manage SupervisionOrderRest object
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
@Component(SupervisionOrderRest.CATEGORY + "." + SupervisionOrderRest.NAME)
public class SupervisionOrderRestRepository extends DSpaceRestRepository<SupervisionOrderRest, Integer> {
private static final Logger log =
org.apache.logging.log4j.LogManager.getLogger(SupervisionOrderRestRepository.class);
@Autowired
private SupervisionOrderService supervisionOrderService;
@Autowired
private ConverterService converterService;
@Autowired
private ItemService itemService;
@Autowired
private GroupService groupService;
@Autowired
private AuthorizeService authorizeService;
@PreAuthorize("hasAuthority('ADMIN')")
@Override
public SupervisionOrderRest findOne(Context context, Integer id) {
try {
SupervisionOrder supervisionOrder = supervisionOrderService.find(context, id);
if (Objects.isNull(supervisionOrder)) {
throw new ResourceNotFoundException("Couldn't find supervision order for id: " + id);
}
return converterService.toRest(supervisionOrder, utils.obtainProjection());
} catch (SQLException e) {
log.error("Something went wrong with getting supervision order with id:" + id, e);
throw new RuntimeException(e.getMessage(), e);
}
}
@PreAuthorize("hasAuthority('ADMIN')")
@Override
public Page<SupervisionOrderRest> findAll(Context context, Pageable pageable) {
try {
List<SupervisionOrder> supervisionOrders = supervisionOrderService.findAll(context);
return converterService.toRestPage(supervisionOrders, pageable, utils.obtainProjection());
} catch (SQLException e) {
log.error("Something went wrong with getting supervision orders", e);
throw new RuntimeException(e.getMessage(), e);
}
}
@PreAuthorize("hasAuthority('ADMIN')")
@Override
public SupervisionOrderRest createAndReturn(Context context) throws AuthorizeException, SQLException {
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
SupervisionOrder supervisionOrder;
String itemId = req.getParameter("uuid");
String groupId = req.getParameter("group");
String type = req.getParameter("type");
validateParameters(itemId, groupId, type);
Item item = itemService.find(context, UUID.fromString(itemId));
if (item == null) {
throw new UnprocessableEntityException("Item with uuid: " + itemId + " not found");
}
Group group = groupService.find(context, UUID.fromString(groupId));
if (group == null) {
throw new UnprocessableEntityException("Group with uuid: " + groupId + " not found");
}
supervisionOrder = supervisionOrderService.findByItemAndGroup(context, item, group);
if (Objects.nonNull(supervisionOrder)) {
throw new ResourceConflictException(
"There is a conflict supervision order with itemId <" + itemId + "> and groupId <" + groupId + ">",
supervisionOrder
);
}
supervisionOrder = supervisionOrderService.create(context, item, group);
addGroupPoliciesToItem(context, item, group, type);
return converterService.toRest(supervisionOrder, utils.obtainProjection());
}
@PreAuthorize("hasAuthority('ADMIN')")
@Override
protected void delete(Context context, Integer id)
throws AuthorizeException, RepositoryMethodNotImplementedException {
try {
SupervisionOrder supervisionOrder = supervisionOrderService.find(context, id);
if (Objects.isNull(supervisionOrder)) {
throw new ResourceNotFoundException(
SupervisionOrderRest.CATEGORY + "." + SupervisionOrderRest.NAME +
" with id: " + id + " not found"
);
}
supervisionOrderService.delete(context, supervisionOrder);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@PreAuthorize("hasAuthority('ADMIN')")
@SearchRestMethod(name = "byItem")
public Page<SupervisionOrderRest> findByItem(@Parameter(value = "uuid", required = true) String itemId,
Pageable pageable) {
try {
Context context = obtainContext();
Item item = itemService.find(context, UUID.fromString(itemId));
if (Objects.isNull(item)) {
throw new ResourceNotFoundException("no item is found for the uuid < " + itemId + " >");
}
return converterService.toRestPage(supervisionOrderService.findByItem(context, item),
pageable, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public Class<SupervisionOrderRest> getDomainClass() {
return SupervisionOrderRest.class;
}
private void validateParameters(String itemId, String groupId, String type) {
if (Objects.isNull(itemId)) {
throw new MissingParameterException("Missing item (uuid) parameter");
}
if (Objects.isNull(groupId)) {
throw new MissingParameterException("Missing group (uuid) parameter");
}
if (Objects.isNull(type)) {
throw new MissingParameterException("Missing type parameter");
} else if (!type.equals(SupervisionOrderType.EDITOR.toString()) &&
!type.equals(SupervisionOrderType.OBSERVER.toString())) {
throw new IllegalArgumentException("wrong type value, Type must be (EDITOR or OBSERVER)");
}
}
private void addGroupPoliciesToItem(Context context, Item item, Group group, String type)
throws SQLException, AuthorizeException {
if (StringUtils.isNotEmpty(type)) {
if (type.equals("EDITOR")) {
addGroupPolicyToItem(context, item, Constants.READ, group, TYPE_SUBMISSION);
addGroupPolicyToItem(context, item, Constants.WRITE, group, TYPE_SUBMISSION);
} else if (type.equals("OBSERVER")) {
addGroupPolicyToItem(context, item, Constants.READ, group, TYPE_SUBMISSION);
}
}
}
private void addGroupPolicyToItem(Context context, Item item, int action, Group group, String policyType)
throws AuthorizeException, SQLException {
authorizeService.addPolicy(context, item, action, group, policyType);
List<Bundle> bundles = item.getBundles();
for (Bundle bundle : bundles) {
authorizeService.addPolicy(context, bundle, action, group, policyType);
List<Bitstream> bits = bundle.getBitstreams();
for (Bitstream bitstream : bits) {
authorizeService.addPolicy(context, bitstream, action, group, policyType);
}
}
}
}

View File

@@ -0,0 +1,61 @@
/**
* 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.repository;
import java.sql.SQLException;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.model.SupervisionOrderRest;
import org.dspace.app.rest.model.WorkspaceItemRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.Context;
import org.dspace.supervision.service.SupervisionOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
* Link repository for the supervision orders of an WorkspaceItem
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.SUPERVISION_ORDERS)
public class WorkspaceItemSupervisionOrdersLinkRepository
extends AbstractDSpaceRestRepository implements LinkRestRepository {
@Autowired
WorkspaceItemService workspaceItemService;
@Autowired
SupervisionOrderService supervisionOrderService;
@PreAuthorize("hasAuthority('ADMIN')")
public Page<SupervisionOrderRest> getSupervisionOrders(@Nullable HttpServletRequest request,
Integer id,
@Nullable Pageable optionalPageable,
Projection projection) {
try {
Context context = obtainContext();
WorkspaceItem workspaceItem = workspaceItemService.find(context, id);
if (workspaceItem == null) {
throw new ResourceNotFoundException("No such workspace item: " + id);
}
return converter.toRestPage(
supervisionOrderService.findByItem(context, workspaceItem.getItem()),
optionalPageable, projection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -20,6 +20,7 @@ import org.dspace.eperson.EPerson;
import org.dspace.eperson.service.EPersonService;
import org.dspace.services.RequestService;
import org.dspace.services.model.Request;
import org.dspace.supervision.service.SupervisionOrderService;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService;
@@ -56,6 +57,9 @@ public class WorkflowRestPermissionEvaluatorPlugin extends RestObjectPermissionE
@Autowired
private EPersonService ePersonService;
@Autowired
private SupervisionOrderService supervisionOrderService;
@Override
public boolean hasDSpacePermission(Authentication authentication, Serializable targetId,
String targetType, DSpaceRestPermission permission) {
@@ -89,6 +93,11 @@ public class WorkflowRestPermissionEvaluatorPlugin extends RestObjectPermissionE
if (claimedTaskService.findByWorkflowIdAndEPerson(context, workflowItem, ePerson) != null) {
return true;
}
if (supervisionOrderService.isSupervisor(context, ePerson, workflowItem.getItem())) {
return true;
}
} catch (SQLException | AuthorizeException | IOException e) {
log.error(e.getMessage(), e);
}

View File

@@ -19,6 +19,7 @@ import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.services.RequestService;
import org.dspace.services.model.Request;
import org.dspace.supervision.service.SupervisionOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,6 +42,9 @@ public class WorkspaceItemRestPermissionEvaluatorPlugin extends RestObjectPermis
@Autowired
WorkspaceItemService wis;
@Autowired
private SupervisionOrderService supervisionOrderService;
@Override
public boolean hasDSpacePermission(Authentication authentication, Serializable targetId, String targetType,
DSpaceRestPermission permission) {
@@ -82,6 +86,13 @@ public class WorkspaceItemRestPermissionEvaluatorPlugin extends RestObjectPermis
return true;
}
}
if (witem.getItem() != null) {
if (supervisionOrderService.isSupervisor(context, ePerson, witem.getItem())) {
return true;
}
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
}

View File

@@ -64,6 +64,7 @@ import org.dspace.app.rest.model.PropertyRest;
import org.dspace.app.rest.model.ResourcePolicyRest;
import org.dspace.app.rest.model.RestAddressableModel;
import org.dspace.app.rest.model.RestModel;
import org.dspace.app.rest.model.SupervisionOrderRest;
import org.dspace.app.rest.model.VersionHistoryRest;
import org.dspace.app.rest.model.VocabularyRest;
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
@@ -296,6 +297,9 @@ public class Utils {
if (StringUtils.equals(modelPlural, "orcidhistories")) {
return OrcidHistoryRest.NAME;
}
if (StringUtils.equals(modelPlural, "supervisionorders")) {
return SupervisionOrderRest.NAME;
}
return modelPlural.replaceAll("s$", "");
}

View File

@@ -9,11 +9,13 @@ package org.dspace.app.rest;
import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.dspace.app.rest.matcher.FacetValueMatcher.entrySupervisedBy;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
@@ -48,6 +50,7 @@ import org.dspace.builder.EPersonBuilder;
import org.dspace.builder.GroupBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.PoolTaskBuilder;
import org.dspace.builder.SupervisionOrderBuilder;
import org.dspace.builder.WorkflowItemBuilder;
import org.dspace.builder.WorkspaceItemBuilder;
import org.dspace.content.Bitstream;
@@ -63,6 +66,7 @@ import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.hamcrest.Matchers;
@@ -5987,4 +5991,491 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
.andExpect(jsonPath("$._embedded.values").value(Matchers.hasSize(1)));
}
@Test
public void discoverFacetsSupervisedByTest() throws Exception {
//We turn off the authorization system in order to create the structure defined below
context.turnOffAuthorisationSystem();
//** GIVEN **
//1. A community-collection structure with one parent community and one collection
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection collection =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
//2. Two workspace items
WorkspaceItem wsItem1 =
WorkspaceItemBuilder.createWorkspaceItem(context, collection)
.withTitle("Workspace Item 1")
.withIssueDate("2010-07-23")
.build();
WorkspaceItem wsItem2 =
WorkspaceItemBuilder.createWorkspaceItem(context, collection)
.withTitle("Workspace Item 2")
.withIssueDate("2010-11-03")
.build();
//3. Two groups
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(eperson)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(eperson)
.build();
//4. Four supervision orders
SupervisionOrder supervisionOrderOne =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem1.getItem(), groupA).build();
SupervisionOrder supervisionOrderTwo =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem1.getItem(), groupB).build();
SupervisionOrder supervisionOrderThree =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem2.getItem(), groupA).build();
SupervisionOrder supervisionOrderFour =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem2.getItem(), groupB).build();
context.restoreAuthSystemState();
//** WHEN **
//The Admin user browses this endpoint to find the supervisedBy results by the facet
getClient(getAuthToken(admin.getEmail(), password)).perform(get("/api/discover/facets/supervisedBy")
.param("configuration", "supervision"))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//The name has to be 'supervisedBy' as that's the facet that we've called
.andExpect(jsonPath("$.name", is("supervisedBy")))
//The facetType has to be `authority` because that's the default configuration for this facet
.andExpect(jsonPath("$.facetType", equalTo("authority")))
//There always needs to be a self link available
.andExpect(jsonPath("$._links.self.href",
containsString("api/discover/facets/supervisedBy?configuration=supervision")))
//This is how the page object must look like because it's the default with size 20
.andExpect(jsonPath("$.page",
is(PageMatcher.pageEntry(0, 20))))
//The supervisedBy values need to be as specified below
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
entrySupervisedBy(groupA.getName(), groupA.getID().toString(), 2),
entrySupervisedBy(groupB.getName(), groupB.getID().toString(), 2)
)));
}
@Test
public void discoverFacetsSupervisedByWithPrefixTest() throws Exception {
//We turn off the authorization system in order to create the structure defined below
context.turnOffAuthorisationSystem();
//** GIVEN **
//1. A community-collection structure with one parent community and one collection
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection collection =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
//2. Two workspace items
WorkspaceItem wsItem1 =
WorkspaceItemBuilder.createWorkspaceItem(context, collection)
.withTitle("Workspace Item 1")
.withIssueDate("2010-07-23")
.build();
WorkspaceItem wsItem2 =
WorkspaceItemBuilder.createWorkspaceItem(context, collection)
.withTitle("Workspace Item 2")
.withIssueDate("2010-11-03")
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(eperson)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrderOneA =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem1.getItem(), groupA).build();
SupervisionOrder supervisionOrderOneB =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem1.getItem(), groupB).build();
SupervisionOrder supervisionOrderTwoA =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem2.getItem(), groupA).build();
SupervisionOrder supervisionOrderTwoB =
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem2.getItem(), groupB).build();
context.restoreAuthSystemState();
//** WHEN **
//The Admin user browses this endpoint to find the supervisedBy results by the facet
getClient(getAuthToken(admin.getEmail(), password)).perform(get("/api/discover/facets/supervisedBy")
.param("configuration", "supervision")
.param("prefix", "group B"))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//The name has to be 'supervisedBy' as that's the facet that we've called
.andExpect(jsonPath("$.name", is("supervisedBy")))
//The facetType has to be `authority` because that's the default configuration for this facet
.andExpect(jsonPath("$.facetType", equalTo("authority")))
//There always needs to be a self link available
.andExpect(jsonPath("$._links.self.href",
containsString("api/discover/facets/supervisedBy?prefix=group%2520B&configuration=supervision")))
//This is how the page object must look like because it's the default with size 20
.andExpect(jsonPath("$.page",
is(PageMatcher.pageEntry(0, 20))))
//The supervisedBy values need to be as specified below
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
entrySupervisedBy(groupB.getName(), groupB.getID().toString(), 2)
)));
}
@Test
/**
* This test is intent to verify that tasks are only visible to the admin users
*
* @throws Exception
*/
public void discoverSearchObjectsSupervisionConfigurationTest() throws Exception {
//We turn off the authorization system in order to create the structure defined below
context.turnOffAuthorisationSystem();
//** GIVEN **
// 1. Two reviewers and two users and two groups
EPerson reviewer1 =
EPersonBuilder.createEPerson(context)
.withEmail("reviewer1@example.com")
.withPassword(password)
.build();
EPerson reviewer2 =
EPersonBuilder.createEPerson(context)
.withEmail("reviewer2@example.com")
.withPassword(password)
.build();
EPerson userA =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("userA@test.com")
.withPassword(password)
.build();
EPerson userB =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("userB@test.com")
.withPassword(password)
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(userA)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(userB)
.build();
// 2. A community-collection structure with one parent community with sub-community and two collections.
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, child1)
.withName("Collection 1")
.build();
// the second collection has two workflow steps active
Collection col2 = CollectionBuilder.createCollection(context, child1)
.withName("Collection 2")
.withWorkflowGroup(1, admin, reviewer1)
.withWorkflowGroup(2, reviewer2)
.build();
// 2. Three public items that are readable by Anonymous with different subjects
Item publicItem1 = ItemBuilder.createItem(context, col1)
.withTitle("Test")
.withIssueDate("2010-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Testing, Works")
.withSubject("ExtraEntry")
.build();
Item publicItem2 = ItemBuilder.createItem(context, col2)
.withTitle("Test 2")
.withIssueDate("1990-02-13")
.withAuthor("Smith, Maria")
.withAuthor("Doe, Jane")
.withAuthor("Testing, Works")
.withSubject("TestingForMore")
.withSubject("ExtraEntry")
.build();
Item publicItem3 = ItemBuilder.createItem(context, col2)
.withTitle("Public item 2")
.withIssueDate("2010-02-13")
.withAuthor("Smith, Maria")
.withAuthor("Doe, Jane")
.withAuthor("test,test")
.withAuthor("test2, test2")
.withAuthor("Maybe, Maybe")
.withSubject("AnotherTest")
.withSubject("TestingForMore")
.withSubject("ExtraEntry")
.build();
//3. three inprogress submission from a normal user (2 ws, 1 wf that will produce also a pooltask)
context.setCurrentUser(eperson);
WorkspaceItem wsItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withTitle("Workspace Item 1")
.withIssueDate("2010-07-23")
.build();
WorkspaceItem wsItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2)
.withTitle("Workspace Item 2")
.withIssueDate("2010-11-03")
.build();
XmlWorkflowItem wfItem1 = WorkflowItemBuilder.createWorkflowItem(context, col2)
.withTitle("Workflow Item 1")
.withIssueDate("2010-11-03")
.build();
// create Four supervision orders for above items
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem1.getItem(), groupA).build();
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem2.getItem(), groupA).build();
SupervisionOrderBuilder.createSupervisionOrder(context, wfItem1.getItem(), groupA).build();
SupervisionOrderBuilder.createSupervisionOrder(context, wfItem1.getItem(), groupB).build();
// 4. a claimed task from the administrator
ClaimedTask cTask = ClaimedTaskBuilder.createClaimedTask(context, col2, admin).withTitle("Claimed Item")
.withIssueDate("2010-11-03")
.build();
// 5. other inprogress submissions made by the administrator
context.setCurrentUser(admin);
WorkspaceItem wsItem1Admin = WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withIssueDate("2010-07-23")
.withTitle("Admin Workspace Item 1").build();
WorkspaceItem wsItem2Admin = WorkspaceItemBuilder.createWorkspaceItem(context, col2)
.withIssueDate("2010-11-03")
.withTitle("Admin Workspace Item 2").build();
XmlWorkflowItem wfItem1Admin = WorkflowItemBuilder.createWorkflowItem(context, col2)
.withIssueDate("2010-11-03")
.withTitle("Admin Workflow Item 1").build();
// create Four supervision orders for above items
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem1Admin.getItem(), groupA).build();
SupervisionOrderBuilder.createSupervisionOrder(context, wsItem2Admin.getItem(), groupA).build();
SupervisionOrderBuilder.createSupervisionOrder(context, wfItem1Admin.getItem(), groupA).build();
SupervisionOrderBuilder.createSupervisionOrder(context, wfItem1Admin.getItem(), groupB).build();
// 6. a pool taks in the second step of the workflow
ClaimedTask cTask2 = ClaimedTaskBuilder.createClaimedTask(context, col2, admin).withTitle("Pool Step2 Item")
.withIssueDate("2010-11-04")
.build();
String epersonToken = getAuthToken(eperson.getEmail(), password);
String adminToken = getAuthToken(admin.getEmail(), password);
String reviewer1Token = getAuthToken(reviewer1.getEmail(), password);
String reviewer2Token = getAuthToken(reviewer2.getEmail(), password);
getClient(adminToken).perform(post("/api/workflow/claimedtasks/" + cTask2.getID())
.param("submit_approve", "true")
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isNoContent());
context.restoreAuthSystemState();
// summary of the structure, we have:
// a simple collection
// a second collection with 2 workflow steps that have 1 reviewer each (reviewer1 and reviewer2)
// 3 public items
// 2 workspace items submitted by a regular submitter
// 2 workspace items submitted by the admin
// 4 workflow items:
// 1 pool task in step 1, submitted by the same regular submitter
// 1 pool task in step 1, submitted by the admin
// 1 claimed task in the first workflow step from the repository admin
// 1 pool task task in step 2, from the repository admin
// (This one is created by creating a claimed task for step 1 and approving it)
//** WHEN **
// the submitter should not see anything in the workflow configuration
getClient(epersonToken)
.perform(get("/api/discover/search/objects").param("configuration", "supervision"))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//There needs to be a page object that shows the total pages and total elements as well as the
// size and the current page (number)
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 0, 0)
)))
//There always needs to be a self link
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
// reviewer1 should not see pool items, as it is not an administrator
getClient(reviewer1Token)
.perform(get("/api/discover/search/objects").param("configuration", "supervision"))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//There needs to be a page object that shows the total pages and total elements as well as the
// size and the current page (number)
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 0, 0)
)))
//There always needs to be a self link
.andExpect(jsonPath("$._links.self.href",
containsString("/api/discover/search/objects")));
// admin should see seven pool items and a claimed task
// Three pool items from the submitter and Five from the admin
getClient(adminToken)
.perform(get("/api/discover/search/objects").param("configuration", "supervision"))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//There needs to be a page object that shows the total pages and total elements as well as the
// size and the current page (number)
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 8)
)))
// These search results have to be shown in the embedded.objects section:
// three workflow items and one claimed task.
// For step 1 one submitted by the user and one submitted by the admin and one for step 2.
//Seeing as everything fits onto one page, they have to all be present
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder(
Matchers.allOf(
SearchResultMatcher.match("workflow", "workflowitem", "workflowitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkflowItemMatcher.matchItemWithTitleAndDateIssued(
null, "Workflow Item 1", "2010-11-03")))
),
Matchers.allOf(
SearchResultMatcher.match("workflow", "workflowitem", "workflowitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkflowItemMatcher.matchItemWithTitleAndDateIssued(
null, "Admin Workflow Item 1", "2010-11-03")))
),
Matchers.allOf(
SearchResultMatcher.match("workflow", "workflowitem", "workflowitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkflowItemMatcher.matchItemWithTitleAndDateIssued(
null, "Pool Step2 Item", "2010-11-04")))
),
Matchers.allOf(
SearchResultMatcher.match("workflow", "workflowitem", "workflowitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkflowItemMatcher.matchItemWithTitleAndDateIssued(
null, "Claimed Item", "2010-11-03")))
),
Matchers.allOf(
SearchResultMatcher.match("submission", "workspaceitem", "workspaceitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(wsItem1,
"Workspace Item 1", "2010-07-23")))
),
Matchers.allOf(
SearchResultMatcher.match("submission", "workspaceitem", "workspaceitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(wsItem2,
"Workspace Item 2", "2010-11-03")))
),
Matchers.allOf(
SearchResultMatcher.match("submission", "workspaceitem", "workspaceitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(wsItem1Admin,
"Admin Workspace Item 1", "2010-07-23")))
),
Matchers.allOf(
SearchResultMatcher.match("submission", "workspaceitem", "workspaceitems"),
JsonPathMatchers.hasJsonPath("$._embedded.indexableObject",
is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(wsItem2Admin,
"Admin Workspace Item 2", "2010-11-03")))
)
)))
//These facets have to show up in the embedded.facets section as well with the given hasMore
//property because we don't exceed their default limit for a hasMore true (the default is 10)
.andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder(
FacetEntryMatcher.resourceTypeFacet(false),
FacetEntryMatcher.typeFacet(false),
FacetEntryMatcher.dateIssuedFacet(false),
FacetEntryMatcher.submitterFacet(false),
FacetEntryMatcher.supervisedByFacet(false)
)))
//check supervisedBy Facet values
.andExpect(jsonPath("$._embedded.facets[4]._embedded.values",
contains(
entrySupervisedBy(groupA.getName(), groupA.getID().toString(), 6),
entrySupervisedBy(groupB.getName(), groupB.getID().toString(), 2)
)))
//There always needs to be a self link
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
// reviewer2 should not see pool items, as it is not an administrator
getClient(reviewer2Token)
.perform(get("/api/discover/search/objects").param("configuration", "supervision"))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//There needs to be a page object that shows the total pages and total elements as well as the
// size and the current page (number)
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 0, 0)
)))
//There always needs to be a self link
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
}
}

View File

@@ -0,0 +1,932 @@
/**
* 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 com.jayway.jsonpath.JsonPath.read;
import static org.dspace.app.rest.matcher.ItemMatcher.matchItemWithTitleAndDateIssued;
import static org.dspace.app.rest.matcher.SupervisionOrderMatcher.matchSuperVisionOrder;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
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.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.ws.rs.core.MediaType;
import org.dspace.app.rest.model.patch.AddOperation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.repository.SupervisionOrderRestRepository;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.EPersonBuilder;
import org.dspace.builder.GroupBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.SupervisionOrderBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.supervision.SupervisionOrder;
import org.dspace.supervision.service.SupervisionOrderService;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Integration test against class {@link SupervisionOrderRestRepository}.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*/
public class SupervisionOrderRestRepositoryIT extends AbstractControllerIntegrationTest {
@Autowired
private SupervisionOrderService supervisionOrderService;
@Test
public void findAllByAnonymousUserTest() throws Exception {
getClient().perform(get("/api/core/supervisionorders/"))
.andExpect(status().isUnauthorized());
}
@Test
public void findAllByNotAdminUserTest() throws Exception {
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(get("/api/core/supervisionorders/"))
.andExpect(status().isForbidden());
}
@Test
public void findAllByAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group groupA = GroupBuilder.createGroup(context)
.withName("group A")
.addMember(admin)
.build();
Group groupB = GroupBuilder.createGroup(context)
.withName("group B")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrderOne =
SupervisionOrderBuilder.createSupervisionOrder(context, item, groupA)
.build();
SupervisionOrder supervisionOrderTwo =
SupervisionOrderBuilder.createSupervisionOrder(context, item, groupB)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(get("/api/core/supervisionorders/"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.page.totalElements", is(2)))
.andExpect(jsonPath("$._embedded.supervisionorders",
containsInAnyOrder(
matchSuperVisionOrder(supervisionOrderOne),
matchSuperVisionOrder(supervisionOrderTwo)
)))
.andExpect(jsonPath("$._links.self.href", containsString("/api/core/supervisionorders")));
}
@Test
public void findOneByAnonymousUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
getClient().perform(get("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isUnauthorized());
}
@Test
public void findOneByNotAdminUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(get("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isForbidden());
}
@Test
public void findOneByAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(get("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$", matchSuperVisionOrder(supervisionOrder)));
}
@Test
public void findOneByAdminAndItemIsWithdrawnTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
String patchBody = getPatchContent(List.of(new ReplaceOperation("/withdrawn", true)));
String adminToken = getAuthToken(admin.getEmail(), password);
// withdraw item
getClient(adminToken).perform(patch("/api/core/items/" + item.getID())
.content(patchBody)
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString())))
.andExpect(jsonPath("$.withdrawn", Matchers.is(true)))
.andExpect(jsonPath("$.inArchive", Matchers.is(false)));
getClient(adminToken).perform(get("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$", matchSuperVisionOrder(context.reloadEntity(supervisionOrder))));
}
@Test
public void findOneByAdminButNotFoundTest() throws Exception {
int fakeId = 12354326;
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(get("/api/core/supervisionorders/" + fakeId))
.andExpect(status().isNotFound());
}
@Test
public void findByItemByAnonymousUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrderBuilder.createSupervisionOrder(context, item, group).build();
context.restoreAuthSystemState();
getClient().perform(get("/api/core/supervisionorders/search/byItem")
.param("uuid", item.getID().toString()))
.andExpect(status().isUnauthorized());
}
@Test
public void findByItemByNotAdminUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrderBuilder.createSupervisionOrder(context, item, group).build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(get("/api/core/supervisionorders/search/byItem")
.param("uuid", item.getID().toString()))
.andExpect(status().isForbidden());
}
@Test
public void findByItemByAdminButNotFoundItemTest() throws Exception {
String fakeItemId = "d9dcf4c3-093d-413e-a538-93d8589d3ea6";
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(get("/api/core/supervisionorders/search/byItem")
.param("uuid", fakeItemId))
.andExpect(status().isNotFound());
}
@Test
public void findByItemByAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item itemOne =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(admin)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrderOne =
SupervisionOrderBuilder.createSupervisionOrder(context, itemOne, groupA)
.build();
SupervisionOrder supervisionOrderTwo =
SupervisionOrderBuilder.createSupervisionOrder(context, itemOne, groupB)
.build();
Item itemTwo =
ItemBuilder.createItem(context, col1)
.withTitle("item two title")
.build();
SupervisionOrder supervisionOrderItemTwo =
SupervisionOrderBuilder.createSupervisionOrder(context, itemTwo, groupA)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(get("/api/core/supervisionorders/search/byItem")
.param("uuid", itemOne.getID().toString()))
.andExpect(jsonPath("$.page.totalElements", is(2)))
.andExpect(jsonPath("$._embedded.supervisionorders", containsInAnyOrder(
matchSuperVisionOrder(supervisionOrderOne),
matchSuperVisionOrder(supervisionOrderTwo)
)))
.andExpect(jsonPath("$._links.self.href", containsString(
"/api/core/supervisionorders/search/byItem?uuid=" + itemOne.getID()))
);
getClient(adminToken).perform(get("/api/core/supervisionorders/search/byItem")
.param("uuid", itemTwo.getID().toString()))
.andExpect(jsonPath("$.page.totalElements", is(1)))
.andExpect(jsonPath("$._embedded.supervisionorders", contains(
matchSuperVisionOrder(supervisionOrderItemTwo)
)))
.andExpect(jsonPath("$._links.self.href", containsString(
"/api/core/supervisionorders/search/byItem?uuid=" + itemTwo.getID()))
);
}
@Test
public void createByAnonymousUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
context.restoreAuthSystemState();
getClient().perform(post("/api/core/supervisionorders/")
.param("uuid", item.getID().toString())
.param("group", group.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isUnauthorized());
}
@Test
public void createByNotAdminUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(post("/api/core/supervisionorders/")
.param("uuid", item.getID().toString())
.param("group", group.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isForbidden());
}
@Test
public void createByAdminButMissingParametersTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item itemOne =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(eperson)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("group", groupA.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isBadRequest());
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isBadRequest());
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("group", groupA.getID().toString())
.contentType(contentType))
.andExpect(status().isBadRequest());
}
@Test
public void createByAdminButIncorrectTypeParameterTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", item.getID().toString())
.param("group", group.getID().toString())
.param("type", "WRONG")
.contentType(contentType))
.andExpect(status().isBadRequest());
}
@Test
public void createByAdminButNotFoundItemOrGroupTest() throws Exception {
String fakeItemId = "d9dcf4c3-093d-413e-a538-93d8589d3ea6";
String fakeGroupId = "d9dcf4c3-093d-413e-a538-93d8589d3ea6";
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item itemOne =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group groupA = GroupBuilder.createGroup(context)
.withName("group A")
.addMember(eperson)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", fakeItemId)
.param("group", groupA.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isUnprocessableEntity());
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("group", fakeGroupId)
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void createTheSameSupervisionOrderTwiceTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item itemOne =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.withIssueDate("2017-10-17")
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(eperson)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("group", groupA.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isCreated());
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("group", groupA.getID().toString())
.param("type", "OBSERVER")
.contentType(contentType))
.andExpect(status().isConflict());
}
@Test
public void createByAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson userA =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("test1@email.com")
.withPassword(password)
.build();
EPerson userB =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("test2@email.com")
.withPassword(password)
.build();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item itemOne =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.withIssueDate("2017-10-17")
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(userA)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(userB)
.build();
context.restoreAuthSystemState();
AtomicInteger supervisionOrderIdOne = new AtomicInteger();
AtomicInteger supervisionOrderIdTwo = new AtomicInteger();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("group", groupA.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isCreated())
.andDo(result -> supervisionOrderIdOne
.set(read(result.getResponse().getContentAsString(), "$.id")));
getClient(adminToken).perform(post("/api/core/supervisionorders/")
.param("uuid", itemOne.getID().toString())
.param("group", groupB.getID().toString())
.param("type", "OBSERVER")
.contentType(contentType))
.andExpect(status().isCreated())
.andDo(result -> supervisionOrderIdTwo
.set(read(result.getResponse().getContentAsString(), "$.id")));
SupervisionOrder supervisionOrderOne =
supervisionOrderService.find(context, supervisionOrderIdOne.get());
SupervisionOrder supervisionOrderTwo =
supervisionOrderService.find(context, supervisionOrderIdTwo.get());
getClient(adminToken).perform(get("/api/core/supervisionorders/" + supervisionOrderOne.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$",
matchSuperVisionOrder(context.reloadEntity(supervisionOrderOne))));
getClient(adminToken).perform(get("/api/core/supervisionorders/" + supervisionOrderTwo.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$",
matchSuperVisionOrder(context.reloadEntity(supervisionOrderTwo))));
String authTokenA = getAuthToken(userA.getEmail(), password);
String authTokenB = getAuthToken(userB.getEmail(), password);
String patchBody = getPatchContent(List.of(
new AddOperation("/metadata/dc.title", List.of(Map.of("value", "new title")))
));
// update title of itemOne by userA is Ok
getClient(authTokenA).perform(patch("/api/core/items/" + itemOne.getID())
.content(patchBody)
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", is(
matchItemWithTitleAndDateIssued(context.reloadEntity(itemOne),
"new title", "2017-10-17")
)));
// update title of itemOne by userB is Forbidden
getClient(authTokenB).perform(patch("/api/core/items/" + itemOne.getID())
.content(patchBody)
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isForbidden());
}
@Test
public void deleteByAnonymousUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
getClient().perform(delete("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isUnauthorized());
}
@Test
public void deleteByNotAdminUserTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(delete("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isForbidden());
}
@Test
public void deleteByAdminButNotFoundTest() throws Exception {
int fakeId = 12354326;
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(delete("/api/core/supervisionorders/" + fakeId))
.andExpect(status().isNotFound());
}
@Test
public void deleteByAdminTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
Item item =
ItemBuilder.createItem(context, col1)
.withTitle("item title")
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrder =
SupervisionOrderBuilder.createSupervisionOrder(context, item, group)
.build();
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken).perform(get("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isOk());
getClient(adminToken).perform(delete("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isNoContent());
getClient(adminToken).perform(get("/api/core/supervisionorders/" + supervisionOrder.getID()))
.andExpect(status().isNotFound());
}
}

View File

@@ -46,6 +46,7 @@ import org.dspace.builder.ClaimedTaskBuilder;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.EPersonBuilder;
import org.dspace.builder.GroupBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.WorkflowItemBuilder;
import org.dspace.builder.WorkspaceItemBuilder;
@@ -55,6 +56,7 @@ import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.WorkspaceItem;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.services.ConfigurationService;
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
import org.dspace.xmlworkflow.state.Step;
@@ -2123,4 +2125,71 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
}
}
@Test
public void testSupervisorFindOne() throws Exception {
context.turnOffAuthorisationSystem();
EPerson user =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("user@test.com")
.withPassword(password)
.build();
EPerson anotherUser =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("anotheruser@test.com")
.withPassword(password)
.build();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Community child1 =
CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
Collection collection =
CollectionBuilder.createCollection(context, child1)
.withName("Collection 1")
.withWorkflowGroup(1, admin)
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(user)
.build();
XmlWorkflowItem workflowItem =
WorkflowItemBuilder.createWorkflowItem(context, collection)
.withSubmitter(admin)
.withTitle("Workflow Item")
.withIssueDate("2017-10-17")
.withAuthor("Author one")
.build();
context.restoreAuthSystemState();
getClient(getAuthToken(admin.getEmail(), password))
.perform(post("/api/core/supervisionorders/")
.param("uuid", workflowItem.getItem().getID().toString())
.param("group", group.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isCreated());
getClient(getAuthToken(anotherUser.getEmail(), password))
.perform(get("/api/workflow/workflowitems/" + workflowItem.getID()))
.andExpect(status().isForbidden());
getClient(getAuthToken(user.getEmail(), password))
.perform(get("/api/workflow/workflowitems/" + workflowItem.getID()))
.andExpect(status().isOk());
}
}

View File

@@ -11,9 +11,12 @@ import static com.jayway.jsonpath.JsonPath.read;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataDoesNotExist;
import static org.dspace.app.rest.matcher.SupervisionOrderMatcher.matchSuperVisionOrder;
import static org.dspace.authorize.ResourcePolicy.TYPE_CUSTOM;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
@@ -70,6 +73,7 @@ import org.dspace.builder.ItemBuilder;
import org.dspace.builder.RelationshipBuilder;
import org.dspace.builder.RelationshipTypeBuilder;
import org.dspace.builder.ResourcePolicyBuilder;
import org.dspace.builder.SupervisionOrderBuilder;
import org.dspace.builder.WorkspaceItemBuilder;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
@@ -89,6 +93,7 @@ import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
import org.dspace.services.ConfigurationService;
import org.dspace.supervision.SupervisionOrder;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
@@ -8291,4 +8296,274 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
assertTrue(date.equals(date2));
}
@Test
public void supervisionOrdersLinksTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
WorkspaceItem witem =
WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withTitle("Workspace Item 1")
.withIssueDate("2022-12-12")
.withAuthor("Eskander, Mohamed")
.withSubject("ExtraEntry")
.grantLicense()
.build();
Group group =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(admin)
.build();
SupervisionOrder supervisionOrderOne = SupervisionOrderBuilder
.createSupervisionOrder(context, witem.getItem(), group)
.build();
//disable file upload mandatory
configurationService.setProperty("webui.submit.upload.required", false);
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
getClient(adminToken)
.perform(get("/api/submission/workspaceitems/" + witem.getID())).andExpect(status().isOk())
.andExpect(jsonPath("$",
Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem,
"Workspace Item 1", "2022-12-12", "ExtraEntry"))))
.andExpect(jsonPath("$._links.supervisionOrders.href", containsString(
"/api/submission/workspaceitems/" + witem.getID() + "/supervisionOrders")
));
}
@Test
public void supervisionOrdersEndpointTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
WorkspaceItem witemOne =
WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withTitle("Test item -- supervision orders")
.withIssueDate("2022-12-12")
.withAuthor("Eskander, Mohamed")
.grantLicense()
.build();
WorkspaceItem witemTwo =
WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withTitle("Test item -- no supervision orders")
.withIssueDate("2022-12-12")
.withAuthor("Eskander")
.grantLicense()
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(admin)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(eperson)
.build();
SupervisionOrder supervisionOrderOne = SupervisionOrderBuilder
.createSupervisionOrder(context, witemOne.getItem(), groupA)
.build();
SupervisionOrder supervisionOrderTwo = SupervisionOrderBuilder
.createSupervisionOrder(context, witemOne.getItem(), groupB)
.build();
//disable file upload mandatory
configurationService.setProperty("webui.submit.upload.required", false);
context.restoreAuthSystemState();
String adminToken = getAuthToken(admin.getEmail(), password);
String authToken = getAuthToken(eperson.getEmail(), password);
// Item's supervision orders endpoint of itemOne by not admin
getClient(authToken)
.perform(get("/api/submission/workspaceitems/" + witemOne.getID() + "/supervisionOrders"))
.andExpect(status().isForbidden());
// Item's supervision orders endpoint of itemOne by admin
getClient(adminToken)
.perform(get("/api/submission/workspaceitems/" + witemOne.getID() + "/supervisionOrders"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.page.totalElements", is(2)))
.andExpect(jsonPath("$._embedded.supervisionOrders", containsInAnyOrder(
matchSuperVisionOrder(supervisionOrderOne),
matchSuperVisionOrder(supervisionOrderTwo)
)))
.andExpect(jsonPath("$._links.self.href", containsString(
"/api/submission/workspaceitems/" + witemOne.getID() + "/supervisionOrders")
));
// Item's supervision orders endpoint of itemTwo by admin
getClient(adminToken)
.perform(get("/api/submission/workspaceitems/" + witemTwo.getID() + "/supervisionOrders"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.page.totalElements", is(0)))
.andExpect(jsonPath("$._embedded.supervisionOrders", empty()))
.andExpect(jsonPath("$._links.self.href", containsString(
"/api/submission/workspaceitems/" + witemTwo.getID() + "/supervisionOrders")
));
}
@Test
public void patchBySupervisorTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson userA =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("userA@test.com")
.withPassword(password)
.build();
EPerson userB =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("userB@test.com")
.withPassword(password)
.build();
EPerson userC =
EPersonBuilder.createEPerson(context)
.withCanLogin(true)
.withEmail("userC@test.com")
.withPassword(password)
.build();
parentCommunity =
CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection publications =
CollectionBuilder.createCollection(context, parentCommunity)
.withName("Publications")
.withEntityType("Publication")
.build();
Group groupA =
GroupBuilder.createGroup(context)
.withName("group A")
.addMember(userA)
.build();
Group groupB =
GroupBuilder.createGroup(context)
.withName("group B")
.addMember(userB)
.build();
WorkspaceItem witem =
WorkspaceItemBuilder.createWorkspaceItem(context, publications)
.withTitle("Workspace Item 1")
.withIssueDate("2017-10-17")
.withSubject("ExtraEntry")
.grantLicense()
.build();
//disable file upload mandatory
configurationService.setProperty("webui.submit.upload.required", false);
context.restoreAuthSystemState();
getClient(getAuthToken(admin.getEmail(), password))
.perform(post("/api/core/supervisionorders/")
.param("uuid", witem.getItem().getID().toString())
.param("group", groupA.getID().toString())
.param("type", "EDITOR")
.contentType(contentType))
.andExpect(status().isCreated());
getClient(getAuthToken(admin.getEmail(), password))
.perform(post("/api/core/supervisionorders/")
.param("uuid", witem.getItem().getID().toString())
.param("group", groupB.getID().toString())
.param("type", "OBSERVER")
.contentType(contentType))
.andExpect(status().isCreated());
String authTokenA = getAuthToken(userA.getEmail(), password);
String authTokenB = getAuthToken(userB.getEmail(), password);
String authTokenC = getAuthToken(userC.getEmail(), password);
getClient(authTokenC).perform(get("/api/submission/workspaceitems/" + witem.getID()))
.andExpect(status().isForbidden());
// a simple patch to update an existent metadata
List<Operation> updateTitle = new ArrayList<>();
Map<String, String> value = new HashMap<>();
value.put("value", "New Title");
updateTitle.add(new ReplaceOperation("/sections/traditionalpageone/dc.title/0", value));
String patchBody = getPatchContent(updateTitle);
getClient(authTokenB).perform(patch("/api/submission/workspaceitems/" + witem.getID())
.content(patchBody)
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isForbidden());
getClient(authTokenA).perform(patch("/api/submission/workspaceitems/" + witem.getID())
.content(patchBody)
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.errors").doesNotExist())
.andExpect(jsonPath("$",
// check the new title and untouched values
Matchers.is(WorkspaceItemMatcher
.matchItemWithTitleAndDateIssuedAndSubject(
witem,
"New Title", "2017-10-17",
"ExtraEntry"))));
getClient(authTokenA).perform(get("/api/submission/workspaceitems/" + witem.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.errors").doesNotExist())
.andExpect(jsonPath("$",
Matchers.is(
WorkspaceItemMatcher
.matchItemWithTitleAndDateIssuedAndSubject(
witem,
"New Title", "2017-10-17",
"ExtraEntry")
)));
getClient(authTokenB).perform(get("/api/submission/workspaceitems/" + witem.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.errors").doesNotExist())
.andExpect(jsonPath("$",
Matchers.is(
WorkspaceItemMatcher
.matchItemWithTitleAndDateIssuedAndSubject(
witem,
"New Title", "2017-10-17",
"ExtraEntry")
)));
}
}

View File

@@ -67,6 +67,17 @@ public class FacetEntryMatcher {
);
}
public static Matcher<? super Object> supervisedByFacet(boolean hasNext) {
return allOf(
hasJsonPath("$.name", is("supervisedBy")),
hasJsonPath("$.facetType", is("authority")),
hasJsonPath("$.facetLimit", any(Integer.class)),
hasJsonPath("$._links.self.href", containsString("api/discover/facets/supervisedBy")),
hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/supervisedBy"))
);
}
public static Matcher<? super Object> dateIssuedFacet(boolean hasNext) {
return allOf(
hasJsonPath("$.name", is("dateIssued")),

View File

@@ -97,4 +97,16 @@ public class FacetValueMatcher {
hasJsonPath("$._links.search.href", containsString(",equals"))
);
}
public static Matcher<? super Object> entrySupervisedBy(String label, String authority, int count) {
return allOf(
hasJsonPath("$.authorityKey", is(authority)),
hasJsonPath("$.count", is(count)),
hasJsonPath("$.label", is(label)),
hasJsonPath("$.type", is("discover")),
hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")),
hasJsonPath("$._links.search.href", containsString("f.supervisedBy=" + authority + ",authority"))
);
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.matcher;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.dspace.app.rest.matcher.GroupMatcher.matchGroupEntry;
import static org.dspace.app.rest.matcher.ItemMatcher.matchItemProperties;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
import org.dspace.eperson.Group;
import org.dspace.supervision.SupervisionOrder;
import org.hamcrest.Matcher;
/**
* Utility class to construct a Matcher for an SupervisionOrder object
*
* @author Mohamed Eskander (mohamed.eskander at 4science dot it)
*/
public class SupervisionOrderMatcher {
private SupervisionOrderMatcher() {
}
public static Matcher<? super Object> matchSuperVisionOrder(SupervisionOrder supervisionOrder) {
Group group = supervisionOrder.getGroup();
return allOf(
hasJsonPath("$.id", is(supervisionOrder.getID())),
hasJsonPath("$._embedded.item", matchItemProperties(supervisionOrder.getItem())),
hasJsonPath("$._embedded.group", matchGroupEntry(group.getID(), group.getName()))
);
}
}

View File

@@ -93,5 +93,7 @@
<mapping class="org.dspace.orcid.OrcidHistory" />
<mapping class="org.dspace.orcid.OrcidToken"/>
<mapping class="org.dspace.supervision.SupervisionOrder"/>
</session-factory>
</hibernate-configuration>

View File

@@ -64,5 +64,7 @@
<bean class="org.dspace.orcid.dao.impl.OrcidQueueDAOImpl" />
<bean class="org.dspace.orcid.dao.impl.OrcidHistoryDAOImpl" />
<bean class="org.dspace.supervision.dao.impl.SupervisionOrderDaoImpl"/>
</beans>

View File

@@ -55,4 +55,6 @@
<bean id="orcidServiceFactory" class="org.dspace.orcid.factory.OrcidServiceFactoryImpl"/>
<bean id="supervisionOrderServiceFactory" class="org.dspace.supervision.factory.SupervisionOrderServiceFactoryImpl"/>
</beans>

View File

@@ -148,5 +148,7 @@
<bean class="org.dspace.authorize.ValidatePasswordServiceImpl"/>
<bean class="org.dspace.authorize.RegexPasswordValidator" />
<bean class="org.dspace.supervision.SupervisionOrderServiceImpl"/>
</beans>

View File

@@ -40,6 +40,9 @@
<!-- Additional indexing plugin enables searching by filenames and by file descriptions for files in ORIGINAL bundle -->
<bean id="solrServiceFileInfoPlugin" class="org.dspace.discovery.SolrServiceFileInfoPlugin"/>
<!-- Additional indexing plugin enables searching by supervised (true,false) -->
<bean id="solrServiceSupervisionOrderIndexingPlugin" class="org.dspace.discovery.SolrServiceSupervisionOrderIndexingPlugin"/>
<!--Bean that is used for mapping communities/collections to certain discovery configurations.-->
<bean id="org.dspace.discovery.configuration.DiscoveryConfigurationService" class="org.dspace.discovery.configuration.DiscoveryConfigurationService">
<property name="map">
@@ -61,10 +64,14 @@
<!-- Do not change the id of special entries or else they won't work -->
<!-- "workspace" is a special entry to search for your own workspace items -->
<entry key="workspace" value-ref="workspaceConfiguration" />
<entry key="otherworkspace" value-ref="otherWorkspaceConfiguration" />
<!-- "workflow" is a special entry to search for your own workflow tasks -->
<entry key="workflow" value-ref="workflowConfiguration" />
<!-- "workflowAdmin" is a special entry to search for all workflow items if you are an administrator -->
<entry key="workflowAdmin" value-ref="workflowAdminConfiguration" />
<!-- "supervision" is a special entry to search for all workspace and workflow items if you are an administrator -->
<entry key="supervision" value-ref="supervisionConfiguration" />
<entry key="undiscoverable" value-ref="unDiscoverableItems" />
<entry key="administrativeView" value-ref="administrativeView" />
@@ -894,6 +901,81 @@
<property name="spellCheckEnabled" value="true"/>
</bean>
<!--The other workspace configuration settings for discovery -->
<bean id="otherWorkspaceConfiguration"
class="org.dspace.discovery.configuration.DiscoveryConfiguration"
scope="prototype">
<property name="id" value="otherworkspace" />
<!--Which sidebar facets are to be displayed -->
<property name="sidebarFacets">
<list>
<ref bean="searchFilterObjectNamedType" />
<ref bean="searchFilterType" />
<ref bean="searchFilterIssued" />
<ref bean="searchFilterSupervision" />
</list>
</property>
<!--The search filters which can be used on the discovery search page -->
<property name="searchFilters">
<list>
<ref bean="searchFilterObjectNamedType" />
<ref bean="searchFilterType" />
<ref bean="searchFilterIssued" />
<ref bean="searchFilterSupervision" />
</list>
</property>
<!--The sort filters for the discovery search-->
<property name="searchSortConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoverySortConfiguration">
<property name="sortFields">
<list>
<ref bean="sortLastModified" />
<ref bean="sortTitleAsc" />
<ref bean="sortDateIssuedDesc" />
</list>
</property>
</bean>
</property>
<!--Any default filter queries, these filter queries will be used for all
queries done by discovery for this configuration -->
<property name="defaultFilterQueries">
<list>
<!--Only find items, workspace and accepted for workflow -->
<value>search.resourcetype:WorkspaceItem</value>
</list>
</property>
<!--Default result per page -->
<property name="defaultRpp" value="10" />
<property name="hitHighlightingConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration">
<property name="metadataFields">
<list>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.title"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.contributor.author"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.description.abstract"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="fulltext"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
</list>
</property>
</bean>
</property>
<!-- When true a "did you mean" example will be displayed, value can be true or false -->
<property name="spellCheckEnabled" value="true"/>
</bean>
<!--The workflow configuration settings for discovery -->
<bean id="workflowConfiguration"
class="org.dspace.discovery.configuration.DiscoveryConfiguration"
@@ -1043,6 +1125,81 @@
<property name="spellCheckEnabled" value="true"/>
</bean>
<bean id="supervisionConfiguration"
class="org.dspace.discovery.configuration.DiscoveryConfiguration"
scope="prototype">
<property name="id" value="supervision" />
<!--Which sidebar facets are to be displayed -->
<property name="sidebarFacets">
<list>
<ref bean="searchFilterObjectNamedType" />
<ref bean="searchFilterType" />
<ref bean="searchFilterIssued" />
<ref bean="searchFilterSubmitter" />
<ref bean="searchFilterSupervision" />
</list>
</property>
<!--The search filters which can be used on the discovery search page -->
<property name="searchFilters">
<list>
<ref bean="searchFilterObjectNamedType" />
<ref bean="searchFilterType" />
<ref bean="searchFilterIssued" />
<ref bean="searchFilterSubmitter" />
<ref bean="searchFilterSupervision" />
</list>
</property>
<!--The sort filters for the discovery search-->
<property name="searchSortConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoverySortConfiguration">
<property name="sortFields">
<list>
<ref bean="sortScore" />
<ref bean="sortTitle" />
<ref bean="sortDateIssued" />
</list>
</property>
</bean>
</property>
<!--Any default filter queries, these filter queries will be used for all
queries done by discovery for this configuration -->
<property name="defaultFilterQueries">
<list>
<value>search.resourcetype:WorkspaceItem OR search.resourcetype:XmlWorkflowItem</value>
</list>
</property>
<!--Default result per page -->
<property name="defaultRpp" value="10" />
<property name="hitHighlightingConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration">
<property name="metadataFields">
<list>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.title"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.contributor.author"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.description.abstract"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="fulltext"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
</list>
</property>
</bean>
</property>
<!-- When true a "did you mean" example will be displayed, value can be true or false -->
<property name="spellCheckEnabled" value="true"/>
</bean>
<bean id="publication" class="org.dspace.discovery.configuration.DiscoveryConfiguration" scope="prototype">
<property name="id" value="publication"/>
<property name="indexAlways" value="true"/>
@@ -2792,6 +2949,18 @@
<property name="pageSize" value="10"/>
</bean>
<!-- Used only to READ "supervisedBy" facets -->
<bean id="searchFilterSupervision"
class="org.dspace.discovery.configuration.DiscoverySearchFilterFacet">
<property name="indexFieldName" value="supervisedBy" />
<property name="type" value="authority" />
<property name="metadataFields">
<list>
<value>placeholder.placeholder.placeholder</value>
</list>
</property>
</bean>
<!--Sort properties-->
<bean id="sortScore" class="org.dspace.discovery.configuration.DiscoverySortFieldConfiguration">
<property name="defaultSortOrder" value="desc"/>
@@ -2866,4 +3035,21 @@
<property name="defaultSortOrder" value="desc"/>
</bean>
<bean id="sortLastModified" class="org.dspace.discovery.configuration.DiscoverySortFieldConfiguration">
<property name="metadataField" value="lastModified" />
<property name="type" value="date" />
<property name="defaultSortOrder" value="desc"/>
</bean>
<bean id="sortTitleAsc" class="org.dspace.discovery.configuration.DiscoverySortFieldConfiguration">
<property name="metadataField" value="dc.title"/>
<property name="defaultSortOrder" value="asc"/>
</bean>
<bean id="sortDateIssuedDesc" class="org.dspace.discovery.configuration.DiscoverySortFieldConfiguration">
<property name="metadataField" value="dc.date.issued"/>
<property name="type" value="date"/>
<property name="defaultSortOrder" value="desc"/>
</bean>
</beans>