mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge remote-tracking branch 'dspace/master' into w2p-68732_list-version-history
Conflicts: dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java
This commit is contained in:
@@ -44,15 +44,16 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
|
||||
with @SuppressWarnings. See also SuppressWarningsHolder below -->
|
||||
<module name="SuppressWarningsFilter" />
|
||||
|
||||
<!-- Maximum line length is 120 characters -->
|
||||
<module name="LineLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="max" value="120"/>
|
||||
<!-- Only exceptions for packages, imports, URLs, and JavaDoc {@link} tags -->
|
||||
<property name="ignorePattern" value="^package.*|^import.*|http://|https://|@link"/>
|
||||
</module>
|
||||
|
||||
<!-- Check individual Java source files for specific rules -->
|
||||
<module name="TreeWalker">
|
||||
<!-- Maximum line length is 120 characters -->
|
||||
<module name="LineLength">
|
||||
<property name="max" value="120"/>
|
||||
<!-- Only exceptions for packages, imports, URLs, and JavaDoc {@link} tags -->
|
||||
<property name="ignorePattern" value="^package.*|^import.*|http://|https://|@link"/>
|
||||
</module>
|
||||
|
||||
<!-- Highlight any TODO or FIXME comments in info messages -->
|
||||
<module name="TodoComment">
|
||||
<property name="severity" value="info"/>
|
||||
@@ -94,11 +95,8 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
|
||||
<!-- <property name="scope" value="public"/> -->
|
||||
<!-- TODO: Above rule has been disabled because of large amount of missing public method Javadocs -->
|
||||
<property name="scope" value="nothing"/>
|
||||
<!-- Allow RuntimeExceptions to be undeclared -->
|
||||
<property name="allowUndeclaredRTE" value="true"/>
|
||||
<!-- Allow params, throws and return tags to be optional -->
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingThrowsTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
</module>
|
||||
|
||||
|
@@ -20,7 +20,6 @@ import com.sun.syndication.feed.module.opensearch.OpenSearchModule;
|
||||
import com.sun.syndication.feed.module.opensearch.entity.OSQuery;
|
||||
import com.sun.syndication.feed.module.opensearch.impl.OpenSearchModuleImpl;
|
||||
import com.sun.syndication.io.FeedException;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.service.OpenSearchService;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
|
@@ -8,10 +8,8 @@
|
||||
package org.dspace.authorize.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
|
@@ -11,7 +11,6 @@ import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
|
@@ -13,7 +13,6 @@ import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
@@ -12,7 +12,6 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
|
@@ -11,7 +11,6 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
@@ -271,4 +270,4 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport
|
||||
return communityService;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
|
@@ -13,7 +13,6 @@ import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.content;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.content.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
@@ -21,7 +20,7 @@ import org.dspace.scripts.Process;
|
||||
import org.dspace.scripts.Process_;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Implementation class for {@link ProcessDAO}
|
||||
*/
|
||||
public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements ProcessDAO {
|
||||
|
@@ -13,7 +13,6 @@ import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
@@ -46,7 +45,7 @@ public interface BitstreamService extends DSpaceObjectService<Bitstream>, DSpace
|
||||
* checksum algorithm as same as the given bitstream.
|
||||
* This allows multiple bitstreams to share the same internal identifier of assets .
|
||||
* An example of such a use case scenario is versioning.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context object
|
||||
* @param bitstream
|
||||
|
@@ -21,7 +21,6 @@ import net.handle.hdllib.HandleStorage;
|
||||
import net.handle.hdllib.HandleValue;
|
||||
import net.handle.hdllib.ScanCallback;
|
||||
import net.handle.hdllib.Util;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.handle.factory.HandleServiceFactory;
|
||||
|
@@ -15,7 +15,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
|
@@ -18,7 +18,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -309,7 +308,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService {
|
||||
@Override
|
||||
public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId,
|
||||
Workflow workflow, WorkflowActionConfig currentActionConfig)
|
||||
throws SQLException, AuthorizeException, IOException, MessagingException, WorkflowException {
|
||||
throws SQLException, AuthorizeException, IOException, WorkflowException {
|
||||
try {
|
||||
XmlWorkflowItem wi = xmlWorkflowItemService.find(c, workflowItemId);
|
||||
Step currentStep = currentActionConfig.getStep();
|
||||
|
@@ -50,6 +50,20 @@ public abstract class Action {
|
||||
*/
|
||||
public abstract List<String> getOptions();
|
||||
|
||||
/**
|
||||
* Returns true if one of the options is a parameter of the request
|
||||
* @param request Action request
|
||||
* @return true if one of the options is a parameter of the request; false if none was found
|
||||
*/
|
||||
protected boolean isOptionInParam(HttpServletRequest request) {
|
||||
for (String option: this.getOptions()) {
|
||||
if (request.getParameter(option) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public WorkflowActionConfig getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
@@ -46,12 +47,14 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
|
||||
if (request.getParameter(SUBMIT_APPROVE) != null) {
|
||||
return processAccept(c, wfi);
|
||||
} else {
|
||||
if (request.getParameter(SUBMIT_REJECT) != null) {
|
||||
return processRejectPage(c, wfi, request);
|
||||
if (super.isOptionInParam(request)) {
|
||||
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||
case SUBMIT_APPROVE:
|
||||
return processAccept(c, wfi);
|
||||
case SUBMIT_REJECT:
|
||||
return processRejectPage(c, wfi, request);
|
||||
default:
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
}
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
|
@@ -12,6 +12,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
@@ -42,20 +43,23 @@ public class FinalEditAction extends ProcessingAction {
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
return processMainPage(c, wfi, step, request);
|
||||
return processMainPage(c, wfi, request);
|
||||
}
|
||||
|
||||
public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
if (request.getParameter(SUBMIT_APPROVE) != null) {
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
} else {
|
||||
//We pressed the leave button so return to our submissions page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
if (super.isOptionInParam(request)) {
|
||||
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||
case SUBMIT_APPROVE:
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
default:
|
||||
//We pressed the leave button so return to our submissions page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
}
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -34,7 +34,8 @@ public abstract class ProcessingAction extends Action {
|
||||
@Autowired(required = true)
|
||||
protected ItemService itemService;
|
||||
|
||||
protected static final String SUBMIT_EDIT_METADATA = "submit_edit_metadata";
|
||||
public static final String SUBMIT_EDIT_METADATA = "submit_edit_metadata";
|
||||
public static final String SUBMIT_CANCEL = "submit_cancel";
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException {
|
||||
|
@@ -11,9 +11,9 @@ import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
@@ -47,14 +47,16 @@ public class ReviewAction extends ProcessingAction {
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
if (request.getParameter(SUBMIT_APPROVE) != null) {
|
||||
return processAccept(c, wfi, step, request);
|
||||
} else {
|
||||
if (request.getParameter(SUBMIT_REJECT) != null) {
|
||||
return processRejectPage(c, wfi, step, request);
|
||||
if (super.isOptionInParam(request)) {
|
||||
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||
case SUBMIT_APPROVE:
|
||||
return processAccept(c, wfi);
|
||||
case SUBMIT_REJECT:
|
||||
return processRejectPage(c, wfi, step, request);
|
||||
default:
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
|
||||
@@ -66,11 +68,9 @@ public class ReviewAction extends ProcessingAction {
|
||||
return options;
|
||||
}
|
||||
|
||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
}
|
||||
|
||||
@@ -80,14 +80,14 @@ public class ReviewAction extends ProcessingAction {
|
||||
|
||||
// Get user's name + email address
|
||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.getEPersonName(c.getCurrentUser());
|
||||
.getEPersonName(c.getCurrentUser());
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
||||
+ usersName + " on " + now + " (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||
provDescription);
|
||||
provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ public class ReviewAction extends ProcessingAction {
|
||||
|
||||
//We have pressed reject, so remove the task the user has & put it back to a workspace item
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
||||
this.getProvenanceStartId(), reason);
|
||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
||||
this.getProvenanceStartId(), reason);
|
||||
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
|
@@ -9,7 +9,6 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
|
@@ -13,7 +13,6 @@ import static org.junit.Assert.fail;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import org.dspace.AbstractUnitTest;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Collection;
|
||||
@@ -24,7 +23,6 @@ import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||
import org.dspace.xmlworkflow.state.Workflow;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@@ -22,7 +22,6 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
import com.lyncode.xoai.dataprovider.exceptions.ConfigurationException;
|
||||
|
@@ -9,7 +9,6 @@ package org.dspace.xoai.services.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.app.rest;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
|
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* 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 java.util.regex.Pattern.compile;
|
||||
import static org.apache.http.HttpStatus.SC_NO_CONTENT;
|
||||
import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY;
|
||||
import static org.dspace.app.rest.utils.ContextUtil.obtainContext;
|
||||
import static org.dspace.app.rest.utils.RegexUtils.REGEX_UUID;
|
||||
import static org.dspace.app.util.AuthorizeUtil.authorizeManageAdminGroup;
|
||||
import static org.dspace.app.util.AuthorizeUtil.authorizeManageSubmittersGroup;
|
||||
import static org.dspace.app.util.AuthorizeUtil.authorizeManageWorkflowsGroup;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.GroupRest;
|
||||
import org.dspace.app.rest.utils.GroupUtil;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.xmlworkflow.storedcomponents.CollectionRole;
|
||||
import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* This will be the entry point for the api/eperson/groups endpoint with additional paths to it
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/" + GroupRest.CATEGORY + "/" + GroupRest.GROUPS)
|
||||
public class GroupRestController {
|
||||
|
||||
@Autowired
|
||||
private GroupService groupService;
|
||||
|
||||
@Autowired
|
||||
private EPersonService ePersonService;
|
||||
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
@Autowired
|
||||
private CollectionRoleService collectionRoleService;
|
||||
|
||||
@Autowired
|
||||
Utils utils;
|
||||
|
||||
@Autowired
|
||||
GroupUtil groupUtil;
|
||||
|
||||
/**
|
||||
* Method to add one or more subgroups to a group.
|
||||
* The subgroups to be added should be provided in the request body as a uri-list.
|
||||
* Note that only the 'AUTHENTICATED' state will be checked in PreAuthorize, a more detailed check will be done by
|
||||
* using the 'checkAuthorization' method.
|
||||
*
|
||||
* @param uuid the uuid of the group to add the subgroups to
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@RequestMapping(method = POST, path = "/{uuid}/subgroups", consumes = {"text/uri-list"})
|
||||
public void addChildGroups(@PathVariable UUID uuid, HttpServletResponse response, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
Context context = obtainContext(request);
|
||||
|
||||
Group parentGroup = groupService.find(context, uuid);
|
||||
if (parentGroup == null) {
|
||||
throw new ResourceNotFoundException("parent group is not found for uuid: " + uuid);
|
||||
}
|
||||
|
||||
checkAuthorization(context, parentGroup);
|
||||
|
||||
List<String> groupLinks = utils.getStringListFromRequest(request);
|
||||
|
||||
List<Group> childGroups = new ArrayList<>();
|
||||
for (String groupLink : groupLinks) {
|
||||
Optional<Group> childGroup = findGroup(context, groupLink);
|
||||
if (!childGroup.isPresent() || !canAddGroup(context, parentGroup, childGroup.get())) {
|
||||
throw new UnprocessableEntityException("cannot add child group: " + groupLink);
|
||||
}
|
||||
childGroups.add(childGroup.get());
|
||||
}
|
||||
|
||||
for (Group childGroup : childGroups) {
|
||||
groupService.addMember(context, parentGroup, childGroup);
|
||||
}
|
||||
|
||||
context.complete();
|
||||
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
private Optional<Group> findGroup(Context context, String groupLink) throws SQLException {
|
||||
|
||||
Group group = null;
|
||||
|
||||
Pattern linkPattern = compile("^.*/(" + REGEX_UUID + ")/?$");
|
||||
Matcher matcher = linkPattern.matcher(groupLink);
|
||||
if (matcher.matches()) {
|
||||
group = groupService.find(context, UUID.fromString(matcher.group(1)));
|
||||
}
|
||||
|
||||
return Optional.ofNullable(group);
|
||||
}
|
||||
|
||||
private boolean canAddGroup(Context context, Group parentGroup, Group childGroup) throws SQLException {
|
||||
|
||||
return !groupService.isParentOf(context, childGroup, parentGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to add one or more members to a group.
|
||||
* The members to be added should be provided in the request body as a uri-list.
|
||||
* Note that only the 'AUTHENTICATED' state will be checked in PreAuthorize, a more detailed check will be done by
|
||||
* using the 'checkAuthorization' method.
|
||||
*
|
||||
* @param uuid the uuid of the group to add the members to
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@RequestMapping(method = POST, path = "/{uuid}/epersons", consumes = {"text/uri-list"})
|
||||
public void addMembers(@PathVariable UUID uuid, HttpServletResponse response, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
Context context = obtainContext(request);
|
||||
|
||||
Group parentGroup = groupService.find(context, uuid);
|
||||
if (parentGroup == null) {
|
||||
throw new ResourceNotFoundException("parent group is not found for uuid: " + uuid);
|
||||
}
|
||||
|
||||
checkAuthorization(context, parentGroup);
|
||||
|
||||
List<String> memberLinks = utils.getStringListFromRequest(request);
|
||||
|
||||
List<EPerson> members = new ArrayList<>();
|
||||
for (String memberLink : memberLinks) {
|
||||
Optional<EPerson> member = findEPerson(context, memberLink);
|
||||
if (!member.isPresent()) {
|
||||
throw new UnprocessableEntityException("cannot add child group: " + memberLink);
|
||||
}
|
||||
members.add(member.get());
|
||||
}
|
||||
|
||||
for (EPerson member : members) {
|
||||
groupService.addMember(context, parentGroup, member);
|
||||
}
|
||||
|
||||
context.complete();
|
||||
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
private Optional<EPerson> findEPerson(Context context, String groupLink) throws SQLException {
|
||||
|
||||
EPerson ePerson = null;
|
||||
|
||||
Pattern linkPattern = compile("^.*/(" + REGEX_UUID + ")/?$");
|
||||
Matcher matcher = linkPattern.matcher(groupLink);
|
||||
if (matcher.matches()) {
|
||||
ePerson = ePersonService.find(context, UUID.fromString(matcher.group(1)));
|
||||
}
|
||||
|
||||
return Optional.ofNullable(ePerson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to remove a subgroup from a group.
|
||||
* Note that only the 'AUTHENTICATED' state will be checked in PreAuthorize, a more detailed check will be done by
|
||||
* using the 'checkAuthorization' method.
|
||||
*
|
||||
* @param parentUUID the uuid of the parent group
|
||||
* @param childUUID the uuid of the subgroup which has to be removed
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@RequestMapping(method = DELETE, path = "/{parentUUID}/subgroups/{childUUID}")
|
||||
public void removeChildGroup(@PathVariable UUID parentUUID, @PathVariable UUID childUUID,
|
||||
HttpServletResponse response, HttpServletRequest request)
|
||||
throws IOException, SQLException, AuthorizeException {
|
||||
|
||||
Context context = obtainContext(request);
|
||||
|
||||
Group parentGroup = groupService.find(context, parentUUID);
|
||||
if (parentGroup == null) {
|
||||
throw new ResourceNotFoundException("parent group is not found for uuid: " + parentUUID);
|
||||
}
|
||||
|
||||
checkAuthorization(context, parentGroup);
|
||||
|
||||
Group childGroup = groupService.find(context, childUUID);
|
||||
if (childGroup == null) {
|
||||
response.sendError(SC_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
groupService.removeMember(context, parentGroup, childGroup);
|
||||
|
||||
context.complete();
|
||||
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to remove a member from a group.
|
||||
* Note that only the 'AUTHENTICATED' state will be checked in PreAuthorize, a more detailed check will be done by
|
||||
* using the 'checkAuthorization' method.
|
||||
*
|
||||
* @param parentUUID the uuid of the parent group
|
||||
* @param memberUUID the uuid of the member which has to be removed
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@RequestMapping(method = DELETE, path = "/{parentUUID}/epersons/{memberUUID}")
|
||||
public void removeMember(@PathVariable UUID parentUUID, @PathVariable UUID memberUUID,
|
||||
HttpServletResponse response, HttpServletRequest request)
|
||||
throws IOException, SQLException, AuthorizeException {
|
||||
|
||||
Context context = obtainContext(request);
|
||||
|
||||
Group parentGroup = groupService.find(context, parentUUID);
|
||||
if (parentGroup == null) {
|
||||
throw new ResourceNotFoundException("parent group is not found for uuid: " + parentUUID);
|
||||
}
|
||||
|
||||
checkAuthorization(context, parentGroup);
|
||||
|
||||
EPerson childGroup = ePersonService.find(context, memberUUID);
|
||||
if (childGroup == null) {
|
||||
response.sendError(SC_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
groupService.removeMember(context, parentGroup, childGroup);
|
||||
|
||||
context.complete();
|
||||
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether the current user has sufficient rights to modify the group.
|
||||
* Depending on the kind of group and due to delegated administration, separate checks need to be done to verify
|
||||
* whether the user is allowed to modify the group.
|
||||
*
|
||||
* @param context the context of which the user will be checked
|
||||
* @param group the group to be checked
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
private void checkAuthorization(Context context, Group group) throws SQLException, AuthorizeException {
|
||||
|
||||
if (authorizeService.isAdmin(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection collection = groupUtil.getCollection(context, group);
|
||||
if (collection != null) {
|
||||
|
||||
if (group.equals(collection.getSubmitters())) {
|
||||
authorizeManageSubmittersGroup(context, collection);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
List<CollectionRole> collectionRoles = collectionRoleService.findByCollection(context, collection);
|
||||
for (CollectionRole role : collectionRoles) {
|
||||
if (group.equals(role.getGroup())) {
|
||||
authorizeManageWorkflowsGroup(context, collection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (group.equals(collection.getAdministrators())) {
|
||||
authorizeManageAdminGroup(context, collection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Community community = groupUtil.getCommunity(context, group);
|
||||
if (community != null) {
|
||||
authorizeManageAdminGroup(context, community);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new AuthorizeException("not authorized to manage this group");
|
||||
}
|
||||
}
|
@@ -12,7 +12,6 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@@ -36,6 +36,7 @@ import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.converter.JsonPatchConverter;
|
||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||
import org.dspace.app.rest.exception.PaginationException;
|
||||
import org.dspace.app.rest.exception.RESTAuthorizationException;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.exception.RepositoryNotFoundException;
|
||||
import org.dspace.app.rest.exception.RepositorySearchMethodNotFoundException;
|
||||
@@ -580,13 +581,14 @@ public class RestResourceController implements InitializingBean {
|
||||
MultipartFile uploadfile) {
|
||||
checkModelPluralForm(apiCategory, model);
|
||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||
|
||||
RestAddressableModel modelObject = null;
|
||||
try {
|
||||
modelObject = repository.upload(request, apiCategory, model, id, uploadfile);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return ControllerUtils.toEmptyResponse(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
} catch (SQLException | IOException e) {
|
||||
throw new RuntimeException("Error " + e.getMessage() +
|
||||
" uploading file to " + model + " with ID= " + id, e);
|
||||
} catch ( AuthorizeException ae) {
|
||||
throw new RESTAuthorizationException(ae);
|
||||
}
|
||||
DSpaceResource result = converter.toResource(modelObject);
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, new HttpHeaders(), result);
|
||||
@@ -910,7 +912,6 @@ public class RestResourceController implements InitializingBean {
|
||||
Pageable page,
|
||||
PagedResourcesAssembler assembler,
|
||||
HttpServletResponse response) {
|
||||
|
||||
DSpaceRestRepository<T, ?> repository = utils.getResourceRepository(apiCategory, model);
|
||||
Link link = linkTo(methodOn(this.getClass(), apiCategory, model).findAll(apiCategory, model,
|
||||
page, assembler, response))
|
||||
|
@@ -19,8 +19,12 @@ import org.dspace.app.rest.RestResourceController;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@LinksRest(links = {
|
||||
@LinkRest(
|
||||
name = GroupRest.GROUPS,
|
||||
name = GroupRest.SUBGROUPS,
|
||||
method = "getGroups"
|
||||
),
|
||||
@LinkRest(
|
||||
name = GroupRest.EPERSONS,
|
||||
method = "getMembers"
|
||||
)
|
||||
})
|
||||
public class GroupRest extends DSpaceObjectRest {
|
||||
@@ -28,6 +32,8 @@ public class GroupRest extends DSpaceObjectRest {
|
||||
public static final String CATEGORY = RestAddressableModel.EPERSON;
|
||||
|
||||
public static final String GROUPS = "groups";
|
||||
public static final String SUBGROUPS = "subgroups";
|
||||
public static final String EPERSONS = "epersons";
|
||||
|
||||
private String name;
|
||||
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest.model.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -93,4 +92,4 @@ public class UploadBitstreamRest extends UploadStatusResponse {
|
||||
public void setFormat(BitstreamFormatRest format) {
|
||||
this.format = format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.ClaimedTaskRest;
|
||||
import org.dspace.app.rest.model.PoolTaskRest;
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
@@ -137,6 +138,11 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository<ClaimedTaskR
|
||||
|
||||
Step step = workflow.getStep(task.getStepID());
|
||||
WorkflowActionConfig currentActionConfig = step.getActionConfig(task.getActionID());
|
||||
String submitButton = Util.getSubmitButton(request, null);
|
||||
if (!currentActionConfig.getProcessingAction().getOptions().contains(submitButton)) {
|
||||
throw new UnprocessableEntityException(submitButton + " is not a valid option on this action (" +
|
||||
currentActionConfig.getProcessingAction().getClass() + ").");
|
||||
}
|
||||
workflowService
|
||||
.doState(context, context.getCurrentUser(), request, task.getWorkflowItem().getID(), workflow,
|
||||
currentActionConfig);
|
||||
|
@@ -14,7 +14,6 @@ import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
@@ -380,10 +379,10 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
* @param file
|
||||
* the uploaded file
|
||||
* @return the new state of the REST object
|
||||
* @throws Exception
|
||||
*/
|
||||
public T upload(HttpServletRequest request, String apiCategory, String model,
|
||||
ID id, MultipartFile file) throws Exception {
|
||||
ID id, MultipartFile file)
|
||||
throws SQLException, FileNotFoundException, IOException, AuthorizeException {
|
||||
throw new RuntimeException("No implementation found; Method not allowed!");
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Link repository for "groups" subresource of an individual eperson.
|
||||
* Link repository for the direct "groups" subresource of an individual eperson.
|
||||
*/
|
||||
@Component(EPersonRest.CATEGORY + "." + EPersonRest.NAME + "." + EPersonRest.GROUPS)
|
||||
public class EPersonGroupLinkRepository extends AbstractDSpaceRestRepository
|
||||
@@ -51,7 +51,7 @@ public class EPersonGroupLinkRepository extends AbstractDSpaceRestRepository
|
||||
if (eperson == null) {
|
||||
throw new ResourceNotFoundException("No such eperson: " + epersonId);
|
||||
}
|
||||
Page<Group> groups = utils.getPage(groupService.allMemberGroups(context, eperson), optionalPageable);
|
||||
Page<Group> groups = utils.getPage(eperson.getGroups(), optionalPageable);
|
||||
return converter.toRestPage(groups, projection);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@@ -114,37 +114,13 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the epersons matching the query q parameter. The search is delegated to the
|
||||
* {@link EPersonService#search(Context, String, int, int)} method
|
||||
*
|
||||
* @param q
|
||||
* is the *required* query string
|
||||
* @param pageable
|
||||
* contains the pagination information
|
||||
* @return a Page of EPersonRest instances matching the user query
|
||||
*/
|
||||
@SearchRestMethod(name = "byName")
|
||||
public Page<EPersonRest> findByName(@Parameter(value = "q", required = true) String q,
|
||||
Pageable pageable) {
|
||||
try {
|
||||
Context context = obtainContext();
|
||||
long total = es.searchResultCount(context, q);
|
||||
List<EPerson> epersons = es.search(context, q, Math.toIntExact(pageable.getOffset()),
|
||||
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
|
||||
return converter.toRestPage(epersons, pageable, total, utils.obtainProjection());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the eperson with the provided email address if any. The search is delegated to the
|
||||
* {@link EPersonService#findByEmail(Context, String)} method
|
||||
*
|
||||
* @param email
|
||||
* is the *required* email address
|
||||
* @return the EPersonRest instance, if any, matching the user query
|
||||
* @return a Page of EPersonRest instances matching the user query
|
||||
*/
|
||||
@SearchRestMethod(name = "byEmail")
|
||||
public EPersonRest findByEmail(@Parameter(value = "email", required = true) String email) {
|
||||
@@ -161,6 +137,32 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
||||
return converter.toRest(eperson, utils.obtainProjection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the epersons matching the query parameter. The search is delegated to the
|
||||
* {@link EPersonService#search(Context, String, int, int)} method
|
||||
*
|
||||
* @param query
|
||||
* is the *required* query string
|
||||
* @param pageable
|
||||
* contains the pagination information
|
||||
* @return a Page of EPersonRest instances matching the user query
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
@SearchRestMethod(name = "byMetadata")
|
||||
public Page<EPersonRest> findByMetadata(@Parameter(value = "query", required = true) String query,
|
||||
Pageable pageable) {
|
||||
|
||||
try {
|
||||
Context context = obtainContext();
|
||||
long total = es.searchResultCount(context, query);
|
||||
List<EPerson> epersons = es.search(context, query, Math.toIntExact(pageable.getOffset()),
|
||||
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
|
||||
return converter.toRestPage(epersons, pageable, total, utils.obtainProjection());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasPermission(#uuid, 'EPERSON', #patch)")
|
||||
protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
|
||||
|
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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 java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.rest.model.GroupRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
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 "epersons" subresource of an individual group.
|
||||
*/
|
||||
@Component(GroupRest.CATEGORY + "." + GroupRest.NAME + "." + GroupRest.EPERSONS)
|
||||
public class GroupEPersonLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
GroupService groupService;
|
||||
|
||||
@PreAuthorize("hasPermission(#groupId, 'GROUP', 'READ')")
|
||||
public Page<GroupRest> getMembers(@Nullable HttpServletRequest request,
|
||||
UUID groupId,
|
||||
@Nullable Pageable optionalPageable,
|
||||
Projection projection) {
|
||||
try {
|
||||
Context context = obtainContext();
|
||||
Group group = groupService.find(context, groupId);
|
||||
if (group == null) {
|
||||
throw new ResourceNotFoundException("No such group: " + groupId);
|
||||
}
|
||||
Page<EPerson> ePersons = utils.getPage(group.getMembers(), optionalPageable);
|
||||
return converter.toRestPage(ePersons, projection);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -27,7 +27,7 @@ import org.springframework.stereotype.Component;
|
||||
/**
|
||||
* Link repository for "groups" subresource of an individual group.
|
||||
*/
|
||||
@Component(GroupRest.CATEGORY + "." + GroupRest.NAME + "." + GroupRest.GROUPS)
|
||||
@Component(GroupRest.CATEGORY + "." + GroupRest.NAME + "." + GroupRest.SUBGROUPS)
|
||||
public class GroupGroupLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
|
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
@@ -14,6 +16,8 @@ import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.MetadataConverter;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
@@ -53,9 +57,10 @@ public class GroupRestRepository extends DSpaceObjectRestRepository<Group, Group
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
protected GroupRest createAndReturn(Context context)
|
||||
throws AuthorizeException, RepositoryMethodNotImplementedException {
|
||||
|
||||
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
GroupRest groupRest = null;
|
||||
GroupRest groupRest;
|
||||
|
||||
try {
|
||||
groupRest = mapper.readValue(req.getInputStream(), GroupRest.class);
|
||||
@@ -63,7 +68,11 @@ public class GroupRestRepository extends DSpaceObjectRestRepository<Group, Group
|
||||
throw new UnprocessableEntityException("error parsing the body ..." + excIO.getMessage());
|
||||
}
|
||||
|
||||
Group group = null;
|
||||
if (isBlank(groupRest.getName())) {
|
||||
throw new UnprocessableEntityException("cannot create group, no group name is provided");
|
||||
}
|
||||
|
||||
Group group;
|
||||
try {
|
||||
group = gs.create(context);
|
||||
gs.setName(group, groupRest.getName());
|
||||
@@ -97,7 +106,7 @@ public class GroupRestRepository extends DSpaceObjectRestRepository<Group, Group
|
||||
try {
|
||||
long total = gs.countTotal(context);
|
||||
List<Group> groups = gs.findAll(context, null, pageable.getPageSize(),
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
return converter.toRestPage(groups, pageable, total, utils.obtainProjection());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
@@ -111,6 +120,31 @@ public class GroupRestRepository extends DSpaceObjectRestRepository<Group, Group
|
||||
patchDSpaceObject(apiCategory, model, id, patch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the groups matching the query parameter. The search is delegated to the
|
||||
* {@link GroupService#search(Context, String, int, int)} method
|
||||
*
|
||||
* @param query is the *required* query string
|
||||
* @param pageable contains the pagination information
|
||||
* @return a Page of GroupRest instances matching the user query
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
@SearchRestMethod(name = "byMetadata")
|
||||
public Page<GroupRest> findByMetadata(@Parameter(value = "query", required = true) String query,
|
||||
Pageable pageable) {
|
||||
|
||||
try {
|
||||
Context context = obtainContext();
|
||||
long total = gs.searchResultCount(context, query);
|
||||
List<Group> groups = gs.search(context, query, Math.toIntExact(pageable.getOffset()),
|
||||
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
|
||||
return converter.toRestPage(groups, pageable, total, utils.obtainProjection());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<GroupRest> getDomainClass() {
|
||||
return GroupRest.class;
|
||||
|
@@ -11,11 +11,9 @@ import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.exception.MissingParameterException;
|
||||
|
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import static org.dspace.xmlworkflow.state.actions.processingaction.ProcessingAction.SUBMIT_EDIT_METADATA;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,7 +46,14 @@ import org.dspace.eperson.EPersonServiceImpl;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.workflow.WorkflowException;
|
||||
import org.dspace.workflow.WorkflowService;
|
||||
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.state.Workflow;
|
||||
import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig;
|
||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
|
||||
import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -95,6 +104,15 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
@Autowired
|
||||
AuthorizeService authorizeService;
|
||||
|
||||
@Autowired
|
||||
ClaimedTaskService claimedTaskService;
|
||||
|
||||
@Autowired
|
||||
protected XmlWorkflowItemService xmlWorkflowItemService;
|
||||
|
||||
@Autowired
|
||||
protected XmlWorkflowFactory workflowFactory;
|
||||
|
||||
private final SubmissionConfigReader submissionConfigReader;
|
||||
|
||||
public WorkflowItemRestRepository() throws SubmissionConfigReaderException {
|
||||
@@ -124,7 +142,8 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
List<XmlWorkflowItem> witems = wis.findAll(context, pageable.getPageNumber(), pageable.getPageSize());
|
||||
return converter.toRestPage(witems, pageable, total, utils.obtainProjection());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
throw new RuntimeException("SQLException in " + this.getClass() + "#findAll trying to retrieve all " +
|
||||
"workflowitems from db.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +158,8 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
pageable.getPageSize());
|
||||
return converter.toRestPage(witems, pageable, total, utils.obtainProjection());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
throw new RuntimeException("SQLException in " + this.getClass() + "#findBySubmitter trying to retrieve " +
|
||||
"eperson or their workflowitems from db.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +177,8 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
throw new UnprocessableEntityException(
|
||||
"Invalid workflow action: " + e.getMessage(), e);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
throw new RuntimeException("SQLException in " + this.getClass() + "#findBySubmitter trying to create " +
|
||||
"a workflow and adding it to db.", e);
|
||||
}
|
||||
//if the item go directly in published status we have to manage a status code 204 with no content
|
||||
if (source.getItem().isArchived()) {
|
||||
@@ -173,11 +194,14 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
|
||||
@Override
|
||||
public WorkflowItemRest upload(HttpServletRequest request, String apiCategory, String model, Integer id,
|
||||
MultipartFile file) throws Exception {
|
||||
MultipartFile file) throws SQLException {
|
||||
|
||||
Context context = obtainContext();
|
||||
WorkflowItemRest wsi = findOne(context, id);
|
||||
XmlWorkflowItem source = wis.find(context, id);
|
||||
|
||||
this.checkIfEditMetadataAllowedInCurrentStep(context, source);
|
||||
|
||||
List<ErrorRest> errors = new ArrayList<ErrorRest>();
|
||||
SubmissionConfig submissionConfig =
|
||||
submissionConfigReader.getSubmissionConfigByName(wsi.getSubmissionDefinition().getName());
|
||||
@@ -226,6 +250,9 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
List<Operation> operations = patch.getOperations();
|
||||
WorkflowItemRest wsi = findOne(context, id);
|
||||
XmlWorkflowItem source = wis.find(context, id);
|
||||
|
||||
this.checkIfEditMetadataAllowedInCurrentStep(context, source);
|
||||
|
||||
for (Operation op : operations) {
|
||||
//the value in the position 0 is a null value
|
||||
String[] path = op.getPath().substring(1).split("/", 3);
|
||||
@@ -296,8 +323,42 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository<WorkflowIte
|
||||
wfs.abort(context, witem, context.getCurrentUser());
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RESTAuthorizationException(e);
|
||||
} catch (SQLException | IOException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQLException in " + this.getClass() + "#delete trying to retrieve or delete a" +
|
||||
" workflowitem from db.", e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("IOException in " + this.getClass() + "#delete trying to delete a workflowitem" +
|
||||
" from db (abort).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @link{SUBMIT_EDIT_METADATA} is a valid option in the workflow step this task is currently at.
|
||||
* Patching and uploading is only allowed if this is the case.
|
||||
* @param context Context
|
||||
* @param xmlWorkflowItem WorkflowItem of the task
|
||||
*/
|
||||
private void checkIfEditMetadataAllowedInCurrentStep(Context context, XmlWorkflowItem xmlWorkflowItem) {
|
||||
try {
|
||||
ClaimedTask claimedTask = claimedTaskService.findByWorkflowIdAndEPerson(context, xmlWorkflowItem,
|
||||
context.getCurrentUser());
|
||||
if (claimedTask == null) {
|
||||
throw new UnprocessableEntityException("WorkflowItem with id " + xmlWorkflowItem.getID()
|
||||
+ " has not been claimed yet.");
|
||||
}
|
||||
Workflow workflow = workflowFactory.getWorkflow(claimedTask.getWorkflowItem().getCollection());
|
||||
Step step = workflow.getStep(claimedTask.getStepID());
|
||||
WorkflowActionConfig currentActionConfig = step.getActionConfig(claimedTask.getActionID());
|
||||
if (!currentActionConfig.getProcessingAction().getOptions().contains(SUBMIT_EDIT_METADATA)) {
|
||||
throw new UnprocessableEntityException(SUBMIT_EDIT_METADATA + " is not a valid option on this " +
|
||||
"action (" + currentActionConfig.getProcessingAction().getClass() + ").");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQLException in " + this.getClass()
|
||||
+ "#checkIfEditMetadataAllowedInCurrentStep trying to retrieve workflowitem from db by eperson.", e);
|
||||
} catch (WorkflowConfigurationException e) {
|
||||
throw new RuntimeException("WorkflowConfigurationException in " + this.getClass()
|
||||
+ "#checkIfEditMetadataAllowedInCurrentStep trying to retrieve workflow configuration from config", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -68,6 +68,7 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -125,7 +126,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
submissionConfigReader = new SubmissionConfigReader();
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')")
|
||||
@PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')")
|
||||
@Override
|
||||
public WorkspaceItemRest findOne(Context context, Integer id) {
|
||||
WorkspaceItem witem = null;
|
||||
@@ -140,7 +141,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
return converter.toRest(witem, utils.obtainProjection());
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasAuthority('ADMIN')")
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
@Override
|
||||
public Page<WorkspaceItemRest> findAll(Context context, Pageable pageable) {
|
||||
try {
|
||||
@@ -153,7 +154,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
}
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#submitterID, 'EPERSON', 'READ')")
|
||||
@PreAuthorize("hasPermission(#submitterID, 'EPERSON', 'READ')")
|
||||
@SearchRestMethod(name = "findBySubmitter")
|
||||
public Page<WorkspaceItemRest> findBySubmitter(@Parameter(value = "uuid", required = true) UUID submitterID,
|
||||
Pageable pageable) {
|
||||
@@ -219,10 +220,10 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
return WorkspaceItemRest.class;
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'WRITE')")
|
||||
@PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'WRITE')")
|
||||
@Override
|
||||
public WorkspaceItemRest upload(HttpServletRequest request, String apiCategory, String model, Integer id,
|
||||
MultipartFile file) throws Exception {
|
||||
MultipartFile file) throws SQLException {
|
||||
|
||||
Context context = obtainContext();
|
||||
WorkspaceItemRest wsi = findOne(context, id);
|
||||
@@ -269,7 +270,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
return wsi;
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'WRITE')")
|
||||
@PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'WRITE')")
|
||||
@Override
|
||||
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, Integer id,
|
||||
Patch patch) throws SQLException, AuthorizeException {
|
||||
@@ -332,7 +333,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
}
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'DELETE')")
|
||||
@PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'DELETE')")
|
||||
@Override
|
||||
protected void delete(Context context, Integer id) throws AuthorizeException {
|
||||
WorkspaceItem witem = null;
|
||||
|
@@ -15,7 +15,6 @@ import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.repository.patch.operation.PatchOperation;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@@ -14,6 +14,7 @@ import java.util.UUID;
|
||||
import org.dspace.app.rest.utils.ContextUtil;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.DSpaceObjectService;
|
||||
import org.dspace.core.Constants;
|
||||
@@ -84,6 +85,15 @@ public class AuthorizeServicePermissionEvaluatorPlugin extends RestObjectPermiss
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the item is still inprogress we can process here only the READ permission.
|
||||
// Other actions need to be evaluated against the wrapper object (workspace or workflow item)
|
||||
if (dSpaceObject instanceof Item) {
|
||||
if (!DSpaceRestPermission.READ.equals(restPermission)
|
||||
&& !((Item) dSpaceObject).isArchived() && !((Item) dSpaceObject).isWithdrawn()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeService.authorizeActionBoolean(context, ePerson, dSpaceObject,
|
||||
restPermission.getDspaceApiActionId(), true);
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -29,9 +28,9 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* {@link RestPermissionEvaluatorPlugin} class that evaluate ADMIN permissions over a Resource Policy
|
||||
*
|
||||
*
|
||||
* @author Mykhaylo Boychuk - (4Science.it)
|
||||
*/
|
||||
@Component
|
||||
|
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.model.WorkspaceItemRest;
|
||||
import org.dspace.app.rest.utils.ContextUtil;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* {@link RestPermissionEvaluatorPlugin} class that evaluate READ, WRITE and DELETE permissions over a WorkspaceItem
|
||||
*
|
||||
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.it)
|
||||
*/
|
||||
@Component
|
||||
public class WorkspaceItemRestPermissionEvaluatorPlugin extends RestObjectPermissionEvaluatorPlugin {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WorkspaceItemRestPermissionEvaluatorPlugin.class);
|
||||
|
||||
@Autowired
|
||||
private RequestService requestService;
|
||||
|
||||
@Autowired
|
||||
WorkspaceItemService wis;
|
||||
|
||||
@Override
|
||||
public boolean hasDSpacePermission(Authentication authentication, Serializable targetId, String targetType,
|
||||
DSpaceRestPermission permission) {
|
||||
|
||||
DSpaceRestPermission restPermission = DSpaceRestPermission.convert(permission);
|
||||
if (!DSpaceRestPermission.READ.equals(restPermission)
|
||||
&& !DSpaceRestPermission.WRITE.equals(restPermission)
|
||||
&& !DSpaceRestPermission.DELETE.equals(restPermission)) {
|
||||
return false;
|
||||
}
|
||||
if (!StringUtils.equalsIgnoreCase(targetType, WorkspaceItemRest.NAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Request request = requestService.getCurrentRequest();
|
||||
Context context = ContextUtil.obtainContext(request.getServletRequest());
|
||||
|
||||
EPerson ePerson = null;
|
||||
WorkspaceItem witem = null;
|
||||
try {
|
||||
ePerson = context.getCurrentUser();
|
||||
Integer dsoId = Integer.parseInt(targetId.toString());
|
||||
|
||||
// anonymous user
|
||||
if (ePerson == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
witem = wis.find(context, dsoId);
|
||||
|
||||
// If the dso is null then we give permission so we can throw another status
|
||||
// code instead
|
||||
if (witem == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (witem.getSubmitter() != null) {
|
||||
if (witem.getSubmitter().getID().equals(ePerson.getID())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest.submit;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -141,7 +140,7 @@ public class SubmissionService {
|
||||
* Build the rest representation of a bitstream as used in the upload section
|
||||
* ({@link DataUpload}. It contains all its metadata and the list of applied
|
||||
* access conditions (@link {@link UploadBitstreamAccessConditionDTO}
|
||||
*
|
||||
*
|
||||
* @param configurationService the DSpace ConfigurationService
|
||||
* @param source the bitstream to translate in its rest submission
|
||||
* representation
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest.submit.factory.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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.utils;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* A class which provides utility methods for Groups
|
||||
*/
|
||||
@Component
|
||||
public class GroupUtil {
|
||||
|
||||
private GroupUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* UUID regex used in the collection regex
|
||||
*/
|
||||
private static final String UUID_REGEX = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0" +
|
||||
"-9a-fA-F]{12}";
|
||||
/**
|
||||
* Collection regex used to extract the ID
|
||||
*/
|
||||
private static final String COLLECTION_REGEX = "COLLECTION_(" + UUID_REGEX + ")_.*?";
|
||||
|
||||
/**
|
||||
* The community prefix: all groups which are specific to
|
||||
* a community start with this.
|
||||
*/
|
||||
private static final String COMMUNITY_PREFIX = "COMMUNITY_";
|
||||
|
||||
/**
|
||||
* These are the possible community suffixes. All groups which are
|
||||
* specific to a community will end with one of these.
|
||||
*/
|
||||
private static final String[] COMMUNITY_SUFFIXES = {"_ADMIN"};
|
||||
|
||||
@Autowired
|
||||
protected CollectionService collectionService;
|
||||
|
||||
@Autowired
|
||||
protected CommunityService communityService;
|
||||
|
||||
/**
|
||||
* Get the collection a given group is related to, or null if it is not related to a collection.
|
||||
*/
|
||||
public Collection getCollection(Context context, Group group) throws SQLException {
|
||||
|
||||
String groupName = group.getName();
|
||||
|
||||
if (groupName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Matcher groupNameMatcher = Pattern.compile(COLLECTION_REGEX).matcher(groupName);
|
||||
|
||||
if (groupNameMatcher.find()) {
|
||||
String uuid = groupNameMatcher.group();
|
||||
Collection collection = collectionService.findByIdOrLegacyId(context, uuid);
|
||||
if (collection != null) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the community a given group is related to, or null if it is not related to a community.
|
||||
*/
|
||||
public Community getCommunity(Context context, Group group) throws SQLException {
|
||||
|
||||
String groupName = group.getName();
|
||||
|
||||
if (groupName == null || !groupName.startsWith(COMMUNITY_PREFIX)) {
|
||||
return null;
|
||||
}
|
||||
for (String suffix : COMMUNITY_SUFFIXES) {
|
||||
if (groupName.endsWith(suffix)) {
|
||||
String idString = groupName.substring(COMMUNITY_PREFIX.length());
|
||||
idString = idString.substring(0, idString.length() - suffix.length());
|
||||
|
||||
Community community = communityService.findByIdOrLegacyId(context, idString);
|
||||
if (community != null) {
|
||||
return community;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -11,11 +11,17 @@ public class RegexUtils {
|
||||
|
||||
private RegexUtils(){}
|
||||
|
||||
/**
|
||||
* Regular expression in the request mapping to accept UUID as identifier
|
||||
*/
|
||||
public static final String REGEX_UUID =
|
||||
"[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}";
|
||||
|
||||
/**
|
||||
* Regular expression in the request mapping to accept UUID as identifier
|
||||
*/
|
||||
public static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID =
|
||||
"/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}";
|
||||
"/{uuid:" + REGEX_UUID + "}";
|
||||
|
||||
/**
|
||||
* Regular expression in the request mapping to accept a string as identifier but not the other kind of
|
||||
|
@@ -28,7 +28,6 @@ import com.lyncode.xoai.dataprovider.services.api.ResourceResolver;
|
||||
import com.lyncode.xoai.dataprovider.services.impl.BaseDateProvider;
|
||||
import com.lyncode.xoai.dataprovider.xml.xoaiconfig.Configuration;
|
||||
import com.lyncode.xoai.dataprovider.xml.xoaiconfig.ContextConfiguration;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.dspace.app.rest.builder.CollectionBuilder;
|
||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||
@@ -39,7 +38,6 @@ import org.dspace.xoai.services.api.EarliestDateResolver;
|
||||
import org.dspace.xoai.services.api.cache.XOAICacheService;
|
||||
import org.dspace.xoai.services.api.config.XOAIManagerResolver;
|
||||
import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver;
|
||||
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@@ -12,10 +12,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@@ -15,13 +15,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import org.dspace.app.rest.builder.CollectionBuilder;
|
||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||
import org.dspace.app.rest.builder.ItemBuilder;
|
||||
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Item;
|
||||
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.junit.Before;
|
||||
|
@@ -30,6 +30,7 @@ import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
@@ -58,6 +59,8 @@ public class AuthenticationRestControllerIT extends AbstractControllerIntegratio
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// Ignored until an endpoint is added to return all groups. Anonymous is not considered a direct group.
|
||||
public void testStatusAuthenticated() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
@@ -352,6 +355,8 @@ public class AuthenticationRestControllerIT extends AbstractControllerIntegratio
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// Ignored until an endpoint is added to return all groups
|
||||
public void testShibbolethLoginRequestAttribute() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
//Enable Shibboleth login
|
||||
@@ -393,6 +398,8 @@ public class AuthenticationRestControllerIT extends AbstractControllerIntegratio
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// Ignored until an endpoint is added to return all groups
|
||||
public void testShibbolethLoginRequestHeaderWithIpAuthentication() throws Exception {
|
||||
configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", SHIB_AND_IP);
|
||||
configurationService.setProperty("authentication-ip.Administrator", "123.123.123.123");
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static java.util.UUID.randomUUID;
|
||||
|
||||
import static org.apache.commons.codec.CharEncoding.UTF_8;
|
||||
import static org.apache.commons.collections.CollectionUtils.isEmpty;
|
||||
import static org.apache.commons.io.IOUtils.toInputStream;
|
||||
|
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
@@ -3717,4 +3719,407 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
public void discoverSearchObjectsTestForAdministrativeViewAnonymous() throws Exception {
|
||||
|
||||
//We turn off the authorization system in order to create the structure as defined below
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
//** GIVEN **
|
||||
|
||||
//1. 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();
|
||||
Collection col2 = CollectionBuilder
|
||||
.createCollection(context, child1)
|
||||
.withName("Collection 2")
|
||||
.build();
|
||||
|
||||
//2. One public item, one private, one withdrawn.
|
||||
|
||||
ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Public Test Item")
|
||||
.withIssueDate("2010-10-17")
|
||||
.withAuthor("Smith, Donald")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn Test Item")
|
||||
.withIssueDate("1990-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("ExtraEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private Test Item")
|
||||
.withIssueDate("2010-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.withSubject("ExtraEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
|
||||
// An anonymous user browses this endpoint to find the withdrawn or private objects in the system
|
||||
// With a query stating 'Test'
|
||||
|
||||
getClient().perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test"))
|
||||
|
||||
//** THEN **
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Public Test Item")
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverSearchObjectsTestForAdministrativeViewEPerson() throws Exception {
|
||||
|
||||
//We turn off the authorization system in order to create the structure as defined below
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
//** GIVEN **
|
||||
|
||||
//1. 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();
|
||||
Collection col2 = CollectionBuilder
|
||||
.createCollection(context, child1)
|
||||
.withName("Collection 2")
|
||||
.build();
|
||||
|
||||
//2. One public item, one private, one withdrawn.
|
||||
|
||||
ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Public Test Item")
|
||||
.withIssueDate("2010-10-17")
|
||||
.withAuthor("Smith, Donald")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn Test Item")
|
||||
.withIssueDate("1990-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("ExtraEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private Test Item")
|
||||
.withIssueDate("2010-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.withSubject("ExtraEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
|
||||
// A non-admin user browses this endpoint to find the withdrawn or private objects in the system
|
||||
// With a query stating 'Test'
|
||||
|
||||
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test"))
|
||||
|
||||
//** THEN **
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Public Test Item")
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverSearchObjectsTestForAdministrativeViewAdmin() throws Exception {
|
||||
|
||||
//We turn off the authorization system in order to create the structure as defined below
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
//** GIVEN **
|
||||
|
||||
//1. 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();
|
||||
Collection col2 = CollectionBuilder
|
||||
.createCollection(context, child1)
|
||||
.withName("Collection 2")
|
||||
.build();
|
||||
|
||||
//2. One public item, one private, one withdrawn.
|
||||
|
||||
ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Public Test Item")
|
||||
.withIssueDate("2010-10-17")
|
||||
.withAuthor("Smith, Donald")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn Test Item")
|
||||
.withIssueDate("1990-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("ExtraEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private Test Item")
|
||||
.withIssueDate("2010-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.withSubject("ExtraEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
|
||||
// A system admin user browses this endpoint to find the withdrawn or private objects in the system
|
||||
// With a query stating 'Test'
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(adminToken).perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test"))
|
||||
|
||||
//** THEN **
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
|
||||
Matchers.containsInAnyOrder(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Public Test Item"),
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Withdrawn Test Item"),
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Private Test Item")
|
||||
)
|
||||
))
|
||||
.andExpect(jsonPath("$._embedded.facets", Matchers.hasItems(
|
||||
allOf(
|
||||
hasJsonPath("$.name", is("discoverable")),
|
||||
hasJsonPath("$._embedded.values", Matchers.hasItems(
|
||||
allOf(
|
||||
hasJsonPath("$.label", is("true")),
|
||||
hasJsonPath("$.count", is(2))
|
||||
),
|
||||
allOf(
|
||||
hasJsonPath("$.label", is("false")),
|
||||
hasJsonPath("$.count", is(1))
|
||||
)
|
||||
))
|
||||
),
|
||||
allOf(
|
||||
hasJsonPath("$.name", is("withdrawn")),
|
||||
hasJsonPath("$._embedded.values", Matchers.hasItems(
|
||||
allOf(
|
||||
hasJsonPath("$.label", is("true")),
|
||||
hasJsonPath("$.count", is(1))
|
||||
),
|
||||
allOf(
|
||||
hasJsonPath("$.label", is("false")),
|
||||
hasJsonPath("$.count", is(2))
|
||||
)
|
||||
))
|
||||
)
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverSearchObjectsTestForAdministrativeViewWithFilters() throws Exception {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
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();
|
||||
Collection col2 = CollectionBuilder
|
||||
.createCollection(context, child1)
|
||||
.withName("Collection 2")
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Public Test Item")
|
||||
.withIssueDate("2010-10-17")
|
||||
.withAuthor("Smith, Donald")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn Test Item")
|
||||
.withIssueDate("1990-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("ExtraEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
|
||||
ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private Test Item")
|
||||
.withIssueDate("2010-02-13")
|
||||
.withAuthor("Smith, Maria")
|
||||
.withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.withSubject("ExtraEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(adminToken)
|
||||
.perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test")
|
||||
.param("f.withdrawn", "true")
|
||||
)
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
|
||||
Matchers.contains(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Withdrawn Test Item")
|
||||
)
|
||||
))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
|
||||
getClient(adminToken)
|
||||
.perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test")
|
||||
.param("f.withdrawn", "false")
|
||||
)
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
|
||||
Matchers.containsInAnyOrder(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Public Test Item"),
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Private Test Item")
|
||||
)
|
||||
))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
|
||||
getClient(adminToken)
|
||||
.perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test")
|
||||
.param("f.discoverable", "true")
|
||||
)
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
|
||||
Matchers.containsInAnyOrder(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Public Test Item"),
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Withdrawn Test Item")
|
||||
)
|
||||
))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
|
||||
getClient(adminToken)
|
||||
.perform(get("/api/discover/search/objects")
|
||||
.param("configuration", "administrativeView")
|
||||
.param("query", "Test")
|
||||
.param("f.discoverable", "false")
|
||||
)
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.type", is("discover")))
|
||||
.andExpect(jsonPath("$._embedded.searchResult.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
|
||||
Matchers.contains(
|
||||
SearchResultMatcher.matchOnItemName("item", "items", "Private Test Item")
|
||||
)
|
||||
))
|
||||
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ package org.dspace.app.rest;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
@@ -30,8 +31,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dspace.app.rest.builder.CollectionBuilder;
|
||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||
import org.dspace.app.rest.builder.EPersonBuilder;
|
||||
import org.dspace.app.rest.builder.GroupBuilder;
|
||||
import org.dspace.app.rest.builder.ItemBuilder;
|
||||
import org.dspace.app.rest.matcher.EPersonMatcher;
|
||||
import org.dspace.app.rest.matcher.GroupMatcher;
|
||||
import org.dspace.app.rest.matcher.HalMatcher;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.MetadataRest;
|
||||
@@ -43,6 +46,7 @@ import org.dspace.app.rest.test.MetadataPatchSuite;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -310,7 +314,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._links.byEmail", Matchers.notNullValue()))
|
||||
.andExpect(jsonPath("$._links.byName", Matchers.notNullValue()));
|
||||
.andExpect(jsonPath("$._links.byMetadata", Matchers.notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -331,40 +335,40 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail")
|
||||
.param("email", ePerson.getEmail()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$", is(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)));
|
||||
.param("email", ePerson.getEmail()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$", is(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)));
|
||||
|
||||
// it must be case-insensitive
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail")
|
||||
.param("email", ePerson.getEmail().toUpperCase()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$", is(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)));
|
||||
.param("email", ePerson.getEmail().toUpperCase()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$", is(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByEmailUndefined() throws Exception {
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail")
|
||||
.param("email", "undefined@undefined.com"))
|
||||
.andExpect(status().isNoContent());
|
||||
.param("email", "undefined@undefined.com"))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByEmailUnprocessable() throws Exception {
|
||||
public void findByEmailMissingParameter() throws Exception {
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail"))
|
||||
.andExpect(status().isBadRequest());
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByName() throws Exception {
|
||||
public void findByMetadataUsingLastName() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John", "Doe")
|
||||
@@ -392,8 +396,8 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
.build();
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byName")
|
||||
.param("q", ePerson.getLastName()))
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", ePerson.getLastName()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder(
|
||||
@@ -405,8 +409,8 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
.andExpect(jsonPath("$.page.totalElements", is(4)));
|
||||
|
||||
// it must be case insensitive
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byName")
|
||||
.param("q", ePerson.getLastName().toLowerCase()))
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", ePerson.getLastName().toLowerCase()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder(
|
||||
@@ -419,19 +423,188 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByNameUndefined() throws Exception {
|
||||
public void findByMetadataUsingFirstName() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John", "Doe")
|
||||
.withEmail("Johndoe@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson2 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Jane", "Smith")
|
||||
.withEmail("janesmith@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson3 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John", "Smith")
|
||||
.withEmail("tomdoe@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson4 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John-Postfix", "Smath")
|
||||
.withEmail("dirkdoepostfix@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson5 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Prefix-John", "Smoth")
|
||||
.withEmail("harrydoeprefix@fake-email.com")
|
||||
.build();
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byName")
|
||||
.param("q", "Doe, John"))
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", ePerson.getFirstName()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson),
|
||||
EPersonMatcher.matchEPersonEntry(ePerson3),
|
||||
EPersonMatcher.matchEPersonEntry(ePerson4),
|
||||
EPersonMatcher.matchEPersonEntry(ePerson5)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(4)));
|
||||
|
||||
// it must be case insensitive
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", ePerson.getFirstName().toLowerCase()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson),
|
||||
EPersonMatcher.matchEPersonEntry(ePerson3),
|
||||
EPersonMatcher.matchEPersonEntry(ePerson4),
|
||||
EPersonMatcher.matchEPersonEntry(ePerson5)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataUsingEmail() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John", "Doe")
|
||||
.withEmail("Johndoe@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson2 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Jane", "Smith")
|
||||
.withEmail("janesmith@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson3 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Tom", "Doe")
|
||||
.withEmail("tomdoe@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson4 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Dirk", "Doe-Postfix")
|
||||
.withEmail("dirkdoepostfix@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson5 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Harry", "Prefix-Doe")
|
||||
.withEmail("harrydoeprefix@fake-email.com")
|
||||
.build();
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", ePerson.getEmail()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.contains(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||
|
||||
// it must be case insensitive
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", ePerson.getEmail().toLowerCase()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.contains(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataUsingUuid() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John", "Doe")
|
||||
.withEmail("Johndoe@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson2 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Jane", "Smith")
|
||||
.withEmail("janesmith@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson3 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Tom", "Doe")
|
||||
.withEmail("tomdoe@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson4 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Dirk", "Doe-Postfix")
|
||||
.withEmail("dirkdoepostfix@fake-email.com")
|
||||
.build();
|
||||
|
||||
EPerson ePerson5 = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("Harry", "Prefix-Doe")
|
||||
.withEmail("harrydoeprefix@fake-email.com")
|
||||
.build();
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", String.valueOf(ePerson.getID())))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.contains(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||
|
||||
// it must be case insensitive
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", String.valueOf(ePerson.getID()).toLowerCase()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.epersons", Matchers.contains(
|
||||
EPersonMatcher.matchEPersonEntry(ePerson)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void findByMetadataUnauthorized() throws Exception {
|
||||
getClient().perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", "Doe, John"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataForbidden() throws Exception {
|
||||
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", "Doe, John"))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataUndefined() throws Exception {
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata")
|
||||
.param("query", "Doe, John"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByNameUnprocessable() throws Exception {
|
||||
public void findByMetadataMissingParameter() throws Exception {
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byName"))
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/search/byMetadata"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@@ -1321,4 +1494,54 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
new MetadataPatchSuite().runWith(getClient(token), "/api/eperson/epersons/" + ePerson.getID(), expectedStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that epersons/<:uuid>/groups endpoint returns the direct groups of the epersons
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void getDirectEpersonGroups() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withNameInMetadata("John", "Doe")
|
||||
.withEmail("Johndoe@fake-email.com")
|
||||
.withPassword(password)
|
||||
.build();
|
||||
|
||||
Group parentGroup1 = GroupBuilder.createGroup(context)
|
||||
.withName("Test Parent Group 1")
|
||||
.build();
|
||||
|
||||
Group childGroup1 = GroupBuilder.createGroup(context)
|
||||
.withName("Test Child Group 1")
|
||||
.withParent(parentGroup1)
|
||||
.addMember(ePerson)
|
||||
.build();
|
||||
|
||||
Group parentGroup2 = GroupBuilder.createGroup(context)
|
||||
.withName("Test Parent Group 2")
|
||||
.build();
|
||||
|
||||
Group childGroup2 = GroupBuilder.createGroup(context)
|
||||
.withName("Test Child Group 2")
|
||||
.withParent(parentGroup2)
|
||||
.addMember(ePerson)
|
||||
.build();
|
||||
|
||||
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/eperson/epersons/" + ePerson.getID() + "/groups"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$._embedded.groups", containsInAnyOrder(
|
||||
GroupMatcher.matchGroupWithName(childGroup1.getName()),
|
||||
GroupMatcher.matchGroupWithName(childGroup2.getName()))))
|
||||
.andExpect(jsonPath("$._embedded.groups", Matchers.not(
|
||||
containsInAnyOrder(
|
||||
GroupMatcher.matchGroupWithName(parentGroup1.getName()),
|
||||
GroupMatcher.matchGroupWithName(parentGroup2.getName()))))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
|
||||
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;
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static com.jayway.jsonpath.JsonPath.read;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
@@ -27,11 +26,9 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.dspace.app.rest.builder.CollectionBuilder;
|
||||
import org.dspace.app.rest.builder.CommunityBuilder;
|
||||
import org.dspace.app.rest.builder.EPersonBuilder;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -669,15 +668,15 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
.andExpect(status().is(200));
|
||||
|
||||
// a workspaceitem should exist now in the submitter workspace
|
||||
getClient(tokenSubmitter).perform(get("/api/submission/workspaceitems"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.workspaceitems", Matchers.containsInAnyOrder(
|
||||
WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(null, "Workflow Item 1",
|
||||
"2017-10-17"))))
|
||||
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/submission/workspaceitems")))
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||
|
||||
getClient(tokenSubmitter).perform(get("/api/submission/workspaceitems/search/findBySubmitter")
|
||||
.param("uuid", submitter.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.workspaceitems", Matchers.containsInAnyOrder(
|
||||
WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(null, "Workflow Item 1",
|
||||
"2017-10-17"))))
|
||||
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/submission/workspaceitems")))
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -914,12 +913,16 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
|
||||
context.setCurrentUser(submitter);
|
||||
|
||||
//3. a workflow item
|
||||
XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
//3. a claimed task with workflow item in edit step
|
||||
ClaimedTask claimedTask = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
claimedTask.setStepID("editstep");
|
||||
claimedTask.setActionID("editaction");
|
||||
XmlWorkflowItem witem = claimedTask.getWorkflowItem();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -942,7 +945,6 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
// check the new title and untouched values
|
||||
Matchers.is(WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem,
|
||||
"New Title", "2017-10-17", "ExtraEntry"))));
|
||||
;
|
||||
|
||||
// verify that the patch changes have been persisted
|
||||
getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID()))
|
||||
@@ -1039,12 +1041,15 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
|
||||
context.setCurrentUser(submitter);
|
||||
|
||||
//3. a workflow item
|
||||
XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
//3. a claimed task with workflow item in edit step
|
||||
ClaimedTask claimedTask = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
claimedTask.setStepID("editstep");
|
||||
claimedTask.setActionID("editaction");
|
||||
XmlWorkflowItem witem = claimedTask.getWorkflowItem();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -1104,30 +1109,40 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
|
||||
context.setCurrentUser(submitter);
|
||||
|
||||
//3. some workflow items for our test
|
||||
XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
//3. some claimed tasks with workflow items in edit step
|
||||
ClaimedTask claimedTask = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
claimedTask.setStepID("editstep");
|
||||
claimedTask.setActionID("editaction");
|
||||
XmlWorkflowItem witem = claimedTask.getWorkflowItem();
|
||||
|
||||
XmlWorkflowItem witemMultipleSubjects = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withTitle("Workflow Item 2")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("Subject1")
|
||||
.withSubject("Subject2")
|
||||
.withSubject("Subject3")
|
||||
.withSubject("Subject4")
|
||||
.build();
|
||||
ClaimedTask claimedTask2 = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withTitle("Workflow Item 2")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("Subject1")
|
||||
.withSubject("Subject2")
|
||||
.withSubject("Subject3")
|
||||
.withSubject("Subject4")
|
||||
.build();
|
||||
claimedTask2.setStepID("editstep");
|
||||
claimedTask2.setActionID("editaction");
|
||||
XmlWorkflowItem witemMultipleSubjects = claimedTask2.getWorkflowItem();
|
||||
|
||||
XmlWorkflowItem witemWithTitleDateAndSubjects = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withTitle("Workflow Item 3")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("Subject1")
|
||||
.withSubject("Subject2")
|
||||
.withSubject("Subject3")
|
||||
.withSubject("Subject4")
|
||||
.build();
|
||||
ClaimedTask claimedTask3 = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withTitle("Workflow Item 3")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("Subject1")
|
||||
.withSubject("Subject2")
|
||||
.withSubject("Subject3")
|
||||
.withSubject("Subject4")
|
||||
.build();
|
||||
claimedTask3.setStepID("editstep");
|
||||
claimedTask3.setActionID("editaction");
|
||||
XmlWorkflowItem witemWithTitleDateAndSubjects = claimedTask3.getWorkflowItem();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -1294,11 +1309,14 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
|
||||
context.setCurrentUser(submitter);
|
||||
|
||||
//3. some workflow items for our test
|
||||
XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
//3. a claimed task with workflow item in edit step
|
||||
ClaimedTask claimedTask = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withIssueDate("2017-10-17")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
claimedTask.setStepID("editstep");
|
||||
claimedTask.setActionID("editaction");
|
||||
XmlWorkflowItem witem = claimedTask.getWorkflowItem();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -1359,11 +1377,16 @@ public class WorkflowItemRestRepositoryIT extends AbstractControllerIntegrationT
|
||||
|
||||
context.setCurrentUser(submitter);
|
||||
|
||||
//3. some workflow items for our test
|
||||
XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1)
|
||||
.withTitle("Test WorkflowItem")
|
||||
.withIssueDate("2017-10-17")
|
||||
.build();
|
||||
//3. a claimed task with workflow item in edit step
|
||||
ClaimedTask claimedTask = ClaimedTaskBuilder.createClaimedTask(context, col1, eperson)
|
||||
.withTitle("Workflow Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
claimedTask.setStepID("editstep");
|
||||
claimedTask.setActionID("editaction");
|
||||
XmlWorkflowItem witem = claimedTask.getWorkflowItem();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,9 @@
|
||||
*/
|
||||
package org.dspace.app.rest.builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.service.DSpaceObjectService;
|
||||
@@ -107,4 +109,20 @@ public class EPersonBuilder extends AbstractDSpaceObjectBuilder<EPerson> {
|
||||
ePersonService.setPassword(ePerson, password);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static void deleteEPerson(UUID uuid) throws SQLException, IOException {
|
||||
try (Context c = new Context()) {
|
||||
c.turnOffAuthorisationSystem();
|
||||
EPerson ePerson = ePersonService.find(c, uuid);
|
||||
if (ePerson != null) {
|
||||
try {
|
||||
ePersonService.delete(c, ePerson);
|
||||
} catch (AuthorizeException e) {
|
||||
// cannot occur, just wrap it to make the compiler happy
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
c.complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest.builder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
|
@@ -34,7 +34,7 @@ public class GroupMatcher {
|
||||
hasJsonPath("$.name", is(name)),
|
||||
hasJsonPath("$.type", is("group")),
|
||||
hasJsonPath("$._links.self.href", containsString("/api/eperson/groups/")),
|
||||
hasJsonPath("$._links.groups.href", endsWith("/groups"))
|
||||
hasJsonPath("$._links.subgroups.href", endsWith("/subgroups"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ public class GroupMatcher {
|
||||
*/
|
||||
public static Matcher<? super Object> matchFullEmbeds() {
|
||||
return matchEmbeds(
|
||||
"groups[]"
|
||||
"subgroups[]",
|
||||
"epersons[]"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,7 +53,8 @@ public class GroupMatcher {
|
||||
*/
|
||||
public static Matcher<? super Object> matchLinks(UUID uuid) {
|
||||
return HalMatcher.matchLinks(REST_SERVER_URL + "eperson/groups/" + uuid,
|
||||
"groups",
|
||||
"subgroups",
|
||||
"epersons",
|
||||
"self"
|
||||
);
|
||||
}
|
||||
@@ -63,7 +65,8 @@ public class GroupMatcher {
|
||||
hasJsonPath("$.name", is(name)),
|
||||
hasJsonPath("$.type", is("group")),
|
||||
hasJsonPath("$._links.self.href", containsString("/api/eperson/groups/" + uuid.toString())),
|
||||
hasJsonPath("$._links.groups.href", endsWith(uuid.toString() + "/groups"))
|
||||
hasJsonPath("$._links.subgroups.href", endsWith(uuid.toString() + "/subgroups")),
|
||||
hasJsonPath("$._links.epersons.href", endsWith(uuid.toString() + "/epersons"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@ package org.dspace.app.rest.matcher;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath;
|
||||
|
||||
import static org.dspace.app.rest.matcher.HalMatcher.matchEmbeds;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
@@ -21,7 +20,7 @@ import org.hamcrest.Matcher;
|
||||
|
||||
/**
|
||||
* Provide convenient org.hamcrest.Matcher to verify a ResourcePolicyRest json response
|
||||
*
|
||||
*
|
||||
* @author Mykhaylo Boychuk (4science.it)
|
||||
*
|
||||
*/
|
||||
|
@@ -18,7 +18,6 @@ import org.dspace.app.rest.model.WorkflowDefinitionRest;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.state.Workflow;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
|
@@ -18,7 +18,7 @@
|
||||
</xsl:attribute>
|
||||
<metsHdr>
|
||||
<xsl:attribute name="CREATEDATE">
|
||||
<xsl:value-of select="concat(format-date(current-date(), 'yyyy-MM-dd'), 'T' , format-time(current-time(), 'HH:mm:ss'), 'Z')"/>
|
||||
<xsl:value-of select="concat(format-date(current-date(), '[Y0001]-[M02]-[D02]'), 'T' , format-time(current-time(), '[H01]:[m01]:[s01]'), 'Z')"/>
|
||||
</xsl:attribute>
|
||||
<agent ROLE="CUSTODIAN" TYPE="ORGANIZATION">
|
||||
<name><xsl:value-of select="doc:metadata/doc:element[@name='repository']/doc:field[@name='name']/text()" /></name>
|
||||
|
@@ -55,6 +55,7 @@
|
||||
<entry key="workspace" value-ref="workspaceConfiguration" />
|
||||
<entry key="workflow" value-ref="workflowConfiguration" />
|
||||
<entry key="undiscoverable" value-ref="unDiscoverableItems" />
|
||||
<entry key="administrativeView" value-ref="administrativeView" />
|
||||
<entry key="publication" value-ref="publication"/>
|
||||
<entry key="person" value-ref="person"/>
|
||||
<entry key="organization" value-ref="organization"/>
|
||||
@@ -392,6 +393,150 @@
|
||||
<property name="spellCheckEnabled" value="true"/>
|
||||
</bean>
|
||||
|
||||
<!--The configuration settings for discovery of withdrawn and undiscoverable items (admin only) and regular items-->
|
||||
<bean id="administrativeView" class="org.dspace.discovery.configuration.DiscoveryConfiguration" scope="prototype">
|
||||
<!--Which sidebar facets are to be displayed-->
|
||||
<property name="sidebarFacets">
|
||||
<list>
|
||||
<ref bean="searchFilterDiscoverable" />
|
||||
<ref bean="searchFilterWithdrawn" />
|
||||
<ref bean="searchFilterAuthor" />
|
||||
<ref bean="searchFilterSubject" />
|
||||
<ref bean="searchFilterIssued" />
|
||||
<ref bean="searchFilterContentInOriginalBundle"/>
|
||||
<ref bean="searchFilterEntityType"/>
|
||||
</list>
|
||||
</property>
|
||||
<!-- Set TagCloud configuration per discovery configuration -->
|
||||
<property name="tagCloudFacetConfiguration" ref="defaultTagCloudFacetConfiguration"/>
|
||||
<!--The search filters which can be used on the discovery search page-->
|
||||
<property name="searchFilters">
|
||||
<list>
|
||||
<ref bean="searchFilterDiscoverable" />
|
||||
<ref bean="searchFilterWithdrawn" />
|
||||
<ref bean="searchFilterTitle" />
|
||||
<ref bean="searchFilterAuthor" />
|
||||
<ref bean="searchFilterSubject" />
|
||||
<ref bean="searchFilterIssued" />
|
||||
<ref bean="searchFilterContentInOriginalBundle"/>
|
||||
<ref bean="searchFilterFileNameInOriginalBundle" />
|
||||
<ref bean="searchFilterFileDescriptionInOriginalBundle" />
|
||||
<ref bean="searchFilterEntityType"/>
|
||||
<ref bean="searchFilterIsAuthorOfPublicationRelation"/>
|
||||
<ref bean="searchFilterIsProjectOfPublicationRelation"/>
|
||||
<ref bean="searchFilterIsOrgUnitOfPublicationRelation"/>
|
||||
<ref bean="searchFilterIsPublicationOfJournalIssueRelation"/>
|
||||
<ref bean="searchFilterIsJournalOfPublicationRelation"/>
|
||||
</list>
|
||||
</property>
|
||||
<!--The sort filters for the discovery search-->
|
||||
<property name="searchSortConfiguration">
|
||||
<bean class="org.dspace.discovery.configuration.DiscoverySortConfiguration">
|
||||
<!--<property name="defaultSort" ref="sortDateIssued"/>-->
|
||||
<!--DefaultSortOrder can either be desc or asc (desc is default)-->
|
||||
<property name="defaultSortOrder" value="desc"/>
|
||||
<property name="sortFields">
|
||||
<list>
|
||||
<ref bean="sortTitle" />
|
||||
<ref bean="sortDateIssued" />
|
||||
<ref bean="sortDateAccessioned"/>
|
||||
</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-->
|
||||
<value>search.resourcetype:Item</value>
|
||||
</list>
|
||||
</property>
|
||||
<!--The configuration for the recent submissions-->
|
||||
<property name="recentSubmissionConfiguration">
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryRecentSubmissionsConfiguration">
|
||||
<property name="metadataSortField" value="dc.date.accessioned" />
|
||||
<property name="type" value="date"/>
|
||||
<property name="max" value="20"/>
|
||||
<!-- If enabled the collection home page will not display metadata but show a pageable list of recent submissions -->
|
||||
<property name="useAsHomePage" value="false"/>
|
||||
</bean>
|
||||
</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.contributor.author"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
|
||||
<property name="field" value="relationship.type"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
|
||||
<property name="field" value="person.identifier.jobtitle"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
|
||||
<property name="field" value="project.identifier.name"/>
|
||||
<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="dc.title"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
<!-- By default, full text snippets are disabled, as snippets of embargoed/restricted bitstreams
|
||||
may appear in search results when the Item is public. See DS-3498
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
|
||||
<property name="field" value="project.identifier.status"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
|
||||
<property name="field" value="orgunit.identifier.name"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
|
||||
<property name="field" value="orgunit.identifier.description"/>
|
||||
<property name="maxSize" value="250"/>
|
||||
<property name="snippets" value="5"/>
|
||||
</bean>
|
||||
-->
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="moreLikeThisConfiguration">
|
||||
<bean class="org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration">
|
||||
<!--When altering this list also alter the "xmlui.Discovery.RelatedItems.help" key as it describes
|
||||
the metadata fields below-->
|
||||
<property name="similarityMetadataFields">
|
||||
<list>
|
||||
<value>dc.title</value>
|
||||
<value>dc.contributor.author</value>
|
||||
<value>dc.creator</value>
|
||||
<value>dc.subject</value>
|
||||
</list>
|
||||
</property>
|
||||
<!--The minimum number of matching terms across the metadata fields above before an item is found as related -->
|
||||
<property name="minTermFrequency" value="5"/>
|
||||
<!--The maximum number of related items displayed-->
|
||||
<property name="max" value="3"/>
|
||||
<!--The minimum word length below which words will be ignored-->
|
||||
<property name="minWordLength" value="5"/>
|
||||
</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 Homepage specific configuration settings for discovery-->
|
||||
<bean id="homepageConfiguration" class="org.dspace.discovery.configuration.DiscoveryConfiguration" scope="prototype">
|
||||
<!--Which sidebar facets are to be displayed (same as defaultConfiguration above)-->
|
||||
@@ -1313,6 +1458,29 @@
|
||||
</bean>
|
||||
|
||||
<!--Search filter configuration beans-->
|
||||
|
||||
<bean id="searchFilterDiscoverable" class="org.dspace.discovery.configuration.DiscoverySearchFilterFacet">
|
||||
<property name="indexFieldName" value="discoverable"/>
|
||||
<property name="type" value="standard"/>
|
||||
<property name="metadataFields">
|
||||
<list>
|
||||
</list>
|
||||
</property>
|
||||
<property name="isOpenByDefault" value="true"/>
|
||||
<property name="pageSize" value="10"/>
|
||||
</bean>
|
||||
|
||||
<bean id="searchFilterWithdrawn" class="org.dspace.discovery.configuration.DiscoverySearchFilterFacet">
|
||||
<property name="indexFieldName" value="withdrawn"/>
|
||||
<property name="type" value="standard"/>
|
||||
<property name="metadataFields">
|
||||
<list>
|
||||
</list>
|
||||
</property>
|
||||
<property name="isOpenByDefault" value="true"/>
|
||||
<property name="pageSize" value="10"/>
|
||||
</bean>
|
||||
|
||||
<bean id="searchFilterTitle" class="org.dspace.discovery.configuration.DiscoverySearchFilter">
|
||||
<property name="indexFieldName" value="title"/>
|
||||
<property name="metadataFields">
|
||||
|
Reference in New Issue
Block a user