mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 15:03:18 +00:00
Merge branch 'main' into CST-7754
This commit is contained in:
@@ -806,10 +806,11 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.bcel</groupId>
|
||||
<artifactId>bcel</artifactId>
|
||||
<version>6.4.0</version>
|
||||
<version>6.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- required for openaire api integration -->
|
||||
|
@@ -8,8 +8,8 @@
|
||||
package org.dspace.browse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
|
||||
/**
|
||||
@@ -140,21 +140,21 @@ public interface BrowseDAO {
|
||||
public void setAscending(boolean ascending);
|
||||
|
||||
/**
|
||||
* Get the database ID of the container object. The container object will be a
|
||||
* Get the container object. The container object will be a
|
||||
* Community or a Collection.
|
||||
*
|
||||
* @return the database id of the container, or -1 if none is set
|
||||
* @return the container, or null if none is set
|
||||
*/
|
||||
public UUID getContainerID();
|
||||
public DSpaceObject getContainer();
|
||||
|
||||
/**
|
||||
* Set the database id of the container object. This should be the id of a
|
||||
* Community or Collection. This will constrain the results of the browse
|
||||
* to only items or values within items that appear in the given container.
|
||||
* Set the container object. This should be a Community or Collection.
|
||||
* This will constrain the results of the browse to only items or values within items that appear in the given
|
||||
* container and add the related configuration default filters.
|
||||
*
|
||||
* @param containerID community/collection internal ID (UUID)
|
||||
* @param container community/collection
|
||||
*/
|
||||
public void setContainerID(UUID containerID);
|
||||
public void setContainer(DSpaceObject container);
|
||||
|
||||
/**
|
||||
* get the name of the field in which to look for the container id. This is
|
||||
|
@@ -141,12 +141,12 @@ public class BrowseEngine {
|
||||
Collection col = (Collection) scope.getBrowseContainer();
|
||||
dao.setContainerTable("collection2item");
|
||||
dao.setContainerIDField("collection_id");
|
||||
dao.setContainerID(col.getID());
|
||||
dao.setContainer(col);
|
||||
} else if (scope.inCommunity()) {
|
||||
Community com = (Community) scope.getBrowseContainer();
|
||||
dao.setContainerTable("communities2item");
|
||||
dao.setContainerIDField("community_id");
|
||||
dao.setContainerID(com.getID());
|
||||
dao.setContainer(com);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,12 +247,12 @@ public class BrowseEngine {
|
||||
Collection col = (Collection) scope.getBrowseContainer();
|
||||
dao.setContainerTable("collection2item");
|
||||
dao.setContainerIDField("collection_id");
|
||||
dao.setContainerID(col.getID());
|
||||
dao.setContainer(col);
|
||||
} else if (scope.inCommunity()) {
|
||||
Community com = (Community) scope.getBrowseContainer();
|
||||
dao.setContainerTable("communities2item");
|
||||
dao.setContainerIDField("community_id");
|
||||
dao.setContainerID(com.getID());
|
||||
dao.setContainer(com);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,12 +413,12 @@ public class BrowseEngine {
|
||||
Collection col = (Collection) scope.getBrowseContainer();
|
||||
dao.setContainerTable("collection2item");
|
||||
dao.setContainerIDField("collection_id");
|
||||
dao.setContainerID(col.getID());
|
||||
dao.setContainer(col);
|
||||
} else if (scope.inCommunity()) {
|
||||
Community com = (Community) scope.getBrowseContainer();
|
||||
dao.setContainerTable("communities2item");
|
||||
dao.setContainerIDField("community_id");
|
||||
dao.setContainerID(com.getID());
|
||||
dao.setContainer(com);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -13,13 +13,13 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.solr.client.solrj.util.ClientUtils;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.DiscoverFacetField;
|
||||
@@ -31,6 +31,8 @@ import org.dspace.discovery.DiscoverResult.SearchDocument;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.discovery.SearchService;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.discovery.SearchUtils;
|
||||
import org.dspace.discovery.configuration.DiscoveryConfiguration;
|
||||
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
|
||||
import org.dspace.discovery.indexobject.IndexableItem;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
@@ -124,9 +126,9 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
private String containerIDField = null;
|
||||
|
||||
/**
|
||||
* the database id of the container we are constraining to
|
||||
* the container we are constraining to
|
||||
*/
|
||||
private UUID containerID = null;
|
||||
private DSpaceObject container = null;
|
||||
|
||||
/**
|
||||
* the column that we are sorting results by
|
||||
@@ -176,6 +178,7 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
if (sResponse == null) {
|
||||
DiscoverQuery query = new DiscoverQuery();
|
||||
addLocationScopeFilter(query);
|
||||
addDefaultFilterQueries(query);
|
||||
addStatusFilter(query);
|
||||
if (distinct) {
|
||||
DiscoverFacetField dff;
|
||||
@@ -240,15 +243,20 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
}
|
||||
|
||||
private void addLocationScopeFilter(DiscoverQuery query) {
|
||||
if (containerID != null) {
|
||||
if (container != null) {
|
||||
if (containerIDField.startsWith("collection")) {
|
||||
query.addFilterQueries("location.coll:" + containerID);
|
||||
query.addFilterQueries("location.coll:" + container.getID());
|
||||
} else if (containerIDField.startsWith("community")) {
|
||||
query.addFilterQueries("location.comm:" + containerID);
|
||||
query.addFilterQueries("location.comm:" + container.getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addDefaultFilterQueries(DiscoverQuery query) {
|
||||
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(container);
|
||||
discoveryConfiguration.getDefaultFilterQueries().forEach(query::addFilterQueries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doCountQuery() throws BrowseException {
|
||||
DiscoverResult resp = getSolrResponse();
|
||||
@@ -337,6 +345,7 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
throws BrowseException {
|
||||
DiscoverQuery query = new DiscoverQuery();
|
||||
addLocationScopeFilter(query);
|
||||
addDefaultFilterQueries(query);
|
||||
addStatusFilter(query);
|
||||
query.setMaxResults(0);
|
||||
query.addFilterQueries("search.resourcetype:" + IndexableItem.TYPE);
|
||||
@@ -398,8 +407,8 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
* @see org.dspace.browse.BrowseDAO#getContainerID()
|
||||
*/
|
||||
@Override
|
||||
public UUID getContainerID() {
|
||||
return containerID;
|
||||
public DSpaceObject getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -561,8 +570,8 @@ public class SolrBrowseDAO implements BrowseDAO {
|
||||
* @see org.dspace.browse.BrowseDAO#setContainerID(int)
|
||||
*/
|
||||
@Override
|
||||
public void setContainerID(UUID containerID) {
|
||||
this.containerID = containerID;
|
||||
public void setContainer(DSpaceObject container) {
|
||||
this.container = container;
|
||||
|
||||
}
|
||||
|
||||
|
@@ -51,8 +51,14 @@ import org.dspace.content.virtual.VirtualMetadataPopulator;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverResult;
|
||||
import org.dspace.discovery.SearchService;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.discovery.indexobject.IndexableItem;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.harvest.HarvestedItem;
|
||||
import org.dspace.harvest.service.HarvestedItemService;
|
||||
@@ -93,6 +99,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
@Autowired(required = true)
|
||||
protected CommunityService communityService;
|
||||
@Autowired(required = true)
|
||||
protected GroupService groupService;
|
||||
@Autowired(required = true)
|
||||
protected AuthorizeService authorizeService;
|
||||
@Autowired(required = true)
|
||||
protected BundleService bundleService;
|
||||
@@ -105,6 +113,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
@Autowired(required = true)
|
||||
protected InstallItemService installItemService;
|
||||
@Autowired(required = true)
|
||||
protected SearchService searchService;
|
||||
@Autowired(required = true)
|
||||
protected ResourcePolicyService resourcePolicyService;
|
||||
@Autowired(required = true)
|
||||
protected CollectionService collectionService;
|
||||
@@ -1065,6 +1075,53 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
return collectionService.canEditBoolean(context, item.getOwningCollection(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all Indexed Items where the current user has edit rights. If the user is an Admin,
|
||||
* this is all Indexed Items. Otherwise, it includes those Items where
|
||||
* an indexed "edit" policy lists either the eperson or one of the eperson's groups
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param discoverQuery
|
||||
* @return discovery search result objects
|
||||
* @throws SQLException if something goes wrong
|
||||
* @throws SearchServiceException if search error
|
||||
*/
|
||||
private DiscoverResult retrieveItemsWithEdit(Context context, DiscoverQuery discoverQuery)
|
||||
throws SQLException, SearchServiceException {
|
||||
EPerson currentUser = context.getCurrentUser();
|
||||
if (!authorizeService.isAdmin(context)) {
|
||||
String userId = currentUser != null ? "e" + currentUser.getID().toString() : "e";
|
||||
Stream<String> groupIds = groupService.allMemberGroupsSet(context, currentUser).stream()
|
||||
.map(group -> "g" + group.getID());
|
||||
String query = Stream.concat(Stream.of(userId), groupIds)
|
||||
.collect(Collectors.joining(" OR ", "edit:(", ")"));
|
||||
discoverQuery.addFilterQueries(query);
|
||||
}
|
||||
return searchService.search(context, discoverQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Item> findItemsWithEdit(Context context, int offset, int limit)
|
||||
throws SQLException, SearchServiceException {
|
||||
DiscoverQuery discoverQuery = new DiscoverQuery();
|
||||
discoverQuery.setDSpaceObjectFilter(IndexableItem.TYPE);
|
||||
discoverQuery.setStart(offset);
|
||||
discoverQuery.setMaxResults(limit);
|
||||
DiscoverResult resp = retrieveItemsWithEdit(context, discoverQuery);
|
||||
return resp.getIndexableObjects().stream()
|
||||
.map(solrItems -> ((IndexableItem) solrItems).getIndexedObject())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countItemsWithEdit(Context context) throws SQLException, SearchServiceException {
|
||||
DiscoverQuery discoverQuery = new DiscoverQuery();
|
||||
discoverQuery.setMaxResults(0);
|
||||
discoverQuery.setDSpaceObjectFilter(IndexableItem.TYPE);
|
||||
DiscoverResult resp = retrieveItemsWithEdit(context, discoverQuery);
|
||||
return (int) resp.getTotalSearchResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the item is an inprogress submission
|
||||
*
|
||||
|
@@ -28,6 +28,7 @@ import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.Thumbnail;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
|
||||
@@ -768,6 +769,27 @@ public interface ItemService
|
||||
*/
|
||||
int countWithdrawnItems(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* finds all items for which the current user has editing rights
|
||||
* @param context DSpace context object
|
||||
* @param offset page offset
|
||||
* @param limit page size limit
|
||||
* @return list of items for which the current user has editing rights
|
||||
* @throws SQLException
|
||||
* @throws SearchServiceException
|
||||
*/
|
||||
public List<Item> findItemsWithEdit(Context context, int offset, int limit)
|
||||
throws SQLException, SearchServiceException;
|
||||
|
||||
/**
|
||||
* counts all items for which the current user has editing rights
|
||||
* @param context DSpace context object
|
||||
* @return list of items for which the current user has editing rights
|
||||
* @throws SQLException
|
||||
* @throws SearchServiceException
|
||||
*/
|
||||
public int countItemsWithEdit(Context context) throws SQLException, SearchServiceException;
|
||||
|
||||
/**
|
||||
* Check if the supplied item is an inprogress submission
|
||||
*
|
||||
|
119
dspace-api/src/main/java/org/dspace/discovery/IndexingUtils.java
Normal file
119
dspace-api/src/main/java/org/dspace/discovery/IndexingUtils.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.discovery;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* Util methods used by indexing.
|
||||
*
|
||||
* @author Koen Pauwels (koen.pauwels at atmire dot com)
|
||||
*/
|
||||
public class IndexingUtils {
|
||||
private IndexingUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all ancestor communities of a given community, with the first one being the given community and the
|
||||
* last one being the root.
|
||||
* <p>
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param community Community for which we search the ancestors
|
||||
* @return A list of ancestor communities.
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
static List<Community> getAncestorCommunities(Context context, Community community) throws SQLException {
|
||||
ArrayList<Community> communities = new ArrayList<>();
|
||||
while (community != null) {
|
||||
communities.add(community);
|
||||
community = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(community)
|
||||
.getParentObject(context, community);
|
||||
}
|
||||
return communities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the ids of all groups that have ADMIN rights to the given community, either directly
|
||||
* (through direct resource policy) or indirectly (through a policy on an ancestor community).
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param community Community for which we search the admin group IDs
|
||||
* @return A list of admin group IDs
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
static List<UUID> findTransitiveAdminGroupIds(Context context, Community community) throws SQLException {
|
||||
return getAncestorCommunities(context, community).stream()
|
||||
.filter(parent -> parent.getAdministrators() != null)
|
||||
.map(parent -> parent.getAdministrators().getID())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the ids of all groups that have ADMIN rights to the given collection, either directly
|
||||
* (through direct resource policy) or indirectly (through a policy on its community, or one of
|
||||
* its ancestor communities).
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param collection Collection for which we search the admin group IDs
|
||||
* @return A list of admin group IDs
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
static List<UUID> findTransitiveAdminGroupIds(Context context, Collection collection) throws SQLException {
|
||||
List<UUID> ids = new ArrayList<>();
|
||||
if (collection.getAdministrators() != null) {
|
||||
ids.add(collection.getAdministrators().getID());
|
||||
}
|
||||
for (Community community : collection.getCommunities()) {
|
||||
for (UUID id : findTransitiveAdminGroupIds(context, community)) {
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve group and eperson IDs for all groups and eperson who have _any_ of the given authorizations
|
||||
* on the given DSpaceObject. The resulting IDs are prefixed with "e" in the case of an eperson ID, and "g" in the
|
||||
* case of a group ID.
|
||||
*
|
||||
* @param authService The authentication service
|
||||
* @param context DSpace context object
|
||||
* @param obj DSpaceObject for which we search the admin group IDs
|
||||
* @return A stream of admin group IDs as Strings, prefixed with either "e" or "g", depending on whether it is a
|
||||
* group or eperson ID.
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
static List<String> findDirectlyAuthorizedGroupAndEPersonPrefixedIds(
|
||||
AuthorizeService authService, Context context, DSpaceObject obj, int[] authorizations)
|
||||
throws SQLException {
|
||||
ArrayList<String> prefixedIds = new ArrayList<>();
|
||||
for (int auth : authorizations) {
|
||||
for (ResourcePolicy policy : authService.getPoliciesActionFilter(context, obj, auth)) {
|
||||
String prefixedId = policy.getGroup() == null
|
||||
? "e" + policy.getEPerson().getID()
|
||||
: "g" + policy.getGroup().getID();
|
||||
prefixedIds.add(prefixedId);
|
||||
context.uncacheEntity(policy);
|
||||
}
|
||||
}
|
||||
return prefixedIds;
|
||||
}
|
||||
}
|
@@ -7,16 +7,17 @@
|
||||
*/
|
||||
package org.dspace.discovery;
|
||||
|
||||
import static org.dspace.discovery.IndexingUtils.findDirectlyAuthorizedGroupAndEPersonPrefixedIds;
|
||||
import static org.dspace.discovery.IndexingUtils.findTransitiveAdminGroupIds;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogHelper;
|
||||
@@ -42,29 +43,21 @@ public class SolrServiceIndexCollectionSubmittersPlugin implements SolrServiceIn
|
||||
Collection col = ((IndexableCollection) idxObj).getIndexedObject();
|
||||
if (col != null) {
|
||||
try {
|
||||
String fieldValue = null;
|
||||
Community parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(col)
|
||||
.getParentObject(context, col);
|
||||
while (parent != null) {
|
||||
if (parent.getAdministrators() != null) {
|
||||
fieldValue = "g" + parent.getAdministrators().getID();
|
||||
document.addField("submit", fieldValue);
|
||||
}
|
||||
parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(parent)
|
||||
.getParentObject(context, parent);
|
||||
// Index groups with ADMIN rights on the Collection, on
|
||||
// Communities containing those Collections, and recursively on any Community containing such a
|
||||
// Community.
|
||||
// TODO: Strictly speaking we should also check for epersons who received admin rights directly,
|
||||
// without being part of the admin group. Finding them may be a lot slower though.
|
||||
for (UUID unprefixedId : findTransitiveAdminGroupIds(context, col)) {
|
||||
document.addField("submit", "g" + unprefixedId);
|
||||
}
|
||||
List<ResourcePolicy> policies = authorizeService.getPoliciesActionFilter(context,col,Constants.ADD);
|
||||
policies.addAll(authorizeService.getPoliciesActionFilter(context, col, Constants.ADMIN));
|
||||
|
||||
for (ResourcePolicy resourcePolicy : policies) {
|
||||
if (resourcePolicy.getGroup() != null) {
|
||||
fieldValue = "g" + resourcePolicy.getGroup().getID();
|
||||
} else {
|
||||
fieldValue = "e" + resourcePolicy.getEPerson().getID();
|
||||
|
||||
}
|
||||
document.addField("submit", fieldValue);
|
||||
context.uncacheEntity(resourcePolicy);
|
||||
// Index groups and epersons with ADD or ADMIN rights on the Collection.
|
||||
List<String> prefixedIds = findDirectlyAuthorizedGroupAndEPersonPrefixedIds(
|
||||
authorizeService, context, col, new int[] {Constants.ADD, Constants.ADMIN}
|
||||
);
|
||||
for (String prefixedId : prefixedIds) {
|
||||
document.addField("submit", prefixedId);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(LogHelper.getHeader(context, "Error while indexing resource policies",
|
||||
@@ -73,5 +66,4 @@ public class SolrServiceIndexCollectionSubmittersPlugin implements SolrServiceIn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.discovery;
|
||||
|
||||
import static org.dspace.discovery.IndexingUtils.findDirectlyAuthorizedGroupAndEPersonPrefixedIds;
|
||||
import static org.dspace.discovery.IndexingUtils.findTransitiveAdminGroupIds;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.discovery.indexobject.IndexableItem;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Indexes policies that yield write access to items.
|
||||
*
|
||||
* @author Koen Pauwels at atmire.com
|
||||
*/
|
||||
public class SolrServiceIndexItemEditorsPlugin implements SolrServiceIndexPlugin {
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager
|
||||
.getLogger(SolrServiceIndexItemEditorsPlugin.class);
|
||||
|
||||
@Autowired(required = true)
|
||||
protected AuthorizeService authorizeService;
|
||||
|
||||
@Override
|
||||
public void additionalIndex(Context context, IndexableObject idxObj, SolrInputDocument document) {
|
||||
if (idxObj instanceof IndexableItem) {
|
||||
Item item = ((IndexableItem) idxObj).getIndexedObject();
|
||||
if (item != null) {
|
||||
try {
|
||||
// Index groups with ADMIN rights on Collections containing the Item, on
|
||||
// Communities containing those Collections, and recursively on any Community containing ssuch a
|
||||
// Community.
|
||||
// TODO: Strictly speaking we should also check for epersons who received admin rights directly,
|
||||
// without being part of the admin group. Finding them may be a lot slower though.
|
||||
for (Collection collection : item.getCollections()) {
|
||||
for (UUID unprefixedId : findTransitiveAdminGroupIds(context, collection)) {
|
||||
document.addField("edit", "g" + unprefixedId);
|
||||
}
|
||||
}
|
||||
|
||||
// Index groups and epersons with WRITE or direct ADMIN rights on the Item.
|
||||
List<String> prefixedIds = findDirectlyAuthorizedGroupAndEPersonPrefixedIds(
|
||||
authorizeService, context, item, new int[] {Constants.WRITE, Constants.ADMIN}
|
||||
);
|
||||
for (String prefixedId : prefixedIds) {
|
||||
document.addField("edit", prefixedId);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(LogHelper.getHeader(context, "Error while indexing resource policies",
|
||||
"Item: (id " + item.getID() + " name " + item.getName() + ")" ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,12 +20,15 @@ import java.util.stream.Collectors;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.EntityTypeBuilder;
|
||||
import org.dspace.builder.GroupBuilder;
|
||||
import org.dspace.builder.ItemBuilder;
|
||||
import org.dspace.builder.RelationshipBuilder;
|
||||
import org.dspace.builder.RelationshipTypeBuilder;
|
||||
import org.dspace.builder.ResourcePolicyBuilder;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.EntityType;
|
||||
@@ -35,6 +38,8 @@ import org.dspace.content.Relationship;
|
||||
import org.dspace.content.RelationshipType;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.factory.VersionServiceFactory;
|
||||
import org.dspace.versioning.service.VersioningService;
|
||||
@@ -473,6 +478,82 @@ public class ItemServiceTest extends AbstractIntegrationTestWithDatabase {
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindItemsWithEditNoRights() throws Exception {
|
||||
context.setCurrentUser(eperson);
|
||||
List<Item> result = itemService.findItemsWithEdit(context, 0, 10);
|
||||
int count = itemService.countItemsWithEdit(context);
|
||||
assertThat(result.size(), equalTo(0));
|
||||
assertThat(count, equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAndCountItemsWithEditEPerson() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(item)
|
||||
.withAction(Constants.WRITE)
|
||||
.build();
|
||||
context.setCurrentUser(eperson);
|
||||
List<Item> result = itemService.findItemsWithEdit(context, 0, 10);
|
||||
int count = itemService.countItemsWithEdit(context);
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(count, equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAndCountItemsWithAdminEPerson() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(item)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
context.setCurrentUser(eperson);
|
||||
List<Item> result = itemService.findItemsWithEdit(context, 0, 10);
|
||||
int count = itemService.countItemsWithEdit(context);
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(count, equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAndCountItemsWithEditGroup() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Group group = GroupBuilder.createGroup(context)
|
||||
.addMember(eperson)
|
||||
.build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(item)
|
||||
.withAction(Constants.WRITE)
|
||||
.build();
|
||||
context.setCurrentUser(eperson);
|
||||
List<Item> result = itemService.findItemsWithEdit(context, 0, 10);
|
||||
int count = itemService.countItemsWithEdit(context);
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(count, equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAndCountItemsWithAdminGroup() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Group group = GroupBuilder.createGroup(context)
|
||||
.addMember(eperson)
|
||||
.build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(item)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
context.setCurrentUser(eperson);
|
||||
List<Item> result = itemService.findItemsWithEdit(context, 0, 10);
|
||||
int count = itemService.countItemsWithEdit(context);
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(count, equalTo(1));
|
||||
}
|
||||
private void assertMetadataValue(String authorQualifier, String contributorElement, String dcSchema, String value,
|
||||
String authority, int place, MetadataValue metadataValue) {
|
||||
assertThat(metadataValue.getValue(), equalTo(value));
|
||||
|
@@ -13,6 +13,7 @@ import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.RestAddressableModel;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ public interface AuthorizationFeature {
|
||||
* wide feature
|
||||
* @return true if the user associated with the context has access to the feature for the specified object
|
||||
*/
|
||||
boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException;
|
||||
boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException, SearchServiceException;
|
||||
|
||||
/**
|
||||
* Return the name of the feature
|
||||
|
@@ -13,6 +13,7 @@ import java.util.List;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
|
||||
/**
|
||||
* This service provides access to the Authorization Features and check if the feature is allowed or not in a specific
|
||||
@@ -34,7 +35,8 @@ public interface AuthorizationFeatureService {
|
||||
* feature pass the {@link SiteRest} object
|
||||
* @return true if the user associated with the context has access to the feature
|
||||
*/
|
||||
boolean isAuthorized(Context context, AuthorizationFeature feature, BaseObjectRest object) throws SQLException;
|
||||
boolean isAuthorized(Context context, AuthorizationFeature feature, BaseObjectRest object)
|
||||
throws SQLException, SearchServiceException;
|
||||
|
||||
/**
|
||||
* Get all the authorization features defined in the system
|
||||
|
@@ -18,6 +18,7 @@ import org.dspace.app.rest.authorization.AuthorizationFeatureService;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -38,7 +39,7 @@ public class AuthorizationFeatureServiceImpl implements AuthorizationFeatureServ
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, AuthorizationFeature feature, BaseObjectRest object)
|
||||
throws SQLException {
|
||||
throws SQLException, SearchServiceException {
|
||||
if (object == null) {
|
||||
// the authorization interface require that the object is not null
|
||||
return false;
|
||||
|
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = EditItemFeature.NAME,
|
||||
description = "It can be used to verify if a user has rights to edit any item.")
|
||||
public class EditItemFeature implements AuthorizationFeature {
|
||||
public static final String NAME = "canEditItem";
|
||||
@Autowired
|
||||
AuthorizeService authService;
|
||||
@Autowired
|
||||
ItemService itemService;
|
||||
|
||||
@Autowired
|
||||
Utils utils;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException, SearchServiceException {
|
||||
if (object instanceof SiteRest) {
|
||||
return itemService.countItemsWithEdit(context) > 0;
|
||||
} else if (object instanceof ItemRest) {
|
||||
Item item = (Item) utils.getDSpaceAPIObjectFromRest(context, object);
|
||||
return authService.authorizeActionBoolean(context, item, Constants.WRITE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[] {
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME,
|
||||
SiteRest.CATEGORY + "." + SiteRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.CollectionRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = SubmitFeature.NAME,
|
||||
description = "It can be used to verify if a user has rights to submit anything.")
|
||||
public class SubmitFeature implements AuthorizationFeature {
|
||||
public static final String NAME = "canSubmit";
|
||||
|
||||
@Autowired
|
||||
AuthorizeService authService;
|
||||
|
||||
@Autowired
|
||||
CollectionService collectionService;
|
||||
|
||||
@Autowired
|
||||
Utils utils;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException, SearchServiceException {
|
||||
if (object instanceof SiteRest) {
|
||||
// Check whether the user has permission to add to any collection
|
||||
return collectionService.countCollectionsWithSubmit("", context, null) > 0;
|
||||
} else if (object instanceof CollectionRest) {
|
||||
// Check whether the user has permission to add to the given collection
|
||||
Collection collection = (Collection) utils.getDSpaceAPIObjectFromRest(context, object);
|
||||
return authService.authorizeActionBoolean(context, collection, Constants.ADD);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[] {
|
||||
CollectionRest.CATEGORY + "." + CollectionRest.NAME,
|
||||
SiteRest.CATEGORY + "." + SiteRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -31,6 +31,7 @@ import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.slf4j.Logger;
|
||||
@@ -124,7 +125,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
|
||||
// restore the real current user
|
||||
context.restoreContextUser();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
} catch (SQLException | SearchServiceException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
@@ -151,7 +152,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
|
||||
@SearchRestMethod(name = "object")
|
||||
public Page<AuthorizationRest> findByObject(@Parameter(value = "uri", required = true) String uri,
|
||||
@Parameter(value = "eperson") UUID epersonUuid, @Parameter(value = "feature") String featureName,
|
||||
Pageable pageable) throws AuthorizeException, SQLException {
|
||||
Pageable pageable) throws AuthorizeException, SQLException, SearchServiceException {
|
||||
|
||||
Context context = obtainContext();
|
||||
|
||||
@@ -234,7 +235,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
|
||||
Context context,
|
||||
EPerson user,
|
||||
String uri,
|
||||
String featureName) throws SQLException {
|
||||
String featureName) throws SQLException, SearchServiceException {
|
||||
|
||||
BaseObjectRest restObject = utils.getBaseObjectRestFromUri(context, uri);
|
||||
return authorizationsForObject(context, user, featureName, restObject);
|
||||
@@ -244,7 +245,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
|
||||
Context context,
|
||||
EPerson user, String featureName,
|
||||
BaseObjectRest obj)
|
||||
throws SQLException {
|
||||
throws SQLException, SearchServiceException {
|
||||
|
||||
if (obj == null) {
|
||||
return new ArrayList<>();
|
||||
@@ -269,7 +270,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
|
||||
|
||||
private List<Authorization> findByObjectAndFeature(
|
||||
Context context, EPerson user, BaseObjectRest obj, String featureName
|
||||
) throws SQLException {
|
||||
) throws SQLException, SearchServiceException {
|
||||
|
||||
AuthorizationFeature feature = authorizationFeatureService.find(featureName);
|
||||
|
||||
|
@@ -176,6 +176,24 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry")
|
||||
.build();
|
||||
Item withdrawnItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("WithdrawnEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
Item privateItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("PrivateEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -369,6 +387,23 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
.withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item withdrawnItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("WithdrawnEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
Item privateItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("PrivateEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
@@ -407,6 +442,276 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, "zPublic item more", "2017-10-17")
|
||||
)));
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items that correspond with the PrivateEntry subject query
|
||||
getClient().perform(get("/api/discover/browses/subject/items")
|
||||
.param("filterValue", "PrivateEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements because the item is private
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items that correspond with the WithdrawnEntry subject query
|
||||
getClient().perform(get("/api/discover/browses/subject/items")
|
||||
.param("filterValue", "WithdrawnEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements because the item is withdrawn
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBrowseBySubjectItemsWithScope() throws Exception {
|
||||
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. Two public items with the same subject and another public item that contains that same subject, but also
|
||||
// another one
|
||||
// All of the items are readable by an Anonymous user
|
||||
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("zPublic item more")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.withSubject("ExtraEntry").withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item publicItem2 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Public item 2")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item publicItem3 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Public item 3")
|
||||
.withIssueDate("2016-02-14")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item withdrawnItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("WithdrawnEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
Item privateItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("PrivateEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items that correspond with the ExtraEntry subject query
|
||||
getClient().perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "ExtraEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements in collection 2
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items that correspond with the AnotherTest subject query
|
||||
getClient().perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "AnotherTest"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be only two elements, the ones that we've added with the requested subject
|
||||
// in collection 2
|
||||
.andExpect(jsonPath("$.page.totalElements", is(2)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
//Verify that the title of the public and embargoed items are present and sorted descending
|
||||
.andExpect(jsonPath("$._embedded.items", contains(
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14")
|
||||
)));
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items that correspond with the PrivateEntry subject query
|
||||
getClient().perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "PrivateEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements because the item is private
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items that correspond with the WithdrawnEntry subject query
|
||||
getClient().perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "WithdrawnEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements because the item is withdrawn
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBrowseBySubjectItemsWithScopeAsAdmin() throws Exception {
|
||||
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. Two public items with the same subject and another public item that contains that same subject, but also
|
||||
// another one
|
||||
// All of the items are readable by an Anonymous user
|
||||
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("zPublic item more")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.withSubject("ExtraEntry").withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item publicItem2 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Public item 2")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item publicItem3 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Public item 3")
|
||||
.withIssueDate("2016-02-14")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest")
|
||||
.build();
|
||||
|
||||
Item withdrawnItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("WithdrawnEntry")
|
||||
.withdrawn()
|
||||
.build();
|
||||
Item privateItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("AnotherTest").withSubject("TestingForMore")
|
||||
.withSubject("ExtraEntry").withSubject("PrivateEntry")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
|
||||
//** WHEN **
|
||||
//An admin user browses the items that correspond with the ExtraEntry subject query
|
||||
getClient(adminToken).perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "ExtraEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements in collection 2
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
|
||||
//** WHEN **
|
||||
//An admin user browses the items that correspond with the AnotherTest subject query
|
||||
getClient(adminToken).perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "AnotherTest"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be only two elements, the ones that we've added with the requested subject
|
||||
// in collection 2
|
||||
.andExpect(jsonPath("$.page.totalElements", is(2)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
//Verify that the title of the public and embargoed items are present and sorted descending
|
||||
.andExpect(jsonPath("$._embedded.items", contains(
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14")
|
||||
)));
|
||||
|
||||
//** WHEN **
|
||||
//An admin user browses the items that correspond with the PrivateEntry subject query
|
||||
getClient(adminToken).perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "PrivateEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements because the item is private
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
|
||||
//** WHEN **
|
||||
//An admin user browses the items that correspond with the WithdrawnEntry subject query
|
||||
getClient(adminToken).perform(get("/api/discover/browses/subject/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("filterValue", "WithdrawnEntry"))
|
||||
//** THEN **
|
||||
//The status has to be 200
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//We expect there to be no elements because the item is withdrawn
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)))
|
||||
.andExpect(jsonPath("$.page.size", is(20)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -501,6 +806,174 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
.andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf(
|
||||
not(matchMetadata("dc.title", "This is a private item")),
|
||||
not(matchMetadata("dc.title", "Internal publication")))));
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items in the Browse by item endpoint
|
||||
//sorted descending by tile
|
||||
getClient(adminToken).perform(get("/api/discover/browses/title/items")
|
||||
.param("sort", "title,desc"))
|
||||
|
||||
//** THEN **
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(4)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
|
||||
.andExpect(jsonPath("$._embedded.items",
|
||||
contains(ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2,
|
||||
"Public item 2",
|
||||
"2016-02-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1,
|
||||
"Public item 1",
|
||||
"2017-10-17"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(internalItem,
|
||||
"Internal publication",
|
||||
"2016-09-19"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(embargoedItem,
|
||||
"An embargoed publication",
|
||||
"2017-08-10")
|
||||
)))
|
||||
|
||||
//The private and internal items must not be present
|
||||
.andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf(
|
||||
not(matchMetadata("dc.title", "This is a private item")),
|
||||
not(matchMetadata("dc.title", "Internal publication")))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBrowseByTitleItemsWithScope() throws Exception {
|
||||
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. Two public items that are readable by Anonymous
|
||||
Item publicItem1 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Public item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.withSubject("Java").withSubject("Unit Testing")
|
||||
.build();
|
||||
|
||||
Item publicItem2 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Public item 2")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
|
||||
.withSubject("Angular").withSubject("Unit Testing")
|
||||
.build();
|
||||
|
||||
//3. An item that has been made private
|
||||
Item privateItem = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("This is a private item")
|
||||
.withIssueDate("2015-03-12")
|
||||
.withAuthor("Duck, Donald")
|
||||
.withSubject("Cartoons").withSubject("Ducks")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
//4. An item with an item-level embargo
|
||||
Item embargoedItem = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("An embargoed publication")
|
||||
.withIssueDate("2017-08-10")
|
||||
.withAuthor("Mouse, Mickey")
|
||||
.withSubject("Cartoons").withSubject("Mice")
|
||||
.withEmbargoPeriod("12 months")
|
||||
.build();
|
||||
|
||||
//5. An item that is only readable for an internal groups
|
||||
Group internalGroup = GroupBuilder.createGroup(context)
|
||||
.withName("Internal Group")
|
||||
.build();
|
||||
|
||||
Item internalItem = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Internal publication")
|
||||
.withIssueDate("2016-09-19")
|
||||
.withAuthor("Doe, John")
|
||||
.withSubject("Unknown")
|
||||
.withReaderGroup(internalGroup)
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items in the Browse by item endpoint
|
||||
//sorted descending by tile
|
||||
getClient().perform(get("/api/discover/browses/title/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("sort", "title,desc"))
|
||||
|
||||
//** THEN **
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(1)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
|
||||
.andExpect(jsonPath("$._embedded.items",
|
||||
contains(ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2,
|
||||
"Public item 2",
|
||||
"2016-02-13"))))
|
||||
|
||||
//The private and internal items must not be present
|
||||
.andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf(
|
||||
not(matchMetadata("dc.title", "This is a private item")),
|
||||
not(matchMetadata("dc.title", "Internal publication")))));
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
//** WHEN **
|
||||
//An admin user browses the items in the Browse by item endpoint
|
||||
//sorted descending by tile
|
||||
getClient(adminToken).perform(get("/api/discover/browses/title/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("sort", "title,desc"))
|
||||
|
||||
//** THEN **
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(3)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
.andExpect(jsonPath("$._embedded.items", contains(
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2,
|
||||
"Public item 2",
|
||||
"2016-02-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(internalItem,
|
||||
"Internal publication",
|
||||
"2016-09-19"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(embargoedItem,
|
||||
"An embargoed publication",
|
||||
"2017-08-10")
|
||||
|
||||
)))
|
||||
|
||||
|
||||
//The private and internal items must not be present
|
||||
.andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf(
|
||||
not(matchMetadata("dc.title", "This is a private item"))
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -623,6 +1096,18 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
.withIssueDate("2016-01-12")
|
||||
.build();
|
||||
|
||||
Item withdrawnItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withdrawn()
|
||||
.build();
|
||||
|
||||
Item privateItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private item 1")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
@@ -682,6 +1167,159 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item7,
|
||||
"Item 7", "2016-01-12")
|
||||
)));
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
//The next page gives us the last two items
|
||||
getClient(adminToken).perform(get("/api/discover/browses/dateissued/items")
|
||||
.param("sort", "title,asc")
|
||||
.param("size", "5")
|
||||
.param("page", "1"))
|
||||
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
//We expect only the first five items to be present
|
||||
.andExpect(jsonPath("$.page.size", is(5)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(7)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(2)))
|
||||
.andExpect(jsonPath("$.page.number", is(1)))
|
||||
|
||||
//Verify that the title and date of the items match and that they are sorted ascending
|
||||
.andExpect(jsonPath("$._embedded.items",
|
||||
contains(ItemMatcher.matchItemWithTitleAndDateIssued(item6,
|
||||
"Item 6", "2016-01-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item7,
|
||||
"Item 7", "2016-01-12")
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaginationBrowseByDateIssuedItemsWithScope() throws Exception {
|
||||
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. 7 public items that are readable by Anonymous
|
||||
Item item1 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Item 1")
|
||||
.withIssueDate("2017-10-17")
|
||||
.build();
|
||||
|
||||
Item item2 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Item 2")
|
||||
.withIssueDate("2016-02-13")
|
||||
.build();
|
||||
|
||||
Item item3 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Item 3")
|
||||
.withIssueDate("2016-02-12")
|
||||
.build();
|
||||
|
||||
Item item4 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Item 4")
|
||||
.withIssueDate("2016-02-11")
|
||||
.build();
|
||||
|
||||
Item item5 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Item 5")
|
||||
.withIssueDate("2016-02-10")
|
||||
.build();
|
||||
|
||||
Item item6 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Item 6")
|
||||
.withIssueDate("2016-01-13")
|
||||
.build();
|
||||
|
||||
Item item7 = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Item 7")
|
||||
.withIssueDate("2016-01-12")
|
||||
.build();
|
||||
|
||||
Item withdrawnItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Withdrawn item 1")
|
||||
.withIssueDate("2016-02-13")
|
||||
.withdrawn()
|
||||
.build();
|
||||
|
||||
Item privateItem1 = ItemBuilder.createItem(context, col2)
|
||||
.withTitle("Private item 1")
|
||||
.makeUnDiscoverable()
|
||||
.build();
|
||||
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
//** WHEN **
|
||||
//An anonymous user browses the items in the Browse by date issued endpoint
|
||||
//sorted ascending by tile with a page size of 5
|
||||
getClient().perform(get("/api/discover/browses/dateissued/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("sort", "title,asc")
|
||||
.param("size", "5"))
|
||||
|
||||
//** THEN **
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
//We expect only the first five items to be present
|
||||
.andExpect(jsonPath("$.page.size", is(5)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(3)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
|
||||
//Verify that the title and date of the items match and that they are sorted ascending
|
||||
.andExpect(jsonPath("$._embedded.items",
|
||||
contains(
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item2,
|
||||
"Item 2", "2016-02-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item4,
|
||||
"Item 4", "2016-02-11"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item6,
|
||||
"Item 6", "2016-01-13")
|
||||
)));
|
||||
|
||||
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(adminToken).perform(get("/api/discover/browses/dateissued/items")
|
||||
.param("scope", String.valueOf(col2.getID()))
|
||||
.param("sort", "title,asc")
|
||||
.param("size", "5"))
|
||||
|
||||
//** THEN **
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
|
||||
//We expect only the first five items to be present
|
||||
.andExpect(jsonPath("$.page.size", is(5)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(3)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
|
||||
//Verify that the title and date of the items match and that they are sorted ascending
|
||||
.andExpect(jsonPath("$._embedded.items",
|
||||
contains(
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item2,
|
||||
"Item 2", "2016-02-13"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item4,
|
||||
"Item 4", "2016-02-11"),
|
||||
ItemMatcher.matchItemWithTitleAndDateIssued(item6,
|
||||
"Item 6", "2016-01-13")
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* 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.authorization;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.dspace.app.rest.authorization.impl.EditItemFeature;
|
||||
import org.dspace.app.rest.converter.ItemConverter;
|
||||
import org.dspace.app.rest.converter.SiteConverter;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.rest.projection.DefaultProjection;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.GroupBuilder;
|
||||
import org.dspace.builder.ItemBuilder;
|
||||
import org.dspace.builder.ResourcePolicyBuilder;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.Site;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
public class EditItemFeatureIT extends AbstractControllerIntegrationTest {
|
||||
@Autowired
|
||||
private AuthorizationFeatureService authorizationFeatureService;
|
||||
@Autowired
|
||||
private SiteService siteService;
|
||||
@Autowired
|
||||
private ItemConverter itemConverter;
|
||||
@Autowired
|
||||
private SiteConverter siteConverter;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
|
||||
private Group group;
|
||||
private String siteUri;
|
||||
private String epersonToken;
|
||||
private AuthorizationFeature editItemFeature;
|
||||
private Community communityA;
|
||||
|
||||
private Collection collectionA1;
|
||||
private Collection collectionA2;
|
||||
|
||||
private Item itemA1X;
|
||||
private Item itemA2X;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
withSuppressedAuthorization(() -> {
|
||||
communityA = CommunityBuilder.createCommunity(context).withName("Community A").build();
|
||||
collectionA1 = CollectionBuilder.createCollection(context, communityA).withName("Collection A1").build();
|
||||
collectionA2 = CollectionBuilder.createCollection(context, communityA).withName("Collection A2").build();
|
||||
itemA1X = ItemBuilder.createItem(context, collectionA1).withTitle("Item A1X").build();
|
||||
itemA2X = ItemBuilder.createItem(context, collectionA2).withTitle("Item A2X").build();
|
||||
group = GroupBuilder.createGroup(context)
|
||||
.withName("group")
|
||||
.addMember(eperson)
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
editItemFeature = authorizationFeatureService.find(EditItemFeature.NAME);
|
||||
|
||||
Site site = siteService.findSite(context);
|
||||
SiteRest siteRest = siteConverter.convert(site, DefaultProjection.DEFAULT);
|
||||
siteUri = utils.linkToSingleResource(siteRest, "self").getHref();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRights() throws Exception {
|
||||
expectZeroResults(requestSitewideEditItemFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectEPersonWritePolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(itemA1X)
|
||||
.withAction(Constants.WRITE)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(itemA1X));
|
||||
expectZeroResults(requestEditItemFeature(itemA2X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectGroupWritePolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(itemA1X)
|
||||
.withAction(Constants.WRITE)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(itemA1X));
|
||||
expectZeroResults(requestEditItemFeature(itemA2X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectEPersonAdminPolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(itemA1X)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(itemA1X));
|
||||
expectZeroResults(requestEditItemFeature(itemA2X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectGroupAdminPolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(itemA1X)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(itemA1X));
|
||||
expectZeroResults(requestEditItemFeature(itemA2X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonemptyCollectionAdmin() throws Exception {
|
||||
Item item = withSuppressedAuthorization(() -> {
|
||||
Collection col = CollectionBuilder
|
||||
.createCollection(context, communityA)
|
||||
.withName("nonempty collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
return ItemBuilder
|
||||
.createItem(context, col)
|
||||
.withTitle("item in nonempty collection")
|
||||
.build();
|
||||
});
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(item));
|
||||
expectZeroResults(requestEditItemFeature(itemA1X));
|
||||
expectZeroResults(requestEditItemFeature(itemA2X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyCollectionAdmin() throws Exception {
|
||||
withSuppressedAuthorization(() -> {
|
||||
Collection col = CollectionBuilder
|
||||
.createCollection(context, communityA)
|
||||
.withName("nonempty collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
expectZeroResults(requestSitewideEditItemFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithEmptyCollectionAdmin() throws Exception {
|
||||
withSuppressedAuthorization(() -> {
|
||||
Community comm = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains a collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Collection coll = CollectionBuilder
|
||||
.createCollection(context, comm)
|
||||
.withName("This collection contains no items")
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
expectZeroResults(requestSitewideEditItemFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithNonemptyCollectionAdmin() throws Exception {
|
||||
Item item = withSuppressedAuthorization(() -> {
|
||||
Community comm = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains a collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Collection coll = CollectionBuilder
|
||||
.createCollection(context, comm)
|
||||
.withName("This collection contains an item")
|
||||
.build();
|
||||
return ItemBuilder
|
||||
.createItem(context, coll)
|
||||
.withTitle("This is an item")
|
||||
.build();
|
||||
});
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(item));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedCommunitiesWithNonemptyCollectionAdmin() throws Exception {
|
||||
Item item = withSuppressedAuthorization(() -> {
|
||||
Community parent = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("parent community")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Community child = CommunityBuilder
|
||||
.createSubCommunity(context, parent)
|
||||
.withName("child community")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Collection coll = CollectionBuilder
|
||||
.createCollection(context, child)
|
||||
.withName("This collection contains an item")
|
||||
.build();
|
||||
return ItemBuilder
|
||||
.createItem(context, coll)
|
||||
.withTitle("This is an item")
|
||||
.build();
|
||||
});
|
||||
expectSomeResults(requestSitewideEditItemFeature());
|
||||
expectSomeResults(requestEditItemFeature(item));
|
||||
}
|
||||
|
||||
private ResultActions requestSitewideEditItemFeature() throws Exception {
|
||||
return requestEditItemFeature(siteUri);
|
||||
}
|
||||
|
||||
private ResultActions requestEditItemFeature(Item item) throws Exception {
|
||||
return requestEditItemFeature(getItemUri(item));
|
||||
}
|
||||
private ResultActions requestEditItemFeature(String uri) throws Exception {
|
||||
epersonToken = getAuthToken(eperson.getEmail(), password);
|
||||
return getClient(epersonToken).perform(get("/api/authz/authorizations/search/object?")
|
||||
.param("uri", uri)
|
||||
.param("feature", editItemFeature.getName())
|
||||
.param("embed", "feature"));
|
||||
}
|
||||
|
||||
private ResultActions expectSomeResults(ResultActions actions) throws Exception {
|
||||
return actions
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", greaterThan(0)));
|
||||
}
|
||||
|
||||
private ResultActions expectZeroResults(ResultActions actions) throws Exception {
|
||||
return actions
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||
}
|
||||
|
||||
private <T> T withSuppressedAuthorization(Callable<T> fn) throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
T result = fn.call();
|
||||
context.restoreAuthSystemState();
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getItemUri(Item item) {
|
||||
ItemRest itemRest = itemConverter.convert(item, DefaultProjection.DEFAULT);
|
||||
return utils.linkToSingleResource(itemRest, "self").getHref();
|
||||
}
|
||||
}
|
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* 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.authorization;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.dspace.app.rest.authorization.impl.SubmitFeature;
|
||||
import org.dspace.app.rest.converter.CollectionConverter;
|
||||
import org.dspace.app.rest.converter.SiteConverter;
|
||||
import org.dspace.app.rest.model.CollectionRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.rest.projection.DefaultProjection;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.GroupBuilder;
|
||||
import org.dspace.builder.ResourcePolicyBuilder;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Site;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
public class SubmitFeatureIT extends AbstractControllerIntegrationTest {
|
||||
@Autowired
|
||||
private AuthorizationFeatureService authorizationFeatureService;
|
||||
@Autowired
|
||||
private SiteService siteService;
|
||||
@Autowired
|
||||
private CollectionConverter collectionConverter;
|
||||
@Autowired
|
||||
private SiteConverter siteConverter;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
|
||||
private Group group;
|
||||
private String siteUri;
|
||||
private String epersonToken;
|
||||
private AuthorizationFeature submitFeature;
|
||||
private Community communityA;
|
||||
|
||||
private Collection collectionA1;
|
||||
private Collection collectionA2;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
withSuppressedAuthorization(() -> {
|
||||
communityA = CommunityBuilder.createCommunity(context).withName("Community A").build();
|
||||
collectionA1 = CollectionBuilder.createCollection(context, communityA).withName("Collection A1").build();
|
||||
collectionA2 = CollectionBuilder.createCollection(context, communityA).withName("Collection A2").build();
|
||||
group = GroupBuilder.createGroup(context)
|
||||
.withName("group")
|
||||
.addMember(eperson)
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
submitFeature = authorizationFeatureService.find(SubmitFeature.NAME);
|
||||
|
||||
Site site = siteService.findSite(context);
|
||||
SiteRest siteRest = siteConverter.convert(site, DefaultProjection.DEFAULT);
|
||||
siteUri = utils.linkToSingleResource(siteRest, "self").getHref();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRights() throws Exception {
|
||||
expectZeroResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectEPersonAddPolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADD)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectGroupAddPolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADD)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectEPersonAdminPolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectGroupAdminPolicy() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionAdmin() throws Exception {
|
||||
withSuppressedAuthorization(() -> {
|
||||
Collection col = CollectionBuilder
|
||||
.createCollection(context, communityA)
|
||||
.withName("this is another test collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithoutCollectionsAdmin() throws Exception {
|
||||
withSuppressedAuthorization(() -> {
|
||||
Community comm = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains no collections")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
expectZeroResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithCollectionsAdmin() throws Exception {
|
||||
withSuppressedAuthorization(() -> {
|
||||
Community comm = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains a collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Collection coll = CollectionBuilder
|
||||
.createCollection(context, comm)
|
||||
.withName("Contained collection")
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithSubCommunityWithCollectionsAdmin() throws Exception {
|
||||
withSuppressedAuthorization(() -> {
|
||||
Community parent = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains no collections")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Community child = CommunityBuilder
|
||||
.createSubCommunity(context, parent)
|
||||
.withName("This community contains a collection")
|
||||
.build();
|
||||
Collection coll = CollectionBuilder
|
||||
.createCollection(context, child)
|
||||
.withName("Contained collection")
|
||||
.build();
|
||||
return null;
|
||||
});
|
||||
expectSomeResults(requestSitewideSubmitFeature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRightsOnCollection() throws Exception {
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA1)));
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectEPersonAddPolicyOnCollection() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADD)
|
||||
.build();
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(collectionA1)));
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectGroupAddPolicyOnCollection() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADD)
|
||||
.build();
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(collectionA1)));
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectEPersonAdminPolicyOnCollection() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withUser(eperson)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(collectionA1)));
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectGroupAdminPolicyOnCollection() throws Exception {
|
||||
ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context)
|
||||
.withGroup(group)
|
||||
.withDspaceObject(collectionA1)
|
||||
.withAction(Constants.ADMIN)
|
||||
.build();
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(collectionA1)));
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionAdminOnCollection() throws Exception {
|
||||
Collection col = withSuppressedAuthorization(() -> {
|
||||
return CollectionBuilder
|
||||
.createCollection(context, communityA)
|
||||
.withName("this is another test collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
});
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(col)));
|
||||
expectZeroResults(requestSubmitFeature(getCollectionUri(collectionA1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithCollectionsAdminOnCollection() throws Exception {
|
||||
Collection coll = withSuppressedAuthorization(() -> {
|
||||
Community comm = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains a collection")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
return CollectionBuilder
|
||||
.createCollection(context, comm)
|
||||
.withName("Contained collection")
|
||||
.build();
|
||||
});
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(coll)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunityWithSubCommunityWithCollectionsAdminOnCollection() throws Exception {
|
||||
Collection coll = withSuppressedAuthorization(() -> {
|
||||
Community parent = CommunityBuilder
|
||||
.createCommunity(context)
|
||||
.withName("This community contains no collections")
|
||||
.withAdminGroup(eperson)
|
||||
.build();
|
||||
Community child = CommunityBuilder
|
||||
.createSubCommunity(context, parent)
|
||||
.withName("This community contains a collection")
|
||||
.build();
|
||||
return CollectionBuilder
|
||||
.createCollection(context, child)
|
||||
.withName("Contained collection")
|
||||
.build();
|
||||
});
|
||||
expectSomeResults(requestSubmitFeature(getCollectionUri(coll)));
|
||||
}
|
||||
|
||||
private ResultActions requestSitewideSubmitFeature() throws Exception {
|
||||
return requestSubmitFeature(siteUri);
|
||||
}
|
||||
|
||||
private ResultActions requestSubmitFeature(String uri) throws Exception {
|
||||
epersonToken = getAuthToken(eperson.getEmail(), password);
|
||||
return getClient(epersonToken).perform(get("/api/authz/authorizations/search/object?")
|
||||
.param("uri", uri)
|
||||
.param("feature", submitFeature.getName())
|
||||
.param("embed", "feature"));
|
||||
}
|
||||
|
||||
private ResultActions expectSomeResults(ResultActions actions) throws Exception {
|
||||
return actions
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", greaterThan(0)));
|
||||
}
|
||||
|
||||
private ResultActions expectZeroResults(ResultActions actions) throws Exception {
|
||||
return actions
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", is(0)));
|
||||
}
|
||||
|
||||
private <T> T withSuppressedAuthorization(Callable<T> fn) throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
T result = fn.call();
|
||||
context.restoreAuthSystemState();
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getCollectionUri(Collection collection) {
|
||||
CollectionRest collectionRest = collectionConverter.convert(collection, DefaultProjection.DEFAULT);
|
||||
return utils.linkToSingleResource(collectionRest, "self").getHref();
|
||||
}
|
||||
}
|
@@ -31,6 +31,7 @@
|
||||
<bean id="solrServicePrivateItemPlugin" class="org.dspace.discovery.SolrServicePrivateItemPlugin" scope="prototype"/>
|
||||
<bean id="SolrServiceParentObjectIndexingPlugin" class="org.dspace.discovery.SolrServiceParentObjectIndexingPlugin" scope="prototype"/>
|
||||
<bean id="SolrServiceIndexCollectionSubmittersPlugin" class="org.dspace.discovery.SolrServiceIndexCollectionSubmittersPlugin" scope="prototype"/>
|
||||
<bean id="SolrServiceIndexItemEditorsPlugin" class="org.dspace.discovery.SolrServiceIndexItemEditorsPlugin" scope="prototype"/>
|
||||
|
||||
<alias name="solrServiceResourceIndexPlugin" alias="org.dspace.discovery.SolrServiceResourceRestrictionPlugin"/>
|
||||
|
||||
|
@@ -264,6 +264,9 @@
|
||||
<!-- used to track which group(s) have submit permissions -->
|
||||
<field name="submit" type="string" indexed="true" stored="true" omitNorms="true" multiValued="true" docValues="true" />
|
||||
|
||||
<!-- used to track which eperson(s) have edit permissions on items -->
|
||||
<field name="edit" type="string" indexed="true" stored="true" omitNorms="true" multiValued="true" docValues="true" />
|
||||
|
||||
<!-- used to track entity type of collections -->
|
||||
<field name="search.entitytype" type="string" indexed="true" stored="true" required="false" />
|
||||
|
||||
|
Reference in New Issue
Block a user