Skip to content

Commit

Permalink
Merge remote-tracking branch 'dspace/main' into fix-inherit-policies-…
Browse files Browse the repository at this point in the history
…at-item-move
  • Loading branch information
Koen Pauwels committed Oct 16, 2023
2 parents 489c3ad + 92844f0 commit 6d4ef67
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,9 @@ public void init() throws Exception {
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@
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.
* The getAccessStatusFromItem method provides a simple logic to
* 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";
Expand All @@ -54,12 +60,12 @@ public DefaultAccessStatusHelper() {

/**
* 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
*/
Expand All @@ -86,7 +92,7 @@ public String getAccessStatusFromItem(Context context, Item item, Date threshold
.findFirst()
.orElse(null);
}
return caculateAccessStatusForDso(context, bitstream, threshold);
return calculateAccessStatusForDso(context, bitstream, threshold);
}

/**
Expand All @@ -104,7 +110,7 @@ public String getAccessStatusFromItem(Context context, Item item, Date threshold
* @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;
Expand Down Expand Up @@ -156,4 +162,87 @@ private String caculateAccessStatusForDso(Context context, DSpaceObject dso, Dat
}
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1363,7 +1363,7 @@ private int displayChanges(List<BulkEditChange> changes, boolean changed) {
* 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,9 @@ public String register(Context context, DSpaceObject dso) {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ public String register(Context context, DSpaceObject dso) {
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);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ public void testWithEmbargo() throws Exception {
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()));
}

/**
Expand Down Expand Up @@ -391,6 +393,8 @@ public void testWithPrimaryAndMultipleBitstreams() throws Exception {
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()));
}

/**
Expand Down Expand Up @@ -420,6 +424,8 @@ public void testWithNoPrimaryAndMultipleBitstreams() throws Exception {
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));
}

/**
Expand Down
14 changes: 2 additions & 12 deletions dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -122,9 +121,8 @@ private List<String> getFileFormats(Item item) {
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;

Expand Down Expand Up @@ -173,12 +171,6 @@ public int index() throws DSpaceSolrIndexerException {
}
solrServerResolver.getServer().commit();

if (optimize) {
println("Optimizing Index");
solrServerResolver.getServer().optimize();
println("Index optimized");
}

// Set last compilation date
xoaiLastCompilationCacheService.put(new Date());
return result;
Expand Down Expand Up @@ -586,7 +578,6 @@ public static void main(String[] argv) throws IOException, ConfigurationExceptio
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");
Expand Down Expand Up @@ -620,7 +611,7 @@ public static void main(String[] argv) throws IOException, ConfigurationExceptio

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);

Expand Down Expand Up @@ -706,7 +697,6 @@ private static void usage() {
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

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;
Expand All @@ -31,6 +32,13 @@
* <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:
Expand All @@ -46,9 +54,15 @@ public Metadata additionalMetadata(Context context, Metadata metadata, Item item
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

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;
Expand All @@ -48,7 +47,7 @@
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.
*
Expand Down Expand Up @@ -173,11 +172,11 @@ public RequestItemRest createAndReturn(Context ctx)
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;
Expand Down
Loading

0 comments on commit 6d4ef67

Please sign in to comment.