mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge remote-tracking branch 'upstream/main' into fix-9070-b
# Conflicts: # dspace-api/src/main/java/org/dspace/curate/XmlWorkflowCuratorServiceImpl.java
This commit is contained in:
@@ -769,7 +769,7 @@
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20230227</version>
|
||||
<version>20231013</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Useful for testing command-line tools -->
|
||||
|
@@ -22,9 +22,21 @@ public interface AccessStatusHelper {
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an access status value
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getAccessStatusFromItem(Context context, Item item, Date threshold)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Retrieve embargo information for the item
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to check for embargo information
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an embargo date
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getEmbargoFromItem(Context context, Item item, Date threshold) throws SQLException;
|
||||
}
|
||||
|
@@ -67,4 +67,9 @@ public class AccessStatusServiceImpl implements AccessStatusService {
|
||||
public String getAccessStatus(Context context, Item item) throws SQLException {
|
||||
return helper.getAccessStatusFromItem(context, item, forever_date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmbargoFromItem(Context context, Item item) throws SQLException {
|
||||
return helper.getEmbargoFromItem(context, item, forever_date);
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Default plugin implementation of the access status helper.
|
||||
@@ -33,6 +34,11 @@ import org.dspace.eperson.Group;
|
||||
* calculate the access status of an item based on the policies of
|
||||
* the primary or the first bitstream in the original bundle.
|
||||
* Users can override this method for enhanced functionality.
|
||||
*
|
||||
* The getEmbargoInformationFromItem method provides a simple logic to
|
||||
* * retrieve embargo information of bitstreams from an item based on the policies of
|
||||
* * the primary or the first bitstream in the original bundle.
|
||||
* * Users can override this method for enhanced functionality.
|
||||
*/
|
||||
public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
public static final String EMBARGO = "embargo";
|
||||
@@ -54,12 +60,12 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
|
||||
/**
|
||||
* Look at the item's policies to determine an access status value.
|
||||
* It is also considering a date threshold for embargos and restrictions.
|
||||
* It is also considering a date threshold for embargoes and restrictions.
|
||||
*
|
||||
* If the item is null, simply returns the "unknown" value.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to embargo
|
||||
* @param item the item to check for embargoes
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an access status value
|
||||
*/
|
||||
@@ -86,7 +92,7 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
return caculateAccessStatusForDso(context, bitstream, threshold);
|
||||
return calculateAccessStatusForDso(context, bitstream, threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +110,7 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an access status value
|
||||
*/
|
||||
private String caculateAccessStatusForDso(Context context, DSpaceObject dso, Date threshold)
|
||||
private String calculateAccessStatusForDso(Context context, DSpaceObject dso, Date threshold)
|
||||
throws SQLException {
|
||||
if (dso == null) {
|
||||
return METADATA_ONLY;
|
||||
@@ -156,4 +162,87 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
}
|
||||
return RESTRICTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the policies of the primary (or first) bitstream of the item to retrieve its embargo.
|
||||
*
|
||||
* If the item is null, simply returns an empty map with no embargo information.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to embargo
|
||||
* @return an access status value
|
||||
*/
|
||||
@Override
|
||||
public String getEmbargoFromItem(Context context, Item item, Date threshold)
|
||||
throws SQLException {
|
||||
Date embargoDate;
|
||||
|
||||
// If Item status is not "embargo" then return a null embargo date.
|
||||
String accessStatus = getAccessStatusFromItem(context, item, threshold);
|
||||
|
||||
if (item == null || !accessStatus.equals(EMBARGO)) {
|
||||
return null;
|
||||
}
|
||||
// Consider only the original bundles.
|
||||
List<Bundle> bundles = item.getBundles(Constants.DEFAULT_BUNDLE_NAME);
|
||||
// Check for primary bitstreams first.
|
||||
Bitstream bitstream = bundles.stream()
|
||||
.map(bundle -> bundle.getPrimaryBitstream())
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (bitstream == null) {
|
||||
// If there is no primary bitstream,
|
||||
// take the first bitstream in the bundles.
|
||||
bitstream = bundles.stream()
|
||||
.map(bundle -> bundle.getBitstreams())
|
||||
.flatMap(List::stream)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (bitstream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
embargoDate = this.retrieveShortestEmbargo(context, bitstream);
|
||||
|
||||
return embargoDate != null ? embargoDate.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Date retrieveShortestEmbargo(Context context, Bitstream bitstream) throws SQLException {
|
||||
Date embargoDate = null;
|
||||
// Only consider read policies.
|
||||
List<ResourcePolicy> policies = authorizeService
|
||||
.getPoliciesActionFilter(context, bitstream, Constants.READ);
|
||||
|
||||
// Looks at all read policies.
|
||||
for (ResourcePolicy policy : policies) {
|
||||
boolean isValid = resourcePolicyService.isDateValid(policy);
|
||||
Group group = policy.getGroup();
|
||||
|
||||
if (group != null && StringUtils.equals(group.getName(), Group.ANONYMOUS)) {
|
||||
// Only calculate the status for the anonymous group.
|
||||
if (!isValid) {
|
||||
// If the policy is not valid there is an active embargo
|
||||
Date startDate = policy.getStartDate();
|
||||
|
||||
if (startDate != null && !startDate.before(LocalDate.now().toDate())) {
|
||||
// There is an active embargo: aim to take the shortest embargo (account for rare cases where
|
||||
// more than one resource policy exists)
|
||||
if (embargoDate == null) {
|
||||
embargoDate = startDate;
|
||||
} else {
|
||||
embargoDate = startDate.before(embargoDate) ? startDate : embargoDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return embargoDate;
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,18 @@ public interface AccessStatusService {
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item
|
||||
* @return an access status value
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getAccessStatus(Context context, Item item) throws SQLException;
|
||||
|
||||
/**
|
||||
* Retrieve embargo information for the item
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to check for embargo information
|
||||
* @return an embargo date
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getEmbargoFromItem(Context context, Item item) throws SQLException;
|
||||
}
|
||||
|
@@ -464,7 +464,7 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
|
||||
.forEach(accessCondition -> createResourcePolicy(item, accessCondition,
|
||||
itemAccessConditions.get(accessCondition.getName())));
|
||||
|
||||
itemService.adjustItemPolicies(context, item, item.getOwningCollection());
|
||||
itemService.adjustItemPolicies(context, item, item.getOwningCollection(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -578,6 +578,10 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
wfItem = workflowService.startWithoutNotify(c, wsItem);
|
||||
}
|
||||
} else {
|
||||
// Add provenance info
|
||||
String provenance = installItemService.getSubmittedByProvenanceMessage(c, wsItem.getItem());
|
||||
itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(),
|
||||
"description", "provenance", "en", provenance);
|
||||
// Install the item
|
||||
installItemService.installItem(c, wsItem);
|
||||
}
|
||||
@@ -1363,7 +1367,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
* is the field is defined as authority controlled
|
||||
*/
|
||||
private static boolean isAuthorityControlledField(String md) {
|
||||
String mdf = StringUtils.substringAfter(md, ":");
|
||||
String mdf = md.contains(":") ? StringUtils.substringAfter(md, ":") : md;
|
||||
mdf = StringUtils.substringBefore(mdf, "[");
|
||||
return authorityControlled.contains(mdf);
|
||||
}
|
||||
|
@@ -774,6 +774,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
// put item in system
|
||||
if (!isTest) {
|
||||
try {
|
||||
// Add provenance info
|
||||
String provenance = installItemService.getSubmittedByProvenanceMessage(c, wi.getItem());
|
||||
itemService.addMetadata(c, wi.getItem(), MetadataSchemaEnum.DC.getName(),
|
||||
"description", "provenance", "en", provenance);
|
||||
installItemService.installItem(c, wi, myhandle);
|
||||
} catch (Exception e) {
|
||||
workspaceItemService.deleteAll(c, wi);
|
||||
|
@@ -403,7 +403,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl<Bitstream> imp
|
||||
|
||||
@Override
|
||||
public Bitstream getThumbnail(Context context, Bitstream bitstream) throws SQLException {
|
||||
Pattern pattern = Pattern.compile("^" + bitstream.getName() + ".([^.]+)$");
|
||||
Pattern pattern = getBitstreamNamePattern(bitstream);
|
||||
|
||||
for (Bundle bundle : bitstream.getBundles()) {
|
||||
for (Item item : bundle.getItems()) {
|
||||
@@ -420,6 +420,13 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl<Bitstream> imp
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Pattern getBitstreamNamePattern(Bitstream bitstream) {
|
||||
if (bitstream.getName() != null) {
|
||||
return Pattern.compile("^" + Pattern.quote(bitstream.getName()) + ".([^.]+)$");
|
||||
}
|
||||
return Pattern.compile("^" + bitstream.getName() + ".([^.]+)$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitstreamFormat getFormat(Context context, Bitstream bitstream) throws SQLException {
|
||||
if (bitstream.getBitstreamFormat() == null) {
|
||||
|
@@ -93,7 +93,7 @@ public class InstallItemServiceImpl implements InstallItemService {
|
||||
// As this is a BRAND NEW item, as a final step we need to remove the
|
||||
// submitter item policies created during deposit and replace them with
|
||||
// the default policies from the collection.
|
||||
itemService.inheritCollectionDefaultPolicies(c, item, collection);
|
||||
itemService.inheritCollectionDefaultPolicies(c, item, collection, false);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -271,4 +271,28 @@ public class InstallItemServiceImpl implements InstallItemService {
|
||||
|
||||
return myMessage.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubmittedByProvenanceMessage(Context context, Item item) throws SQLException {
|
||||
// get date
|
||||
DCDate now = DCDate.getCurrent();
|
||||
|
||||
// Create provenance description
|
||||
StringBuffer provmessage = new StringBuffer();
|
||||
|
||||
if (item.getSubmitter() != null) {
|
||||
provmessage.append("Submitted by ").append(item.getSubmitter().getFullName())
|
||||
.append(" (").append(item.getSubmitter().getEmail()).append(") on ")
|
||||
.append(now.toString());
|
||||
} else {
|
||||
// else, null submitter
|
||||
provmessage.append("Submitted by unknown (probably automated) on")
|
||||
.append(now.toString());
|
||||
}
|
||||
provmessage.append("\n");
|
||||
|
||||
// add sizes and checksums of bitstreams
|
||||
provmessage.append(getBitstreamProvenanceMessage(context, item));
|
||||
return provmessage.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -920,8 +920,16 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
@Override
|
||||
public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection)
|
||||
throws SQLException, AuthorizeException {
|
||||
adjustItemPolicies(context, item, collection);
|
||||
adjustBundleBitstreamPolicies(context, item, collection);
|
||||
inheritCollectionDefaultPolicies(context, item, collection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
adjustItemPolicies(context, item, collection, replaceReadRPWithCollectionRP);
|
||||
adjustBundleBitstreamPolicies(context, item, collection, replaceReadRPWithCollectionRP);
|
||||
|
||||
log.debug(LogHelper.getHeader(context, "item_inheritCollectionDefaultPolicies",
|
||||
"item_id=" + item.getID()));
|
||||
@@ -930,6 +938,13 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
@Override
|
||||
public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection)
|
||||
throws SQLException, AuthorizeException {
|
||||
adjustBundleBitstreamPolicies(context, item, collection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException {
|
||||
// Bundles should inherit from DEFAULT_ITEM_READ so that if the item is readable, the files
|
||||
// can be listed (even if they are themselves not readable as per DEFAULT_BITSTREAM_READ or other
|
||||
// policies or embargos applied
|
||||
@@ -948,10 +963,19 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
}
|
||||
// TODO: should we also throw an exception if no DEFAULT_ITEM_READ?
|
||||
|
||||
boolean removeCurrentReadRPBitstream =
|
||||
replaceReadRPWithCollectionRP && defaultCollectionBitstreamPolicies.size() > 0;
|
||||
boolean removeCurrentReadRPBundle =
|
||||
replaceReadRPWithCollectionRP && defaultCollectionBundlePolicies.size() > 0;
|
||||
|
||||
// remove all policies from bundles, add new ones
|
||||
// Remove bundles
|
||||
List<Bundle> bunds = item.getBundles();
|
||||
for (Bundle mybundle : bunds) {
|
||||
// If collection has default READ policies, remove the bundle's READ policies.
|
||||
if (removeCurrentReadRPBundle) {
|
||||
authorizeService.removePoliciesActionFilter(context, mybundle, Constants.READ);
|
||||
}
|
||||
|
||||
// if come from InstallItem: remove all submission/workflow policies
|
||||
authorizeService.removeAllPoliciesByDSOAndType(context, mybundle, ResourcePolicy.TYPE_SUBMISSION);
|
||||
@@ -960,6 +984,11 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
addDefaultPoliciesNotInPlace(context, mybundle, defaultCollectionBundlePolicies);
|
||||
|
||||
for (Bitstream bitstream : mybundle.getBitstreams()) {
|
||||
// If collection has default READ policies, remove the bundle's READ policies.
|
||||
if (removeCurrentReadRPBitstream) {
|
||||
authorizeService.removePoliciesActionFilter(context, bitstream, Constants.READ);
|
||||
}
|
||||
|
||||
// if come from InstallItem: remove all submission/workflow policies
|
||||
removeAllPoliciesAndAddDefault(context, bitstream, defaultItemPolicies,
|
||||
defaultCollectionBitstreamPolicies);
|
||||
@@ -968,7 +997,14 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustBitstreamPolicies(Context context, Item item, Collection collection , Bitstream bitstream)
|
||||
public void adjustBitstreamPolicies(Context context, Item item, Collection collection, Bitstream bitstream)
|
||||
throws SQLException, AuthorizeException {
|
||||
adjustBitstreamPolicies(context, item, collection, bitstream, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustBitstreamPolicies(Context context, Item item, Collection collection , Bitstream bitstream,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException {
|
||||
List<ResourcePolicy> defaultCollectionPolicies = authorizeService
|
||||
.getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ);
|
||||
@@ -998,10 +1034,22 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
@Override
|
||||
public void adjustItemPolicies(Context context, Item item, Collection collection)
|
||||
throws SQLException, AuthorizeException {
|
||||
adjustItemPolicies(context, item, collection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustItemPolicies(Context context, Item item, Collection collection,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException {
|
||||
// read collection's default READ policies
|
||||
List<ResourcePolicy> defaultCollectionPolicies = authorizeService
|
||||
.getPoliciesActionFilter(context, collection, Constants.DEFAULT_ITEM_READ);
|
||||
|
||||
// If collection has defaultREAD policies, remove the item's READ policies.
|
||||
if (replaceReadRPWithCollectionRP && defaultCollectionPolicies.size() > 0) {
|
||||
authorizeService.removePoliciesActionFilter(context, item, Constants.READ);
|
||||
}
|
||||
|
||||
// MUST have default policies
|
||||
if (defaultCollectionPolicies.size() < 1) {
|
||||
throw new SQLException("Collection " + collection.getID()
|
||||
|
@@ -83,4 +83,15 @@ public interface InstallItemService {
|
||||
public String getBitstreamProvenanceMessage(Context context, Item myitem)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Generate provenance description of direct item submission (not through workflow).
|
||||
*
|
||||
* @param context context
|
||||
* @param item the item to generate description for
|
||||
* @return provenance description
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
public String getSubmittedByProvenanceMessage(Context context, Item item)
|
||||
throws SQLException;;
|
||||
|
||||
}
|
||||
|
@@ -473,7 +473,7 @@ public interface ItemService
|
||||
public void removeGroupPolicies(Context context, Item item, Group group) throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* remove all policies on an item and its contents, and replace them with
|
||||
* Remove all policies on an item and its contents, and replace them with
|
||||
* the DEFAULT_ITEM_READ and DEFAULT_BITSTREAM_READ policies belonging to
|
||||
* the collection.
|
||||
*
|
||||
@@ -488,6 +488,26 @@ public interface ItemService
|
||||
public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection)
|
||||
throws java.sql.SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Remove all submission and workflow policies on an item and its contents, and add
|
||||
* default collection policies which are not yet already in place.
|
||||
* If overrideItemReadPolicies is true, then all read policies on the item are replaced (but only if the
|
||||
* collection has a default read policy).
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param item item to reset policies on
|
||||
* @param collection Collection
|
||||
* @param overrideItemReadPolicies if true, all read policies on the item are replaced (but only if the
|
||||
* collection has a default read policy)
|
||||
* @throws SQLException if database error
|
||||
* if an SQL error or if no default policies found. It's a bit
|
||||
* draconian, but default policies must be enforced.
|
||||
* @throws AuthorizeException if authorization error
|
||||
*/
|
||||
public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection,
|
||||
boolean overrideItemReadPolicies)
|
||||
throws java.sql.SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Adjust the Bundle and Bitstream policies to reflect what have been defined
|
||||
* during the submission/workflow. The temporary SUBMISSION and WORKFLOW
|
||||
@@ -507,6 +527,28 @@ 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
|
||||
* @param replaceReadRPWithCollectionRP if true, all read policies on the item are replaced (but only if the
|
||||
* collection has a default read policy)
|
||||
* @throws SQLException If database error
|
||||
* @throws AuthorizeException If authorization error
|
||||
*/
|
||||
public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Adjust the Bitstream policies to reflect what have been defined
|
||||
* during the submission/workflow. The temporary SUBMISSION and WORKFLOW
|
||||
@@ -527,6 +569,29 @@ public interface ItemService
|
||||
public void adjustBitstreamPolicies(Context context, Item item, Collection collection, Bitstream bitstream)
|
||||
throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Adjust the 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 bitstream only if no explicit custom policies were
|
||||
* already applied to the 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
|
||||
* @param bitstream Bitstream to adjust policies on
|
||||
* @param replaceReadRPWithCollectionRP If true, all read policies on the bitstream are replaced (but only if the
|
||||
* collection has a default read policy)
|
||||
* @throws SQLException If database error
|
||||
* @throws AuthorizeException If authorization error
|
||||
*/
|
||||
public void adjustBitstreamPolicies(Context context, Item item, Collection collection, Bitstream bitstream,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException;
|
||||
|
||||
|
||||
/**
|
||||
* Adjust the Item's policies to reflect what have been defined during the
|
||||
@@ -545,6 +610,26 @@ public interface ItemService
|
||||
public void adjustItemPolicies(Context context, Item item, Collection collection)
|
||||
throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Adjust the Item's policies to reflect what have been defined during the
|
||||
* submission/workflow. The temporary SUBMISSION and WORKFLOW policies are
|
||||
* removed and the default policies defined at the collection level are
|
||||
* inherited as appropriate. 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
|
||||
* @param replaceReadRPWithCollectionRP If true, all read policies on the item are replaced (but only if the
|
||||
* collection has a default read policy)
|
||||
* @throws SQLException If database error
|
||||
* @throws AuthorizeException If authorization error
|
||||
*/
|
||||
public void adjustItemPolicies(Context context, Item item, Collection collection,
|
||||
boolean replaceReadRPWithCollectionRP)
|
||||
throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Moves the item from one collection to another one
|
||||
*
|
||||
@@ -790,24 +875,24 @@ 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
|
||||
*/
|
||||
* 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
|
||||
*/
|
||||
* 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;
|
||||
|
||||
/**
|
||||
|
@@ -17,9 +17,12 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.core.service.LicenseService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.web.ContextUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -101,13 +104,14 @@ public class LicenseServiceImpl implements LicenseService {
|
||||
/**
|
||||
* Get the site-wide default license that submitters need to grant
|
||||
*
|
||||
* Localized license requires: default_{{locale}}.license file.
|
||||
* Locale also must be listed in webui.supported.locales setting.
|
||||
*
|
||||
* @return the default license
|
||||
*/
|
||||
@Override
|
||||
public String getDefaultSubmissionLicense() {
|
||||
if (null == license) {
|
||||
init();
|
||||
}
|
||||
init();
|
||||
return license;
|
||||
}
|
||||
|
||||
@@ -115,9 +119,8 @@ public class LicenseServiceImpl implements LicenseService {
|
||||
* Load in the default license.
|
||||
*/
|
||||
protected void init() {
|
||||
File licenseFile = new File(
|
||||
DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir")
|
||||
+ File.separator + "config" + File.separator + "default.license");
|
||||
Context context = obtainContext();
|
||||
File licenseFile = new File(I18nUtil.getDefaultLicense(context));
|
||||
|
||||
FileInputStream fir = null;
|
||||
InputStreamReader ir = null;
|
||||
@@ -169,4 +172,24 @@ public class LicenseServiceImpl implements LicenseService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtaining current request context.
|
||||
* Return new context if getting one from current request failed.
|
||||
*
|
||||
* @return DSpace context object
|
||||
*/
|
||||
private Context obtainContext() {
|
||||
try {
|
||||
Request currentRequest = DSpaceServicesFactory.getInstance().getRequestService().getCurrentRequest();
|
||||
if (currentRequest != null) {
|
||||
HttpServletRequest request = currentRequest.getHttpServletRequest();
|
||||
return ContextUtil.obtainContext(request);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Can't load current request context.");
|
||||
}
|
||||
|
||||
return new Context();
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Collection;
|
||||
@@ -31,6 +32,7 @@ import org.dspace.workflow.CurationTaskConfig;
|
||||
import org.dspace.workflow.FlowStep;
|
||||
import org.dspace.workflow.Task;
|
||||
import org.dspace.workflow.TaskSet;
|
||||
import org.dspace.xmlworkflow.Role;
|
||||
import org.dspace.xmlworkflow.RoleMembers;
|
||||
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
|
||||
@@ -48,14 +50,17 @@ import org.springframework.stereotype.Service;
|
||||
* Manage interactions between curation and workflow. A curation task can be
|
||||
* attached to a workflow step, to be executed during the step.
|
||||
*
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> when run in workflow, curation tasks <em>run with
|
||||
* authorization disabled</em>.
|
||||
*
|
||||
* @see CurationTaskConfig
|
||||
* @author mwood
|
||||
*/
|
||||
@Service
|
||||
public class XmlWorkflowCuratorServiceImpl
|
||||
implements XmlWorkflowCuratorService {
|
||||
private static final Logger LOG
|
||||
= org.apache.logging.log4j.LogManager.getLogger();
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
|
||||
@Autowired(required = true)
|
||||
protected XmlWorkflowFactory workflowFactory;
|
||||
@@ -98,7 +103,18 @@ public class XmlWorkflowCuratorServiceImpl
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
Curator curator = new Curator();
|
||||
curator.setReporter(reporter);
|
||||
return curate(curator, c, wfi);
|
||||
c.turnOffAuthorisationSystem();
|
||||
boolean wasAnonymous = false;
|
||||
if (null == c.getCurrentUser()) { // We need someone to email
|
||||
wasAnonymous = true;
|
||||
c.setCurrentUser(ePersonService.getSystemEPerson(c));
|
||||
}
|
||||
boolean failedP = curate(curator, c, wfi);
|
||||
if (wasAnonymous) {
|
||||
c.setCurrentUser(null);
|
||||
}
|
||||
c.restoreAuthSystemState();
|
||||
return failedP;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,7 +146,7 @@ public class XmlWorkflowCuratorServiceImpl
|
||||
curator.queue(c, item.getID().toString(), step.queue);
|
||||
} else {
|
||||
// Task is configured to be run automatically
|
||||
curator.curate(item);
|
||||
curator.curate(c, item);
|
||||
int status = curator.getStatus(task.name);
|
||||
String result = curator.getResult(task.name);
|
||||
String action = "none";
|
||||
@@ -231,8 +247,12 @@ public class XmlWorkflowCuratorServiceImpl
|
||||
String status, String action, String message)
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
List<EPerson> epa = resolveContacts(c, task.getContacts(status), wfi);
|
||||
if (epa.size() > 0) {
|
||||
if (!epa.isEmpty()) {
|
||||
workflowService.notifyOfCuration(c, wfi, epa, task.name, action, message);
|
||||
} else {
|
||||
LOG.warn("No contacts were found for workflow item {}: "
|
||||
+ "task {} returned action {} with message {}",
|
||||
wfi.getID(), task.name, action, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +275,7 @@ public class XmlWorkflowCuratorServiceImpl
|
||||
// decode contacts
|
||||
if ("$flowgroup".equals(contact)) {
|
||||
// special literal for current flowgoup
|
||||
ClaimedTask claimedTask = claimedTaskService.findByWorkflowIdAndEPerson(c, wfi, c.getCurrentUser());
|
||||
String stepID = claimedTask.getStepID();
|
||||
String stepID = getFlowStep(c, wfi).step;
|
||||
Step step;
|
||||
try {
|
||||
Workflow workflow = workflowFactory.getWorkflow(wfi.getCollection());
|
||||
@@ -266,19 +285,26 @@ public class XmlWorkflowCuratorServiceImpl
|
||||
String.valueOf(wfi.getID()), e);
|
||||
return epList;
|
||||
}
|
||||
RoleMembers roleMembers = step.getRole().getMembers(c, wfi);
|
||||
for (EPerson ep : roleMembers.getEPersons()) {
|
||||
epList.add(ep);
|
||||
}
|
||||
for (Group group : roleMembers.getGroups()) {
|
||||
epList.addAll(group.getMembers());
|
||||
Role role = step.getRole();
|
||||
if (null != role) {
|
||||
RoleMembers roleMembers = role.getMembers(c, wfi);
|
||||
for (EPerson ep : roleMembers.getEPersons()) {
|
||||
epList.add(ep);
|
||||
}
|
||||
for (Group group : roleMembers.getGroups()) {
|
||||
epList.addAll(group.getMembers());
|
||||
}
|
||||
} else {
|
||||
epList.add(ePersonService.getSystemEPerson(c));
|
||||
}
|
||||
} else if ("$colladmin".equals(contact)) {
|
||||
// special literal for collection administrators
|
||||
Group adGroup = wfi.getCollection().getAdministrators();
|
||||
if (adGroup != null) {
|
||||
epList.addAll(groupService.allMembers(c, adGroup));
|
||||
}
|
||||
} else if ("$siteadmin".equals(contact)) {
|
||||
// special literal for site administrator
|
||||
EPerson siteEp = ePersonService.findByEmail(c,
|
||||
configurationService.getProperty("mail.admin"));
|
||||
if (siteEp != null) {
|
||||
|
@@ -42,9 +42,9 @@ public interface XmlWorkflowCuratorService {
|
||||
*
|
||||
* @param c the context
|
||||
* @param wfi the workflow item
|
||||
* @return true if curation was completed or not required,
|
||||
* @return true if curation was completed or not required;
|
||||
* false if tasks were queued for later completion,
|
||||
* or item was rejected
|
||||
* or item was rejected.
|
||||
* @throws AuthorizeException if authorization error
|
||||
* @throws IOException if IO error
|
||||
* @throws SQLException if database error
|
||||
@@ -58,7 +58,9 @@ public interface XmlWorkflowCuratorService {
|
||||
* @param curator the curation context
|
||||
* @param c the user context
|
||||
* @param wfId the workflow item's ID
|
||||
* @return true if curation failed.
|
||||
* @return true if curation curation was completed or not required;
|
||||
* false if tasks were queued for later completion,
|
||||
* or item was rejected.
|
||||
* @throws AuthorizeException if authorization error
|
||||
* @throws IOException if IO error
|
||||
* @throws SQLException if database error
|
||||
@@ -72,7 +74,9 @@ public interface XmlWorkflowCuratorService {
|
||||
* @param curator the curation context
|
||||
* @param c the user context
|
||||
* @param wfi the workflow item
|
||||
* @return true if curation failed.
|
||||
* @return true if workflow curation was completed or not required;
|
||||
* false if tasks were queued for later completion,
|
||||
* or item was rejected.
|
||||
* @throws AuthorizeException if authorization error
|
||||
* @throws IOException if IO error
|
||||
* @throws SQLException if database error
|
||||
|
@@ -47,6 +47,7 @@ import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.orcid.service.OrcidTokenService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.util.UUIDUtils;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersionHistory;
|
||||
@@ -101,6 +102,8 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl<EPerson> impleme
|
||||
protected VersionDAO versionDAO;
|
||||
@Autowired(required = true)
|
||||
protected ClaimedTaskService claimedTaskService;
|
||||
@Autowired(required = true)
|
||||
protected ConfigurationService configurationService;
|
||||
@Autowired
|
||||
protected OrcidTokenService orcidTokenService;
|
||||
|
||||
@@ -113,6 +116,30 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl<EPerson> impleme
|
||||
return ePersonDAO.findByID(context, EPerson.class, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fake EPerson which can receive email. Its address will be the
|
||||
* value of "mail.admin", or "postmaster" if all else fails.
|
||||
* @param c
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public EPerson getSystemEPerson(Context c)
|
||||
throws SQLException {
|
||||
String adminEmail = configurationService.getProperty("mail.admin");
|
||||
if (null == adminEmail) {
|
||||
adminEmail = "postmaster"; // Last-ditch attempt to send *somewhere*
|
||||
}
|
||||
EPerson systemEPerson = findByEmail(c, adminEmail);
|
||||
|
||||
if (null == systemEPerson) {
|
||||
systemEPerson = new EPerson();
|
||||
systemEPerson.setEmail(adminEmail);
|
||||
}
|
||||
|
||||
return systemEPerson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EPerson findByIdOrLegacyId(Context context, String id) throws SQLException {
|
||||
if (StringUtils.isNumeric(id)) {
|
||||
|
@@ -13,6 +13,7 @@ import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Item;
|
||||
@@ -157,6 +158,19 @@ public interface EPersonService extends DSpaceObjectService<EPerson>, DSpaceObje
|
||||
public List<EPerson> findAll(Context context, int sortField, int pageSize, int offset)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* The "System EPerson" is a fake account that exists only to receive email.
|
||||
* It has an email address that should be presumed usable. It does not
|
||||
* exist in the database and is not complete.
|
||||
*
|
||||
* @param context current DSpace session.
|
||||
* @return an EPerson that can presumably receive email.
|
||||
* @throws SQLException
|
||||
*/
|
||||
@NotNull
|
||||
public EPerson getSystemEPerson(Context context)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Create a new eperson
|
||||
*
|
||||
|
@@ -90,13 +90,11 @@ public class HandleDAOImpl extends AbstractHibernateDAO<Handle> implements Handl
|
||||
|
||||
@Override
|
||||
public long countHandlesByPrefix(Context context, String prefix) throws SQLException {
|
||||
|
||||
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Handle.class);
|
||||
|
||||
Root<Handle> handleRoot = criteriaQuery.from(Handle.class);
|
||||
criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(Handle.class)));
|
||||
criteriaQuery.select(handleRoot);
|
||||
criteriaQuery.where(criteriaBuilder.like(handleRoot.get(Handle_.handle), prefix + "%"));
|
||||
return countLong(context, criteriaQuery, criteriaBuilder, handleRoot);
|
||||
}
|
||||
|
@@ -68,10 +68,9 @@ public class HandleIdentifierProvider extends IdentifierProvider {
|
||||
try {
|
||||
String id = mint(context, dso);
|
||||
|
||||
// move canonical to point the latest version
|
||||
// Populate metadata
|
||||
if (dso instanceof Item || dso instanceof Collection || dso instanceof Community) {
|
||||
Item item = (Item) dso;
|
||||
populateHandleMetadata(context, item, id);
|
||||
populateHandleMetadata(context, dso, id);
|
||||
}
|
||||
|
||||
return id;
|
||||
|
@@ -95,11 +95,11 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident
|
||||
String id = mint(context, dso);
|
||||
|
||||
// move canonical to point the latest version
|
||||
if (dso != null && dso.getType() == Constants.ITEM) {
|
||||
if (dso.getType() == Constants.ITEM && dso instanceof Item) {
|
||||
Item item = (Item) dso;
|
||||
VersionHistory history = null;
|
||||
VersionHistory history;
|
||||
try {
|
||||
history = versionHistoryService.findByItem(context, (Item) dso);
|
||||
history = versionHistoryService.findByItem(context, item);
|
||||
} catch (SQLException ex) {
|
||||
throw new RuntimeException("A problem with the database connection occured.", ex);
|
||||
}
|
||||
|
@@ -221,6 +221,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService {
|
||||
//Get our next step, if none is found, archive our item
|
||||
firstStep = wf.getNextStep(context, wfi, firstStep, ActionResult.OUTCOME_COMPLETE);
|
||||
if (firstStep == null) {
|
||||
// record the submitted provenance message
|
||||
recordStart(context, wfi.getItem(),null);
|
||||
archive(context, wfi);
|
||||
} else {
|
||||
activateFirstStep(context, wf, firstStep, wfi);
|
||||
@@ -1187,25 +1189,30 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService {
|
||||
DCDate now = DCDate.getCurrent();
|
||||
|
||||
// Create provenance description
|
||||
String provmessage = "";
|
||||
StringBuffer provmessage = new StringBuffer();
|
||||
|
||||
if (myitem.getSubmitter() != null) {
|
||||
provmessage = "Submitted by " + myitem.getSubmitter().getFullName()
|
||||
+ " (" + myitem.getSubmitter().getEmail() + ") on "
|
||||
+ now.toString() + " workflow start=" + action.getProvenanceStartId() + "\n";
|
||||
provmessage.append("Submitted by ").append(myitem.getSubmitter().getFullName())
|
||||
.append(" (").append(myitem.getSubmitter().getEmail()).append(") on ")
|
||||
.append(now.toString());
|
||||
} else {
|
||||
// else, null submitter
|
||||
provmessage = "Submitted by unknown (probably automated) on"
|
||||
+ now.toString() + " workflow start=" + action.getProvenanceStartId() + "\n";
|
||||
provmessage.append("Submitted by unknown (probably automated) on")
|
||||
.append(now.toString());
|
||||
}
|
||||
if (action != null) {
|
||||
provmessage.append(" workflow start=").append(action.getProvenanceStartId()).append("\n");
|
||||
} else {
|
||||
provmessage.append("\n");
|
||||
}
|
||||
|
||||
// add sizes and checksums of bitstreams
|
||||
provmessage += installItemService.getBitstreamProvenanceMessage(context, myitem);
|
||||
provmessage.append(installItemService.getBitstreamProvenanceMessage(context, myitem));
|
||||
|
||||
// Add message to the DC
|
||||
itemService
|
||||
.addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(),
|
||||
"description", "provenance", "en", provmessage);
|
||||
"description", "provenance", "en", provmessage.toString());
|
||||
itemService.update(context, myitem);
|
||||
}
|
||||
|
||||
|
@@ -1,9 +0,0 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
ALTER TABLE process MODIFY (parameters CLOB);
|
@@ -274,6 +274,8 @@ public class DefaultAccessStatusHelperTest extends AbstractUnitTest {
|
||||
context.restoreAuthSystemState();
|
||||
String status = helper.getAccessStatusFromItem(context, itemWithEmbargo, threshold);
|
||||
assertThat("testWithEmbargo 0", status, equalTo(DefaultAccessStatusHelper.EMBARGO));
|
||||
String embargoDate = helper.getEmbargoFromItem(context, itemWithEmbargo, threshold);
|
||||
assertThat("testWithEmbargo 1", embargoDate, equalTo(policy.getStartDate().toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,6 +393,8 @@ public class DefaultAccessStatusHelperTest extends AbstractUnitTest {
|
||||
context.restoreAuthSystemState();
|
||||
String status = helper.getAccessStatusFromItem(context, itemWithPrimaryAndMultipleBitstreams, threshold);
|
||||
assertThat("testWithPrimaryAndMultipleBitstreams 0", status, equalTo(DefaultAccessStatusHelper.EMBARGO));
|
||||
String embargoDate = helper.getEmbargoFromItem(context, itemWithPrimaryAndMultipleBitstreams, threshold);
|
||||
assertThat("testWithPrimaryAndMultipleBitstreams 1", embargoDate, equalTo(policy.getStartDate().toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,6 +424,8 @@ public class DefaultAccessStatusHelperTest extends AbstractUnitTest {
|
||||
context.restoreAuthSystemState();
|
||||
String status = helper.getAccessStatusFromItem(context, itemWithoutPrimaryAndMultipleBitstreams, threshold);
|
||||
assertThat("testWithNoPrimaryAndMultipleBitstreams 0", status, equalTo(DefaultAccessStatusHelper.OPEN_ACCESS));
|
||||
String embargoDate = helper.getEmbargoFromItem(context, itemWithEmbargo, threshold);
|
||||
assertThat("testWithNoPrimaryAndMultipleBitstreams 1", embargoDate, equalTo(null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -26,6 +26,8 @@ import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||
import org.dspace.app.requestitem.RequestItem;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.builder.BitstreamBuilder;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
@@ -37,6 +39,7 @@ import org.dspace.builder.RelationshipTypeBuilder;
|
||||
import org.dspace.builder.RequestItemBuilder;
|
||||
import org.dspace.builder.ResourcePolicyBuilder;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.EntityType;
|
||||
@@ -48,6 +51,8 @@ import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.factory.VersionServiceFactory;
|
||||
import org.dspace.versioning.service.VersioningService;
|
||||
@@ -68,6 +73,8 @@ public class ItemServiceIT extends AbstractIntegrationTestWithDatabase {
|
||||
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
|
||||
protected MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
|
||||
protected VersioningService versioningService = VersionServiceFactory.getInstance().getVersionService();
|
||||
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
||||
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
||||
|
||||
Community community;
|
||||
Collection collection1;
|
||||
@@ -752,6 +759,154 @@ public class ItemServiceIT extends AbstractIntegrationTestWithDatabase {
|
||||
|
||||
assertNull(itemService.find(context, item.getID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveItemToCollectionWithMoreRestrictiveItemReadPolicy() throws Exception {
|
||||
/* Verify that, if we move an item from a collection with a permissive default item READ policy
|
||||
* to a collection with a restrictive default item READ policy,
|
||||
* that the item and its bundles do not retain the original permissive item READ policy.
|
||||
* However, its bitstreams do.
|
||||
*/
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
Group anonymous = groupService.findByName(context, Group.ANONYMOUS);
|
||||
Group admin = groupService.findByName(context, Group.ADMIN);
|
||||
|
||||
// Set up the two different collections: one permissive and one restrictive in its default READ policy.
|
||||
Collection permissive = CollectionBuilder
|
||||
.createCollection(context, community)
|
||||
.build();
|
||||
Collection restrictive = CollectionBuilder
|
||||
.createCollection(context, community)
|
||||
.build();
|
||||
authorizeService.removePoliciesActionFilter(context, restrictive, Constants.DEFAULT_ITEM_READ);
|
||||
authorizeService.addPolicy(context, restrictive, Constants.DEFAULT_ITEM_READ, admin);
|
||||
|
||||
// Add an item to the permissive collection.
|
||||
Item item = ItemBuilder
|
||||
.createItem(context, permissive)
|
||||
.build();
|
||||
|
||||
Bitstream bitstream = BitstreamBuilder.createBitstream(context, item, InputStream.nullInputStream())
|
||||
.build();
|
||||
|
||||
Bundle bundle = item.getBundles("ORIGINAL").get(0);
|
||||
|
||||
// Verify that the item, bundle and bitstream each have exactly one READ policy, for the anonymous group.
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, item, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, bundle, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, bitstream, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
|
||||
// Move the item to the restrictive collection, making sure to inherit default policies.
|
||||
itemService.move(context, item, permissive, restrictive, true);
|
||||
|
||||
// Verify that the item's read policy now only allows administrators.
|
||||
assertEquals(
|
||||
List.of(admin),
|
||||
authorizeService.getPoliciesActionFilter(context, item, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(admin),
|
||||
authorizeService.getPoliciesActionFilter(context, bundle, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, bitstream, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveItemToCollectionWithMoreRestrictiveBitstreamReadPolicy() throws Exception {
|
||||
/* Verify that, if we move an item from a collection with a permissive default bitstream READ policy
|
||||
* to a collection with a restrictive default bitstream READ policy,
|
||||
* that the item's bitstreams do not retain the original permissive READ policy.
|
||||
* However, the item itself and its bundles do retain the original policy.
|
||||
*/
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
Group anonymous = groupService.findByName(context, Group.ANONYMOUS);
|
||||
Group admin = groupService.findByName(context, Group.ADMIN);
|
||||
|
||||
// Set up the two different collections: one permissive and one restrictive in its default READ policy.
|
||||
Collection permissive = CollectionBuilder
|
||||
.createCollection(context, community)
|
||||
.build();
|
||||
Collection restrictive = CollectionBuilder
|
||||
.createCollection(context, community)
|
||||
.build();
|
||||
authorizeService.removePoliciesActionFilter(context, restrictive, Constants.DEFAULT_BITSTREAM_READ);
|
||||
authorizeService.addPolicy(context, restrictive, Constants.DEFAULT_BITSTREAM_READ, admin);
|
||||
|
||||
// Add an item to the permissive collection.
|
||||
Item item = ItemBuilder
|
||||
.createItem(context, permissive)
|
||||
.build();
|
||||
|
||||
Bitstream bitstream = BitstreamBuilder.createBitstream(context, item, InputStream.nullInputStream())
|
||||
.build();
|
||||
|
||||
Bundle bundle = item.getBundles("ORIGINAL").get(0);
|
||||
|
||||
// Verify that the item, bundle and bitstream each have exactly one READ policy, for the anonymous group.
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, item, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, bundle, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, bitstream, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
|
||||
// Move the item to the restrictive collection, making sure to inherit default policies.
|
||||
itemService.move(context, item, permissive, restrictive, true);
|
||||
|
||||
// Verify that the bundle and bitstream's read policies now only allows administrators.
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, item, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(anonymous),
|
||||
authorizeService.getPoliciesActionFilter(context, bundle, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(admin),
|
||||
authorizeService.getPoliciesActionFilter(context, bitstream, Constants.READ)
|
||||
.stream().map(ResourcePolicy::getGroup).collect(Collectors.toList())
|
||||
);
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
}
|
||||
|
||||
private void assertMetadataValue(String authorQualifier, String contributorElement, String dcSchema, String value,
|
||||
String authority, int place, MetadataValue metadataValue) {
|
||||
assertThat(metadataValue.getValue(), equalTo(value));
|
||||
|
@@ -85,7 +85,6 @@ public class XOAI {
|
||||
|
||||
// needed because the solr query only returns 10 rows by default
|
||||
private final Context context;
|
||||
private boolean optimize;
|
||||
private final boolean verbose;
|
||||
private boolean clean;
|
||||
|
||||
@@ -122,9 +121,8 @@ public class XOAI {
|
||||
return formats;
|
||||
}
|
||||
|
||||
public XOAI(Context context, boolean optimize, boolean clean, boolean verbose) {
|
||||
public XOAI(Context context, boolean clean, boolean verbose) {
|
||||
this.context = context;
|
||||
this.optimize = optimize;
|
||||
this.clean = clean;
|
||||
this.verbose = verbose;
|
||||
|
||||
@@ -173,12 +171,6 @@ public class XOAI {
|
||||
}
|
||||
solrServerResolver.getServer().commit();
|
||||
|
||||
if (optimize) {
|
||||
println("Optimizing Index");
|
||||
solrServerResolver.getServer().optimize();
|
||||
println("Index optimized");
|
||||
}
|
||||
|
||||
// Set last compilation date
|
||||
xoaiLastCompilationCacheService.put(new Date());
|
||||
return result;
|
||||
@@ -586,7 +578,6 @@ public class XOAI {
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
Options options = new Options();
|
||||
options.addOption("c", "clear", false, "Clear index before indexing");
|
||||
options.addOption("o", "optimize", false, "Optimize index at the end");
|
||||
options.addOption("v", "verbose", false, "Verbose output");
|
||||
options.addOption("h", "help", false, "Shows some help");
|
||||
options.addOption("n", "number", true, "FOR DEVELOPMENT MUST DELETE");
|
||||
@@ -620,7 +611,7 @@ public class XOAI {
|
||||
|
||||
if (COMMAND_IMPORT.equals(command)) {
|
||||
ctx = new Context(Context.Mode.READ_ONLY);
|
||||
XOAI indexer = new XOAI(ctx, line.hasOption('o'), line.hasOption('c'), line.hasOption('v'));
|
||||
XOAI indexer = new XOAI(ctx, line.hasOption('c'), line.hasOption('v'));
|
||||
|
||||
applicationContext.getAutowireCapableBeanFactory().autowireBean(indexer);
|
||||
|
||||
@@ -706,7 +697,6 @@ public class XOAI {
|
||||
System.out.println(" " + COMMAND_IMPORT + " - To import DSpace items into OAI index and cache system");
|
||||
System.out.println(" " + COMMAND_CLEAN_CACHE + " - Cleans the OAI cached responses");
|
||||
System.out.println("> Parameters:");
|
||||
System.out.println(" -o Optimize index after indexing (" + COMMAND_IMPORT + " only)");
|
||||
System.out.println(" -c Clear index (" + COMMAND_IMPORT + " only)");
|
||||
System.out.println(" -v Verbose output");
|
||||
System.out.println(" -h Shows this text");
|
||||
|
@@ -12,6 +12,7 @@ import java.util.List;
|
||||
|
||||
import com.lyncode.xoai.dataprovider.xml.xoai.Element;
|
||||
import com.lyncode.xoai.dataprovider.xml.xoai.Metadata;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.access.status.factory.AccessStatusServiceFactory;
|
||||
import org.dspace.access.status.service.AccessStatusService;
|
||||
import org.dspace.content.Item;
|
||||
@@ -31,6 +32,13 @@ import org.dspace.xoai.util.ItemUtils;
|
||||
* <field name="value">open.access</field>
|
||||
* </element>
|
||||
* </element>
|
||||
* OR
|
||||
* <element name="others">
|
||||
* <element name="access-status">
|
||||
* <field name="value">embargo</field>
|
||||
* <field name="embargo">2024-10-10</field>
|
||||
* </element>
|
||||
* </element>
|
||||
* }
|
||||
* </pre>
|
||||
* Returning Values are based on:
|
||||
@@ -46,9 +54,15 @@ public class AccessStatusElementItemCompilePlugin implements XOAIExtensionItemCo
|
||||
String accessStatusType;
|
||||
accessStatusType = accessStatusService.getAccessStatus(context, item);
|
||||
|
||||
String embargoFromItem = accessStatusService.getEmbargoFromItem(context, item);
|
||||
|
||||
Element accessStatus = ItemUtils.create("access-status");
|
||||
accessStatus.getField().add(ItemUtils.createValue("value", accessStatusType));
|
||||
|
||||
if (StringUtils.isNotEmpty(embargoFromItem)) {
|
||||
accessStatus.getField().add(ItemUtils.createValue("embargo", embargoFromItem));
|
||||
}
|
||||
|
||||
Element others;
|
||||
List<Element> elements = metadata.getElement();
|
||||
if (ItemUtils.getElement(elements, "others") != null) {
|
||||
|
@@ -21,7 +21,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.commons.validator.routines.EmailValidator;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -48,7 +47,7 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
/**
|
||||
* Component to expose item requests.
|
||||
*
|
||||
@@ -173,11 +172,11 @@ public class RequestItemRepository
|
||||
username = user.getFullName();
|
||||
} else { // An anonymous session may provide a name.
|
||||
// Escape username to evade nasty XSS attempts
|
||||
username = StringEscapeUtils.escapeHtml4(rir.getRequestName());
|
||||
username = HtmlUtils.htmlEscape(rir.getRequestName(),"UTF-8");
|
||||
}
|
||||
|
||||
// Requester's message text, escaped to evade nasty XSS attempts
|
||||
String message = StringEscapeUtils.escapeHtml4(rir.getRequestMessage());
|
||||
String message = HtmlUtils.htmlEscape(rir.getRequestMessage(),"UTF-8");
|
||||
|
||||
// Create the request.
|
||||
String token;
|
||||
|
@@ -1695,6 +1695,53 @@ public class BitstreamRestRepositoryIT extends AbstractControllerIntegrationTest
|
||||
.andExpect(jsonPath("$.type", is("bitstream")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thumbnailEndpointTestWithSpecialCharactersInFileName() throws Exception {
|
||||
// Given an Item
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community")
|
||||
.build();
|
||||
|
||||
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Collection 1").build();
|
||||
|
||||
Item item = ItemBuilder.createItem(context, col1)
|
||||
.withTitle("Test item -- thumbnail")
|
||||
.withIssueDate("2017-10-17")
|
||||
.withAuthor("Smith, Donald").withAuthor("Doe, John")
|
||||
.build();
|
||||
|
||||
Bundle originalBundle = BundleBuilder.createBundle(context, item)
|
||||
.withName(Constants.DEFAULT_BUNDLE_NAME)
|
||||
.build();
|
||||
Bundle thumbnailBundle = BundleBuilder.createBundle(context, item)
|
||||
.withName("THUMBNAIL")
|
||||
.build();
|
||||
|
||||
InputStream is = IOUtils.toInputStream("dummy", "utf-8");
|
||||
|
||||
// With an ORIGINAL Bitstream & matching THUMBNAIL Bitstream containing special characters in filenames
|
||||
Bitstream bitstream = BitstreamBuilder.createBitstream(context, originalBundle, is)
|
||||
.withName("test (2023) file.pdf")
|
||||
.withMimeType("application/pdf")
|
||||
.build();
|
||||
Bitstream thumbnail = BitstreamBuilder.createBitstream(context, thumbnailBundle, is)
|
||||
.withName("test (2023) file.pdf.jpg")
|
||||
.withMimeType("image/jpeg")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(tokenAdmin).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/thumbnail"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.uuid", Matchers.is(thumbnail.getID().toString())))
|
||||
.andExpect(jsonPath("$.type", is("bitstream")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thumbnailEndpointMultipleThumbnailsWithPrimaryBitstreamTest() throws Exception {
|
||||
// Given an Item
|
||||
|
@@ -1432,6 +1432,18 @@
|
||||
<xsl:when test="$lc_dc_type = 'book review'">
|
||||
<xsl:text>literature</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$lc_dc_type = 'bachelor thesis'">
|
||||
<xsl:text>literature</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$lc_dc_type = 'doctoral thesis'">
|
||||
<xsl:text>literature</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$lc_dc_type = 'master thesis'">
|
||||
<xsl:text>literature</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$lc_dc_type = 'thesis'">
|
||||
<xsl:text>literature</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$lc_dc_type = 'dataset'">
|
||||
<xsl:text>dataset</xsl:text>
|
||||
</xsl:when>
|
||||
|
@@ -115,6 +115,20 @@
|
||||
<!-- <dc:identifier xsi:type="dcterms:URI"><xsl:value-of select="." /></dc:identifier> -->
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- ******* Check access-status information to determine the item's access status ******* -->
|
||||
<xsl:for-each select="doc:metadata/doc:element[@name='others']/doc:element[@name='access-status']/doc:field[@name='value']/text()">
|
||||
<!-- Add access status information for embargo or restricted status only in uketdterms:embargotype -->
|
||||
<xsl:if test=".='restricted' or .='embargo'">
|
||||
<uketdterms:embargotype><xsl:value-of select="." /></uketdterms:embargotype>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- ******* Check access-status embargo information for embargoed content associated with this item ******* -->
|
||||
<xsl:for-each select="doc:metadata/doc:element[@name='others']/doc:element[@name='access-status']/doc:field[@name='embargo']/text()">
|
||||
<!-- Add embargo information -->
|
||||
<uketdterms:embargodate><xsl:value-of select="." /></uketdterms:embargodate>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- ******* URLs for digital object(s) (obtained from file 'bundles') ******* -->
|
||||
<xsl:for-each select="doc:metadata/doc:element[@name='bundles']/doc:element[@name='bundle']">
|
||||
|
||||
|
2
pom.xml
2
pom.xml
@@ -37,7 +37,7 @@
|
||||
<jaxb-runtime.version>2.3.8</jaxb-runtime.version>
|
||||
<jcache-version>1.1.1</jcache-version>
|
||||
<!-- NOTE: Jetty needed for Solr, Handle Server & tests -->
|
||||
<jetty.version>9.4.52.v20230823</jetty.version>
|
||||
<jetty.version>9.4.53.v20231009</jetty.version>
|
||||
<log4j.version>2.20.0</log4j.version>
|
||||
<pdfbox-version>2.0.29</pdfbox-version>
|
||||
<rome.version>1.19.0</rome.version>
|
||||
|
Reference in New Issue
Block a user