bulk access controll

This commit is contained in:
Mohamed Saber Eskander
2023-05-11 12:04:20 +03:00
committed by eskander
parent 6b40f2eea6
commit 4e64afbe3b
22 changed files with 1505 additions and 5 deletions

View File

@@ -0,0 +1,456 @@
/**
* 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.bulkaccesscontrol;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.dspace.authorize.ResourcePolicy.TYPE_CUSTOM;
import static org.dspace.authorize.ResourcePolicy.TYPE_INHERITED;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.bulkaccesscontrol.exception.BulkAccessControlException;
import org.dspace.app.bulkaccesscontrol.model.AccessCondition;
import org.dspace.app.bulkaccesscontrol.model.AccessConditionBitstream;
import org.dspace.app.bulkaccesscontrol.model.AccessControl;
import org.dspace.app.bulkaccesscontrol.model.BulkAccessConditionConfiguration;
import org.dspace.app.bulkaccesscontrol.service.BulkAccessConditionConfigurationService;
import org.dspace.app.util.DSpaceObjectUtilsImpl;
import org.dspace.app.util.service.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.Bitstream;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.submit.model.AccessConditionOption;
import org.dspace.util.MultiFormatDateParser;
import org.dspace.utils.DSpace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of {@link DSpaceRunnable} to perform a bulk access control via json file.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*
*/
public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptConfiguration<BulkAccessControl>> {
private static final Logger LOGGER = LoggerFactory.getLogger(BulkAccessControl.class);
private DSpaceObjectUtils dSpaceObjectUtils;
private SearchService searchService;
private IndexObjectFactoryFactory indexObjectServiceFactory;
private CommunityService communityService;
private CollectionService collectionService;
private ConfigurationService configurationService;
private ItemService itemService;
private AuthorizeService authorizeService;
private String filename;
private String[] uuids;
private String [] targetUuids;
private Context context;
private BundleService bundleService;
private BitstreamService bitstreamService;
private BulkAccessConditionConfigurationService bulkAccessConditionConfigurationService;
private ResourcePolicyService resourcePolicyService;
private Map<String, AccessConditionOption> itemAccessConditions;
private Map<String, AccessConditionOption> uploadAccessConditions;
@Override
@SuppressWarnings("unchecked")
public void setup() throws ParseException {
this.searchService = SearchUtils.getSearchService();
this.indexObjectServiceFactory = IndexObjectFactoryFactory.getInstance();
this.communityService = ContentServiceFactory.getInstance().getCommunityService();
this.collectionService = ContentServiceFactory.getInstance().getCollectionService();
this.itemService = ContentServiceFactory.getInstance().getItemService();
this.authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
this.bundleService = ContentServiceFactory.getInstance().getBundleService();
this.bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
this.resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService();
this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
this.bulkAccessConditionConfigurationService = new DSpace().getServiceManager().getServiceByName(
"bulkAccessConditionConfigurationService", BulkAccessConditionConfigurationService.class);
this.dSpaceObjectUtils = new DSpace().getServiceManager().getServiceByName(
DSpaceObjectUtilsImpl.class.getName(), DSpaceObjectUtilsImpl.class);
BulkAccessConditionConfiguration bulkAccessConditionConfiguration =
bulkAccessConditionConfigurationService.getBulkAccessConditionConfiguration("default");
itemAccessConditions = bulkAccessConditionConfiguration
.getItemAccessConditionOptions()
.stream()
.collect(Collectors.toMap(AccessConditionOption::getName, Function.identity()));
uploadAccessConditions = bulkAccessConditionConfiguration
.getBitstreamAccessConditionOptions()
.stream()
.collect(Collectors.toMap(AccessConditionOption::getName, Function.identity()));
filename = commandLine.getOptionValue('f');
uuids = commandLine.getOptionValues('u');
}
@Override
public void internalRun() throws Exception {
ObjectMapper mapper = new ObjectMapper();
AccessControl accessControl;
context = new Context(Context.Mode.BATCH_EDIT);
assignCurrentUserInContext();
assignSpecialGroupsInContext();
context.turnOffAuthorisationSystem();
if (uuids == null) {
handler.logError("A target uuid must be provided (run with -h flag for details)");
throw new IllegalArgumentException("A target uuid must be provided");
} else if (uuids.length <= 0) {
handler.logError("A target uuid must be provided with at least on uuid");
throw new IllegalArgumentException("A target uuid must be provided with at least on uuid");
}
InputStream inputStream = handler.getFileStream(context, filename)
.orElseThrow(() -> new IllegalArgumentException("Error reading file, the file couldn't be "
+ "found for filename: " + filename));
try {
accessControl = mapper.readValue(inputStream, AccessControl.class);
} catch (IOException e) {
handler.logError("Error parsing json file");
throw new IllegalArgumentException("Error parsing json file", e);
}
try {
validate(accessControl);
updateItemsAndBitstreamsPolices(accessControl);
context.complete();
context.restoreAuthSystemState();
} catch (Exception e) {
handler.handleException(e);
context.abort();
}
}
private void validate(AccessControl accessControl) {
if (Objects.isNull(accessControl.getItem()) && Objects.isNull(accessControl.getBitstream())) {
handler.logError("item or bitstream nodes must be provided");
}
if (Objects.nonNull(accessControl.getItem())) {
if (StringUtils.isNotEmpty(accessControl.getItem().getMode()) &&
!(accessControl.getItem().getMode().equals("add") ||
accessControl.getItem().getMode().equals("replace"))) {
handler.logError("wrong value for item mode<" + accessControl.getItem().getMode() + ">");
}
for (AccessCondition accessCondition : accessControl.getItem().getAccessConditions()) {
validateAccessCondition(accessCondition);
}
}
if (Objects.nonNull(accessControl.getBitstream())) {
if (StringUtils.isNotEmpty(accessControl.getBitstream().getMode()) &&
!(accessControl.getBitstream().getMode().equals("add") ||
accessControl.getBitstream().getMode().equals("replace"))) {
handler.logError("wrong value for bitstream mode<" + accessControl.getBitstream().getMode() + ">");
}
for (AccessCondition accessCondition : accessControl.getBitstream().getAccessConditions()) {
validateAccessCondition(accessCondition);
}
}
}
private void validateAccessCondition(AccessCondition accessCondition) {
if (!itemAccessConditions.containsKey(accessCondition.getName())) {
handler.logError("wrong access condition <" + accessCondition.getName() + ">");
throw new IllegalArgumentException("wrong access condition <" + accessCondition.getName() + ">");
}
try {
itemAccessConditions.get(accessCondition.getName()).validateResourcePolicy(
context, accessCondition.getName(), accessCondition.getStartDate(), accessCondition.getEndDate());
} catch (Exception e) {
handler.logError("invalid access condition");
handler.handleException(e);
}
}
public void updateItemsAndBitstreamsPolices(AccessControl accessControl)
throws SQLException, SearchServiceException, AuthorizeException {
int counter = 0;
int start = 0;
int limit = 20;
String query = buildSolrQuery(uuids);
Iterator<Item> itemIterator = findItems(query, start, limit);
while (itemIterator.hasNext()) {
Item item = itemIterator.next();
if (Objects.nonNull(accessControl.getItem())) {
updateItemPolicies(item, accessControl);
}
if (Objects.nonNull(accessControl.getBitstream())) {
updateBitstreamsPolicies(item, accessControl);
}
context.commit();
context.uncacheEntity(item);
counter++;
if (counter == limit) {
start += limit;
itemIterator = findItems(query, start, limit);
}
}
}
private String buildSolrQuery(String[] uuids) throws SQLException {
HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
String [] query = new String[uuids.length];
for (int i = 0 ; i < query.length ; i++) {
DSpaceObject dso = dSpaceObjectUtils.findDSpaceObject(context, UUID.fromString(uuids[i]));
if (dso.getType() == Constants.COMMUNITY) {
query[i] = "location.comm:" + dso.getID();
} else if (dso.getType() == Constants.COLLECTION) {
query[i] = "location.coll:" + dso.getID();
} else if (dso.getType() == Constants.ITEM) {
query[i] = "search.resourceid:" + dso.getID();
}
}
return StringUtils.joinWith(" OR ", query);
}
private Iterator<Item> findItems(String query, int start, int limit)
throws SearchServiceException {
DiscoverQuery discoverQuery = buildDiscoveryQuery(query, start, limit);
return searchService.search(context, discoverQuery)
.getIndexableObjects()
.stream()
.map(indexableObject ->
((IndexableItem) indexableObject).getIndexedObject())
.collect(Collectors.toList())
.iterator();
}
private DiscoverQuery buildDiscoveryQuery(String query, int start, int limit) {
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(IndexableItem.TYPE);
discoverQuery.setQuery(query);
discoverQuery.setStart(start);
discoverQuery.setMaxResults(limit);
return discoverQuery;
}
private void updateItemPolicies(Item item, AccessControl accessControl) throws SQLException, AuthorizeException {
if ("replace".equals(accessControl.getItem().getMode())) {
removeReadPolicies(item, TYPE_CUSTOM);
removeReadPolicies(item, TYPE_INHERITED);
}
setItemPolicies(item, accessControl);
}
private void setItemPolicies(Item item, AccessControl accessControl) throws SQLException, AuthorizeException {
if (isAppendModeDisabled() && item.isArchived()) {
// change to add
itemService.adjustItemPolicies(context, item, item.getOwningCollection());
}
accessControl
.getItem()
.getAccessConditions()
.forEach(accessCondition -> createResourcePolicy(item, accessCondition,
itemAccessConditions.get(accessCondition.getName())));
}
private void updateBitstreamsPolicies(Item item, AccessControl accessControl) {
if (containsConstraints(accessControl)) {
findMatchedBitstreams(item, accessControl.getBitstream().getConstraint().getUuids())
.forEach(bitstream ->
updateBitstreamPolicies(bitstream, item, accessControl));
} else {
item.getBundles()
.stream()
.flatMap(bundle -> bundle.getBitstreams().stream())
.forEach(bitstream ->
updateBitstreamPolicies(bitstream, item, accessControl));
}
}
private boolean containsConstraints(AccessControl accessControl) {
AccessConditionBitstream controlBitstream = accessControl.getBitstream();
return Objects.nonNull(controlBitstream) &&
Objects.nonNull(controlBitstream.getConstraint()) &&
isNotEmpty(controlBitstream.getConstraint().getUuids());
}
private List<Bitstream> findMatchedBitstreams(Item item, List<String> uuids) {
return item.getBundles().stream()
.flatMap(bundle -> bundle.getBitstreams().stream())
.filter(bitstream -> uuids.contains(bitstream.getID().toString()))
.collect(Collectors.toList());
}
private void updateBitstreamPolicies(Bitstream bitstream, Item item, AccessControl accessControl) {
if ("replace".equals(accessControl.getBitstream().getMode())) {
removeReadPolicies(bitstream, TYPE_CUSTOM);
removeReadPolicies(bitstream, TYPE_INHERITED);
}
try {
setBitstreamPolicies(bitstream, item, accessControl);
} catch (SQLException | AuthorizeException e) {
throw new RuntimeException(e);
}
}
private void removeReadPolicies(DSpaceObject dso, String type) {
try {
resourcePolicyService.removePolicies(context, dso, type, Constants.READ);
} catch (SQLException | AuthorizeException e) {
throw new BulkAccessControlException(e);
}
}
private void setBitstreamPolicies(Bitstream bitstream, Item item, AccessControl accessControl)
throws SQLException, AuthorizeException {
if (isAppendModeDisabled() && item.isArchived()) {
itemService.adjustBitstreamPolicies(context, item, item.getOwningCollection(), bitstream);
}
accessControl.getBitstream()
.getAccessConditions()
.forEach(accessCondition -> createResourcePolicy(bitstream, accessCondition,
uploadAccessConditions.get(accessCondition.getName())));
}
private void createResourcePolicy(DSpaceObject obj, AccessCondition accessCondition,
AccessConditionOption AccessConditionOption) {
String name = accessCondition.getName();
String description = accessCondition.getDescription();
Date startDate = accessCondition.getStartDate();
Date endDate = accessCondition.getEndDate();
try {
AccessConditionOption.createResourcePolicy(context, obj, name, description, startDate, endDate);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// private void rollback() {
// try {
// context.rollback();
// } catch (SQLException e) {
// throw new SQLRuntimeException(e);
// }
// }
private void assignCurrentUserInContext() throws SQLException {
UUID uuid = getEpersonIdentifier();
if (uuid != null) {
EPerson ePerson = EPersonServiceFactory.getInstance().getEPersonService().find(context, uuid);
context.setCurrentUser(ePerson);
}
}
private void assignSpecialGroupsInContext() throws SQLException {
for (UUID uuid : handler.getSpecialGroups()) {
context.setSpecialGroup(uuid);
}
}
private Date parseDate(String date) {
return MultiFormatDateParser.parse(date);
}
private boolean isAppendModeDisabled() {
return !configurationService.getBooleanProperty(
"core.authorization.installitem.inheritance-read.append-mode");
}
@Override
@SuppressWarnings("unchecked")
public BulkAccessControlScriptConfiguration<BulkAccessControl> getScriptConfiguration() {
return new DSpace().getServiceManager()
.getServiceByName("bulk-access-control",BulkAccessControlScriptConfiguration.class);
}
}

View File

@@ -0,0 +1,18 @@
/**
* 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.bulkaccesscontrol;
/**
* Extension of {@link BulkAccessControl} for CLI.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*
*/
public class BulkAccessControlCli extends BulkAccessControl {
}

View File

@@ -0,0 +1,19 @@
/**
* 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.bulkaccesscontrol;
/**
* Extension of {@link BulkAccessControlScriptConfiguration} for CLI.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*
*/
public class BulkAccessControlCliScriptConfiguration<T extends BulkAccessControlCli>
extends BulkAccessControlScriptConfiguration<T> {
}

View File

@@ -0,0 +1,113 @@
/**
* 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.bulkaccesscontrol;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.cli.Options;
import org.dspace.app.util.DSpaceObjectUtilsImpl;
import org.dspace.app.util.service.DSpaceObjectUtils;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceCommandLineParameter;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.utils.DSpace;
/**
* Script configuration for {@link BulkAccessControl}.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*
* @param <T> the {@link BulkAccessControl} type
*/
public class BulkAccessControlScriptConfiguration<T extends BulkAccessControl> extends ScriptConfiguration<T> {
private Class<T> dspaceRunnableClass;
@Override
public boolean isAllowedToExecute(Context context, List<DSpaceCommandLineParameter> commandLineParameters) {
try {
if (Objects.isNull(commandLineParameters)) {
throw new IllegalArgumentException();
} else if (commandLineParameters.stream()
.map(DSpaceCommandLineParameter::getName)
.noneMatch("-u"::equals)) {
throw new IllegalArgumentException();
} else {
List<String> dspaceObjectIDs =
commandLineParameters.stream()
.filter(parameter -> "-u".equals(parameter.getName()))
.map(DSpaceCommandLineParameter::getValue)
.collect(Collectors.toList());
DSpaceObjectUtils dSpaceObjectUtils = new DSpace().getServiceManager().getServiceByName(
DSpaceObjectUtilsImpl.class.getName(), DSpaceObjectUtilsImpl.class);
for (String dspaceObjectID : dspaceObjectIDs) {
DSpaceObject dso = dSpaceObjectUtils.findDSpaceObject(context, UUID.fromString(dspaceObjectID));
if (Objects.isNull(dso)) {
throw new IllegalArgumentException();
}
if (!authorizeService.isAdmin(context, dso)) {
return false;
}
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return true;
}
@Override
public Options getOptions() {
if (options == null) {
Options options = new Options();
options.addOption("u", "target", true, "target uuids of communities/collections/items");
options.getOption("u").setType(String.class);
options.getOption("u").setRequired(true);
options.addOption("f", "file", true, "source json file");
options.getOption("f").setType(InputStream.class);
options.getOption("f").setRequired(true);
options.addOption("h", "help", false, "help");
super.options = options;
}
return options;
}
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
/**
* Generic setter for the dspaceRunnableClass
*
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this
* BulkImportScriptConfiguration
*/
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
}

View File

@@ -0,0 +1,48 @@
/**
* 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.bulkaccesscontrol.exception;
/**
* Exception for errors that occurs during the bulk access control
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*
*/
public class BulkAccessControlException extends RuntimeException {
private static final long serialVersionUID = -74730626862418515L;
/**
* Constructor with error message and cause.
*
* @param message the error message
* @param cause the error cause
*/
public BulkAccessControlException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructor with error message.
*
* @param message the error message
*/
public BulkAccessControlException(String message) {
super(message);
}
/**
* Constructor with error cause.
*
* @param cause the error cause
*/
public BulkAccessControlException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,54 @@
/**
* 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.bulkaccesscontrol.model;
import java.util.Date;
/**
* Class that model the value of ACCESS_CONDITION_CELL
* of sheet BITSTREAM_METADATA of the Bulk import excel.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*/
public class AccessCondition {
private String name;
private String description;
private Date startDate;
private Date endDate;
public AccessCondition() {
}
public AccessCondition(String name, String description, Date startDate, Date endDate) {
this.name = name;
this.description = description;
this.startDate = startDate;
this.endDate = endDate;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Date getStartDate() {
return startDate;
}
public Date getEndDate() {
return endDate;
}
}

View File

@@ -0,0 +1,60 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.bulkaccesscontrol.model;
import java.util.List;
/**
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*/
public class AccessConditionBitstream {
private String mode;
private Constraint constraint;
private List<AccessCondition> accessConditions;
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public Constraint getConstraint() {
return constraint;
}
public void setConstraint(Constraint constraint) {
this.constraint = constraint;
}
public List<AccessCondition> getAccessConditions() {
return accessConditions;
}
public void setAccessConditions(List<AccessCondition> accessConditions) {
this.accessConditions = accessConditions;
}
public class Constraint {
private List<String> uuids;
public List<String> getUuids() {
return uuids;
}
public void setUuids(List<String> uuids) {
this.uuids = uuids;
}
}
}

View File

@@ -0,0 +1,36 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.bulkaccesscontrol.model;
import java.util.List;
/**
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*/
public class AccessConditionItem {
String mode;
List<AccessCondition> accessConditions;
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public List<AccessCondition> getAccessConditions() {
return accessConditions;
}
public void setAccessConditions(List<AccessCondition> accessConditions) {
this.accessConditions = accessConditions;
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.bulkaccesscontrol.model;
public class AccessControl {
AccessConditionItem item;
AccessConditionBitstream bitstream;
public AccessControl() {
}
public AccessControl(AccessConditionItem item,
AccessConditionBitstream bitstream) {
this.item = item;
this.bitstream = bitstream;
}
public AccessConditionItem getItem() {
return item;
}
public void setItem(AccessConditionItem item) {
this.item = item;
}
public AccessConditionBitstream getBitstream() {
return bitstream;
}
public void setBitstream(AccessConditionBitstream bitstream) {
this.bitstream = bitstream;
}
}

View File

@@ -232,6 +232,15 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService {
c.restoreAuthSystemState();
}
@Override
public void removePolicies(Context c, DSpaceObject o, String type, int action)
throws SQLException, AuthorizeException {
resourcePolicyDAO.deleteByDsoAndTypeAndAction(c, o, type, action);
c.turnOffAuthorisationSystem();
contentServiceFactory.getDSpaceObjectService(o).updateLastModified(c, o);
c.restoreAuthSystemState();
}
@Override
public void removeDsoGroupPolicies(Context context, DSpaceObject dso, Group group)
throws SQLException, AuthorizeException {

View File

@@ -39,6 +39,9 @@ public interface ResourcePolicyDAO extends GenericDAO<ResourcePolicy> {
public List<ResourcePolicy> findByDSoAndAction(Context context, DSpaceObject dso, int actionId) throws SQLException;
public void deleteByDsoAndTypeAndAction(Context context, DSpaceObject dSpaceObject, String type, int action)
throws SQLException;
public List<ResourcePolicy> findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action)
throws SQLException;

View File

@@ -103,6 +103,19 @@ public class ResourcePolicyDAOImpl extends AbstractHibernateDAO<ResourcePolicy>
return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1);
}
@Override
public void deleteByDsoAndTypeAndAction(Context context, DSpaceObject dso, String type, int actionId)
throws SQLException {
String queryString = "delete from ResourcePolicy where dSpaceObject.id = :dsoId "
+ "AND rptype = :rptype AND actionId= :actionId";
Query query = createQuery(context, queryString);
query.setParameter("dsoId", dso.getID());
query.setParameter("rptype", type);
query.setParameter("actionId", actionId);
query.executeUpdate();
}
@Override
public List<ResourcePolicy> findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action)
throws SQLException {

View File

@@ -93,6 +93,9 @@ public interface ResourcePolicyService extends DSpaceCRUDService<ResourcePolicy>
public void removePolicies(Context c, DSpaceObject o, String type) throws SQLException, AuthorizeException;
public void removePolicies(Context c, DSpaceObject o, String type, int action)
throws SQLException, AuthorizeException;
public void removeDsoGroupPolicies(Context context, DSpaceObject dso, Group group)
throws SQLException, AuthorizeException;

View File

@@ -940,14 +940,39 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
for (Bitstream bitstream : mybundle.getBitstreams()) {
// if come from InstallItem: remove all submission/workflow policies
authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_SUBMISSION);
authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_WORKFLOW);
addCustomPoliciesNotInPlace(context, bitstream, defaultItemPolicies);
addDefaultPoliciesNotInPlace(context, bitstream, defaultCollectionPolicies);
removeAllPoliciesAndAddDefault(context, bitstream, defaultItemPolicies, defaultCollectionPolicies);
}
}
}
@Override
public void adjustBitstreamPolicies(Context context, Item item, Collection collection , Bitstream bitstream)
throws SQLException, AuthorizeException {
List<ResourcePolicy> defaultCollectionPolicies = authorizeService
.getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ);
List<ResourcePolicy> defaultItemPolicies = authorizeService.findPoliciesByDSOAndType(context, item,
ResourcePolicy.TYPE_CUSTOM);
if (defaultCollectionPolicies.size() < 1) {
throw new SQLException("Collection " + collection.getID()
+ " (" + collection.getHandle() + ")"
+ " has no default bitstream READ policies");
}
// remove all policies from bitstream, add new ones
removeAllPoliciesAndAddDefault(context, bitstream, defaultItemPolicies, defaultCollectionPolicies);
}
private void removeAllPoliciesAndAddDefault(Context context, Bitstream bitstream,
List<ResourcePolicy> defaultItemPolicies,
List<ResourcePolicy> defaultCollectionPolicies)
throws SQLException, AuthorizeException {
authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_SUBMISSION);
authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_WORKFLOW);
addCustomPoliciesNotInPlace(context, bitstream, defaultItemPolicies);
addDefaultPoliciesNotInPlace(context, bitstream, defaultCollectionPolicies);
}
@Override
public void adjustItemPolicies(Context context, Item item, Collection collection)
throws SQLException, AuthorizeException {

View File

@@ -507,6 +507,25 @@ public interface ItemService
public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection)
throws SQLException, AuthorizeException;
/**
* Adjust the Bundle and Bitstream policies to reflect what have been defined
* during the submission/workflow. The temporary SUBMISSION and WORKFLOW
* policies are removed and the policies defined at the item and collection
* level are copied and inherited as appropriate. Custom selected Item policies
* are copied to the bundle/bitstream only if no explicit custom policies were
* already applied to the bundle/bitstream. Collection's policies are inherited
* if there are no other policies defined or if the append mode is defined by
* the configuration via the core.authorization.installitem.inheritance-read.append-mode property
*
* @param context DSpace context object
* @param item Item to adjust policies on
* @param collection Collection
* @throws SQLException If database error
* @throws AuthorizeException If authorization error
*/
public void adjustBitstreamPolicies(Context context, Item item, Collection collection, Bitstream bitstream)
throws SQLException, AuthorizeException;
/**
* Adjust the Item's policies to reflect what have been defined during the

View File

@@ -184,7 +184,7 @@ public class AccessConditionOption {
* @param endDate End date of the resource policy. If {@link #getHasEndDate()}
* returns false, endDate should be null. Otherwise endDate may not be null.
*/
private void validateResourcePolicy(Context context, String name, Date startDate, Date endDate)
public void validateResourcePolicy(Context context, String name, Date startDate, Date endDate)
throws SQLException, AuthorizeException, ParseException {
if (getHasStartDate() && Objects.isNull(startDate)) {
throw new IllegalStateException("The access condition " + getName() + " requires a start date.");

View File

@@ -86,4 +86,9 @@
<property name="dspaceRunnableClass" value="org.dspace.app.itemexport.ItemExportCLI"/>
</bean>
<bean id="bulk-access-control" class="org.dspace.app.bulkaccesscontrol.BulkAccessControlCliScriptConfiguration" primary="true">
<property name="description" value="Bulk access control"/>
<property name="dspaceRunnableClass" value="org.dspace.app.bulkaccesscontrol.BulkAccessControlCli"/>
</bean>
</beans>

View File

@@ -0,0 +1,437 @@
/**
* 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.bulkaccesscontrol;
import static org.dspace.app.matcher.ResourcePolicyMatcher.matches;
import static org.dspace.authorize.ResourcePolicy.TYPE_CUSTOM;
import static org.dspace.core.Constants.READ;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.constraints.AssertTrue;
import org.apache.commons.io.file.PathUtils;
import org.dspace.AbstractIntegrationTestWithDatabase;
import org.dspace.app.launcher.ScriptLauncher;
import org.dspace.app.matcher.ResourcePolicyMatcher;
import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.eperson.Group;
import org.dspace.eperson.GroupTest;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
import org.dspace.matcher.DateMatcher;
import org.dspace.util.MultiFormatDateParser;
import org.dspace.utils.DSpace;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Basic integration testing for the Bulk Access conditions Feature{@link BulkAccessControl}.
*
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
*/
public class BulkAccessControlIT extends AbstractIntegrationTestWithDatabase {
private Path tempDir;
private String tempFilePath;
private Collection collection;
private ItemService itemService = ContentServiceFactory.getInstance().getItemService();
private GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
@Before
@Override
public void setUp() throws Exception {
super.setUp();
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
collection = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection")
.withEntityType("Publication")
.build();
context.restoreAuthSystemState();
tempDir = Files.createTempDirectory("bulkAccessTest");
tempFilePath = tempDir + "/bulk-access.json";
}
@After
@Override
public void destroy() throws Exception {
PathUtils.deleteDirectory(tempDir);
super.destroy();
}
@Test
public void performBulkAccessWithoutRequiredParamTest() throws Exception {
buildJsonFile("");
String[] args = new String[] {"bulk-access-control", "-f", tempFilePath};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
}
@Test
public void performBulkAccessWithEmptyJsonTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = CommunityBuilder.createCommunity(context)
.withName("community")
.build();
Collection collection = CollectionBuilder.createCollection(context, community)
.withName("collection")
.build();
Item item = ItemBuilder.createItem(context, collection).withTitle("title").build();
context.restoreAuthSystemState();
buildJsonFile("");
String[] args = new String[] {"bulk-access-control", "-u", item.getID().toString(), "-f", tempFilePath};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
}
@Test
public void performBulkAccessWithWrongModeOfItemValueTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = CommunityBuilder.createCommunity(context)
.withName("community")
.build();
Collection collection = CollectionBuilder.createCollection(context, community)
.withName("collection")
.build();
Item item = ItemBuilder.createItem(context, collection).build();
context.restoreAuthSystemState();
String json = "{ \"item\": {\n" +
" \"mode\": \"wrong\",\n" +
" \"accessConditions\": [\n" +
" {\n" +
" \"name\": \"openaccess\"\n" +
" }\n" +
" ]\n" +
" }}\n";
buildJsonFile(json);
String[] args = new String[] {"bulk-access-control", "-u", item.getID().toString(), "-f", tempFilePath};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
}
@Test
public void performBulkAccessWithWrongModeOfBitstreamValueTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = CommunityBuilder.createCommunity(context)
.withName("community")
.build();
Collection collection = CollectionBuilder.createCollection(context, community)
.withName("collection")
.build();
Item item = ItemBuilder.createItem(context, collection).build();
context.restoreAuthSystemState();
String json = "{ \"bitstream\": {\n" +
" \"mode\": \"wrong\",\n" +
" \"accessConditions\": [\n" +
" {\n" +
" \"name\": \"openaccess\"\n" +
" }\n" +
" ]\n" +
" }}\n";
buildJsonFile(json);
String[] args = new String[] {"bulk-access-control", "-u", item.getID().toString(), "-f", tempFilePath};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
}
@Test
public void performBulkAccessWithNotFoundAccessConditionNameTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = CommunityBuilder.createCommunity(context)
.withName("community")
.build();
Collection collection = CollectionBuilder.createCollection(context, community)
.withName("collection")
.build();
Item item = ItemBuilder.createItem(context, collection).build();
context.restoreAuthSystemState();
String json = "{ \"item\": {\n" +
" \"mode\": \"add\",\n" +
" \"accessConditions\": [\n" +
" {\n" +
" \"name\": \"wrongAccess\"\n" +
" }\n" +
" ]\n" +
" }}\n";
buildJsonFile(json);
String[] args = new String[] {"bulk-access-control", "-u", item.getID().toString(), "-f", tempFilePath};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
context.restoreAuthSystemState();
}
@Test
public void performBulkAccessWithInvalidAccessConditionDateTest() throws Exception {
context.turnOffAuthorisationSystem();
Community community = CommunityBuilder.createCommunity(context)
.withName("community")
.build();
Collection collection = CollectionBuilder.createCollection(context, community)
.withName("collection")
.build();
Item item = ItemBuilder.createItem(context, collection).build();
context.restoreAuthSystemState();
String jsonOne = "{ \"item\": {\n" +
" \"mode\": \"add\",\n" +
" \"accessConditions\": [\n" +
" {\n" +
" \"name\": \"embargo\",\n" +
" \"endDate\": \"2024-06-24T23:59:59.999+0000\"\n" +
" }\n" +
" ]\n" +
" }}\n";
buildJsonFile(jsonOne);
String[] args = new String[] {"bulk-access-control", "-u", item.getID().toString(), "-f", tempFilePath};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
String jsonTwo = "{ \"item\": {\n" +
" \"mode\": \"add\",\n" +
" \"accessConditions\": [\n" +
" {\n" +
" \"name\": \"lease\",\n" +
" \"startDate\": \"2024-06-24T23:59:59.999+0000\"\n" +
" }\n" +
" ]\n" +
" }}\n";
buildJsonFile(jsonTwo);
args = new String[] {"bulk-access-control", "-u", item.getID().toString(), "-f", tempFilePath};
testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), hasSize(1));
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
}
@Test
public void performBulkAccessWithValidJsonTest() throws Exception {
context.turnOffAuthorisationSystem();
Community parentCommunity = CommunityBuilder.createCommunity(context)
.withName("parent community")
.build();
Community subCommunityOne = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("sub community one")
.build();
Community subCommunityTwo = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("sub community two")
.build();
Community subCommunityThree = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("sub community two")
.build();
Collection collectionOne = CollectionBuilder.createCollection(context, subCommunityOne)
.withName("collection one")
.build();
Collection collectionTwo = CollectionBuilder.createCollection(context, subCommunityTwo)
.withName("collection two")
.build();
Collection collectionThree = CollectionBuilder.createCollection(context, subCommunityThree)
.withName("collection three")
.build();
ItemBuilder.createItem(context, collectionOne).build();
ItemBuilder.createItem(context, collectionTwo).build();
Item itemThree = ItemBuilder.createItem(context, collectionThree).withTitle("item three title").build();
Item itemFour = ItemBuilder.createItem(context, collectionThree).withTitle("item four title").build();
context.restoreAuthSystemState();
String jsonOne = "{ \"item\": {\n" +
" \"mode\": \"replace\",\n" +
" \"accessConditions\": [\n" +
" {\n" +
" \"name\": \"embargo\",\n" +
" \"startDate\": \"2024-06-24T00:00:00.000Z\"\n" +
" }\n" +
" ]\n" +
" }}\n";
buildJsonFile(jsonOne);
String[] args = new String[] {
"bulk-access-control",
"-u", subCommunityOne.getID().toString(),
"-u", collectionTwo.getID().toString(),
"-u", itemThree.getID().toString(),
"-f", tempFilePath
};
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
Iterator<Item> itemIteratorOne = itemService.findByCollection(context, collectionOne);
Iterator<Item> itemIteratorTwo = itemService.findByCollection(context, collectionTwo);
itemThree = context.reloadEntity(itemThree);
itemFour = context.reloadEntity(itemFour);
Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS);
// matchItemsResourcePolicies(itemIteratorOne, anonymousGroup, "embargo", TYPE_CUSTOM, "2024-06-24", null);
// matchItemsResourcePolicies(itemIteratorTwo, anonymousGroup, "embargo", TYPE_CUSTOM, "2024-06-24", null);
// matchItemResourcePolicies(itemThree, anonymousGroup, "embargo", TYPE_CUSTOM, "2024-06-24", null);
assertThat(itemThree.getResourcePolicies(), hasSize(2));
assertThat(itemThree.getResourcePolicies(), containsInAnyOrder(
matches(Constants.READ, anonymousGroup, ResourcePolicy.TYPE_INHERITED),
matches(READ, anonymousGroup, "embargo", TYPE_CUSTOM, "2024-06-24T00:00:00.000Z", null, null)
));
// just a note here is working fine
assertThat(itemThree.getResourcePolicies(), hasItem(
matches(READ, anonymousGroup, "embargo", TYPE_CUSTOM,
itemThree.getResourcePolicies().get(0).getStartDate(), null, null)
));
assertThat(itemFour.getResourcePolicies().size(), is(1));
assertThat(itemFour.getResourcePolicies(), hasItem(
matches(Constants.READ, anonymousGroup, ResourcePolicy.TYPE_INHERITED)
));
}
private void matchItemsResourcePolicies(
Iterator<Item> itemIterator, Group group, String rpName, String rpType, String startDate, String endDate) {
while (itemIterator.hasNext()) {
Item item = itemIterator.next();
matchItemResourcePolicies(item, group, rpName, rpType, startDate, endDate);
}
}
private void matchItemResourcePolicies(
Item item, Group group, String rpName, String rpType, String startDate, String endDate) {
assertThat(item.getResourcePolicies(), hasItem(
matches(READ, group, rpName, rpType, startDate, endDate, null)));
}
private void buildJsonFile(String json) throws IOException {
File file = new File(tempDir + "/bulk-access.json");
Path path = Paths.get(file.getAbsolutePath());
Files.writeString(path, json, StandardCharsets.UTF_8);
}
}

View File

@@ -0,0 +1,126 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.matcher;
import static org.dspace.util.MultiFormatDateParser.parse;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import java.util.Date;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
/**
* Implementation of {@link Matcher} to match a ResourcePolicy.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class ResourcePolicyMatcher extends TypeSafeMatcher<ResourcePolicy> {
private final Matcher<Integer> actionId;
private final Matcher<EPerson> ePerson;
private final Matcher<Group> group;
private final Matcher<String> rptype;
private final Matcher<String> rpName;
private final Matcher<String> description;
private final Matcher<Date> startDate;
private final Matcher<Date> endDate;
public ResourcePolicyMatcher(Matcher<Integer> actionId, Matcher<EPerson> ePerson, Matcher<Group> group,
Matcher<String> rpName, Matcher<String> rptype, Matcher<Date> startDate,
Matcher<Date> endDate, Matcher<String> description) {
this.actionId = actionId;
this.ePerson = ePerson;
this.group = group;
this.rptype = rptype;
this.rpName = rpName;
this.description = description;
this.startDate = startDate;
this.endDate = endDate;
}
@Override
public void describeTo(Description description) {
description.appendText("Resource policy with action id ").appendDescriptionOf(actionId)
.appendText(" and EPerson ").appendDescriptionOf(ePerson)
.appendText(" and Group ").appendDescriptionOf(group)
.appendText(" and rpType ").appendDescriptionOf(rptype)
.appendText(" and rpName ").appendDescriptionOf(rpName)
.appendText(" and description ").appendDescriptionOf(this.description)
.appendText(" and start date ").appendDescriptionOf(startDate)
.appendText(" and end date ").appendDescriptionOf(endDate);
}
public static ResourcePolicyMatcher matches(int actionId, EPerson ePerson, String rptype) {
return new ResourcePolicyMatcher(is(actionId), is(ePerson), nullValue(Group.class),
any(String.class), is(rptype), any(Date.class), any(Date.class), any(String.class));
}
public static ResourcePolicyMatcher matches(int actionId, EPerson ePerson, String rpName, String rptype) {
return new ResourcePolicyMatcher(is(actionId), is(ePerson), nullValue(Group.class),
is(rpName), is(rptype), any(Date.class), any(Date.class), any(String.class));
}
public static ResourcePolicyMatcher matches(int actionId, Group group, String rptype) {
return new ResourcePolicyMatcher(is(actionId), nullValue(EPerson.class), is(group),
any(String.class), is(rptype), any(Date.class), any(Date.class), any(String.class));
}
public static ResourcePolicyMatcher matches(int actionId, Group group, String rpName, String rptype) {
return new ResourcePolicyMatcher(is(actionId), nullValue(EPerson.class), is(group), is(rpName),
is(rptype), any(Date.class), any(Date.class), any(String.class));
}
public static ResourcePolicyMatcher matches(int actionId, Group group, String rpName, String rptype,
String description) {
return new ResourcePolicyMatcher(is(actionId), nullValue(EPerson.class), is(group), is(rpName),
is(rptype), any(Date.class), any(Date.class), is(description));
}
public static ResourcePolicyMatcher matches(int actionId, Group group, String rpName, String rpType, Date startDate,
Date endDate, String description) {
return new ResourcePolicyMatcher(is(actionId), nullValue(EPerson.class), is(group), is(rpName),
is(rpType), is(startDate), is(endDate), is(description));
}
public static ResourcePolicyMatcher matches(int actionId, Group group, String rpName, String rpType,
String startDate, String endDate, String description) {
return matches(actionId, group, rpName, rpType, startDate != null ? parse(startDate) : null,
endDate != null ? parse(endDate) : null, description);
}
@Override
protected boolean matchesSafely(ResourcePolicy resourcePolicy) {
return actionId.matches(resourcePolicy.getAction())
&& ePerson.matches(resourcePolicy.getEPerson())
&& group.matches(resourcePolicy.getGroup())
&& rptype.matches(resourcePolicy.getRpType())
&& rpName.matches(resourcePolicy.getRpName())
&& description.matches(resourcePolicy.getRpDescription())
&& startDate.matches(resourcePolicy.getStartDate())
&& endDate.matches(resourcePolicy.getEndDate());
}
private static <T> Matcher<T> any(Class<T> clazz) {
return LambdaMatcher.matches((obj) -> true, "any value");
}
}

View File

@@ -43,4 +43,9 @@
<property name="dspaceRunnableClass" value="org.dspace.app.itemexport.ItemExport"/>
</bean>
<bean id="bulk-access-control" class="org.dspace.app.bulkaccesscontrol.BulkAccessControlScriptConfiguration" primary="true">
<property name="description" value="Bulk access control"/>
<property name="dspaceRunnableClass" value="org.dspace.app.bulkaccesscontrol.BulkAccessControl"/>
</bean>
</beans>

View File

@@ -86,4 +86,9 @@
<property name="dspaceRunnableClass" value="org.dspace.subscriptions.SubscriptionEmailNotificationCli"/>
</bean>
<bean id="bulk-access-control" class="org.dspace.app.bulkaccesscontrol.BulkAccessControlCliScriptConfiguration" primary="true">
<property name="description" value="Bulk access control"/>
<property name="dspaceRunnableClass" value="org.dspace.app.bulkaccesscontrol.BulkAccessControlCli"/>
</bean>
</beans>

View File

@@ -63,4 +63,10 @@
<property name="description" value="Batch Export to Simple Archive Format (SAF)"/>
<property name="dspaceRunnableClass" value="org.dspace.app.itemexport.ItemExport"/>
</bean>
<bean id="bulk-access-control" class="org.dspace.app.bulkaccesscontrol.BulkAccessControlScriptConfiguration" primary="true">
<property name="description" value="Bulk access control"/>
<property name="dspaceRunnableClass" value="org.dspace.app.bulkaccesscontrol.BulkAccessControl"/>
</bean>
</beans>