Merge branch 'main' into contract-pr-222-primary-bitstream-on-bundle-support

This commit is contained in:
Nona Luypaert
2023-06-01 12:22:56 +02:00
10 changed files with 230 additions and 62 deletions

View File

@@ -22,7 +22,9 @@ public class ImageMagickPdfThumbnailFilter extends ImageMagickThumbnailFilter {
File f2 = null; File f2 = null;
File f3 = null; File f3 = null;
try { try {
f2 = getImageFile(f, 0, verbose); // Step 1: get an image from our PDF file, with PDF-specific processing options
f2 = getImageFile(f, verbose);
// Step 2: use the image above to create the final resized and rotated thumbnail
f3 = getThumbnailFile(f2, verbose); f3 = getThumbnailFile(f2, verbose);
byte[] bytes = Files.readAllBytes(f3.toPath()); byte[] bytes = Files.readAllBytes(f3.toPath());
return new ByteArrayInputStream(bytes); return new ByteArrayInputStream(bytes);

View File

@@ -116,9 +116,17 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
return f2; return f2;
} }
public File getImageFile(File f, int page, boolean verbose) /**
* Return an image from a bitstream with specific processing options for
* PDFs. This is only used by ImageMagickPdfThumbnailFilter in order to
* generate an intermediate image file for use with getThumbnailFile.
*/
public File getImageFile(File f, boolean verbose)
throws IOException, InterruptedException, IM4JavaException { throws IOException, InterruptedException, IM4JavaException {
File f2 = new File(f.getParentFile(), f.getName() + ".jpg"); // Writing an intermediate file to disk is inefficient, but since we're
// doing it anyway, we should use a lossless format. IM's internal MIFF
// is lossless like PNG and TIFF, but much faster.
File f2 = new File(f.getParentFile(), f.getName() + ".miff");
f2.deleteOnExit(); f2.deleteOnExit();
ConvertCmd cmd = new ConvertCmd(); ConvertCmd cmd = new ConvertCmd();
IMOperation op = new IMOperation(); IMOperation op = new IMOperation();
@@ -155,7 +163,7 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
op.define("pdf:use-cropbox=true"); op.define("pdf:use-cropbox=true");
} }
String s = "[" + page + "]"; String s = "[0]";
op.addImage(f.getAbsolutePath() + s); op.addImage(f.getAbsolutePath() + s);
if (configurationService.getBooleanProperty(PRE + ".flatten", true)) { if (configurationService.getBooleanProperty(PRE + ".flatten", true)) {
op.flatten(); op.flatten();
@@ -208,20 +216,20 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
if (description != null) { if (description != null) {
if (replaceRegex.matcher(description).matches()) { if (replaceRegex.matcher(description).matches()) {
if (verbose) { if (verbose) {
System.out.format("%s %s matches pattern and is replacable.%n", System.out.format("%s %s matches pattern and is replaceable.%n",
description, nsrc); description, n);
} }
continue; continue;
} }
if (description.equals(getDescription())) { if (description.equals(getDescription())) {
if (verbose) { if (verbose) {
System.out.format("%s %s is replaceable.%n", System.out.format("%s %s is replaceable.%n",
getDescription(), nsrc); getDescription(), n);
} }
continue; continue;
} }
} }
System.out.format("Custom Thumbnail exists for %s for item %s. Thumbnail will not be generated.%n", System.out.format("Custom thumbnail exists for %s for item %s. Thumbnail will not be generated.%n",
nsrc, item.getHandle()); nsrc, item.getHandle());
return false; return false;
} }

View File

@@ -11,6 +11,8 @@ import java.text.ParseException;
import java.util.Date; import java.util.Date;
import java.util.Objects; import java.util.Objects;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.AuthorizeService;
@@ -21,6 +23,7 @@ import org.dspace.core.Context;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.dspace.util.DateMathParser; import org.dspace.util.DateMathParser;
import org.dspace.util.TimeHelpers;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
@@ -28,9 +31,8 @@ import org.springframework.beans.factory.annotation.Autowired;
* set permission on a file. An option is defined by a name such as "open * set permission on a file. An option is defined by a name such as "open
* access", "embargo", "restricted access", etc. and some optional attributes to * access", "embargo", "restricted access", etc. and some optional attributes to
* better clarify the constraints and input available to the user. For instance * better clarify the constraints and input available to the user. For instance
* an embargo option could allow to set a start date not longer than 3 years, * an embargo option could allow to set a start date not longer than 3 years.
* etc *
*
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/ */
public class AccessConditionOption { public class AccessConditionOption {
@@ -44,9 +46,9 @@ public class AccessConditionOption {
@Autowired @Autowired
private ResourcePolicyService resourcePolicyService; private ResourcePolicyService resourcePolicyService;
DateMathParser dateMathParser = new DateMathParser(); private static final Logger LOG = LogManager.getLogger();
/** An unique name identifying the access contion option **/ /** A unique name identifying the access condition option. **/
private String name; private String name;
/** /**
@@ -147,6 +149,9 @@ public class AccessConditionOption {
* startDate should be null. Otherwise startDate may not be null. * startDate should be null. Otherwise startDate may not be null.
* @param endDate end date of the resource policy. If {@link #getHasEndDate()} returns false, * @param endDate end date of the resource policy. If {@link #getHasEndDate()} returns false,
* endDate should be null. Otherwise endDate may not be null. * endDate should be null. Otherwise endDate may not be null.
* @throws SQLException passed through.
* @throws AuthorizeException passed through.
* @throws ParseException passed through (indicates problem with a date).
*/ */
public void createResourcePolicy(Context context, DSpaceObject obj, String name, String description, public void createResourcePolicy(Context context, DSpaceObject obj, String name, String description,
Date startDate, Date endDate) Date startDate, Date endDate)
@@ -160,7 +165,7 @@ public class AccessConditionOption {
/** /**
* Validate ResourcePolicy and after update it * Validate ResourcePolicy and after update it
* *
* @param context DSpace context * @param context DSpace context
* @param resourcePolicy ResourcePolicy to update * @param resourcePolicy ResourcePolicy to update
* @throws SQLException If database error * @throws SQLException If database error
@@ -175,17 +180,25 @@ public class AccessConditionOption {
} }
/** /**
* Validate the policy properties, throws exceptions if any is not valid * Validate the policy properties, throws exceptions if any is not valid.
* *
* @param context DSpace context * @param context DSpace context.
* @param name Name of the resource policy * @param name Name of the resource policy.
* @param startDate Start date of the resource policy. If {@link #getHasStartDate()} * @param startDate Start date of the resource policy. If
* returns false, startDate should be null. Otherwise startDate may not be null. * {@link #getHasStartDate()} returns false, startDate
* @param endDate End date of the resource policy. If {@link #getHasEndDate()} * should be null. Otherwise startDate may not be null.
* returns false, endDate should be null. Otherwise endDate may not be null. * @param endDate End date of the resource policy. If
* {@link #getHasEndDate()} returns false, endDate should
* be null. Otherwise endDate may not be null.
* @throws IllegalStateException if a date is required and absent,
* a date is not required and present, or a date exceeds its
* configured maximum.
* @throws ParseException passed through.
*/ */
private void validateResourcePolicy(Context context, String name, Date startDate, Date endDate) private void validateResourcePolicy(Context context, String name, Date startDate, Date endDate)
throws SQLException, AuthorizeException, ParseException { throws IllegalStateException, ParseException {
LOG.debug("Validate policy dates: name '{}', startDate {}, endDate {}",
name, startDate, endDate);
if (getHasStartDate() && Objects.isNull(startDate)) { if (getHasStartDate() && Objects.isNull(startDate)) {
throw new IllegalStateException("The access condition " + getName() + " requires a start date."); throw new IllegalStateException("The access condition " + getName() + " requires a start date.");
} }
@@ -199,29 +212,33 @@ public class AccessConditionOption {
throw new IllegalStateException("The access condition " + getName() + " cannot contain an end date."); throw new IllegalStateException("The access condition " + getName() + " cannot contain an end date.");
} }
DateMathParser dateMathParser = new DateMathParser();
Date latestStartDate = null; Date latestStartDate = null;
if (Objects.nonNull(getStartDateLimit())) { if (Objects.nonNull(getStartDateLimit())) {
latestStartDate = dateMathParser.parseMath(getStartDateLimit()); latestStartDate = TimeHelpers.toMidnightUTC(dateMathParser.parseMath(getStartDateLimit()));
} }
Date latestEndDate = null; Date latestEndDate = null;
if (Objects.nonNull(getEndDateLimit())) { if (Objects.nonNull(getEndDateLimit())) {
latestEndDate = dateMathParser.parseMath(getEndDateLimit()); latestEndDate = TimeHelpers.toMidnightUTC(dateMathParser.parseMath(getEndDateLimit()));
} }
LOG.debug(" latestStartDate {}, latestEndDate {}",
latestStartDate, latestEndDate);
// throw if startDate after latestStartDate // throw if startDate after latestStartDate
if (Objects.nonNull(startDate) && Objects.nonNull(latestStartDate) && startDate.after(latestStartDate)) { if (Objects.nonNull(startDate) && Objects.nonNull(latestStartDate) && startDate.after(latestStartDate)) {
throw new IllegalStateException(String.format( throw new IllegalStateException(String.format(
"The start date of access condition %s should be earlier than %s from now.", "The start date of access condition %s should be earlier than %s from now (%s).",
getName(), getStartDateLimit() getName(), getStartDateLimit(), dateMathParser.getNow()
)); ));
} }
// throw if endDate after latestEndDate // throw if endDate after latestEndDate
if (Objects.nonNull(endDate) && Objects.nonNull(latestEndDate) && endDate.after(latestEndDate)) { if (Objects.nonNull(endDate) && Objects.nonNull(latestEndDate) && endDate.after(latestEndDate)) {
throw new IllegalStateException(String.format( throw new IllegalStateException(String.format(
"The end date of access condition %s should be earlier than %s from now.", "The end date of access condition %s should be earlier than %s from now (%s).",
getName(), getEndDateLimit() getName(), getEndDateLimit(), dateMathParser.getNow()
)); ));
} }
} }

View File

@@ -26,12 +26,15 @@ import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /**
* This class (Apache license) is copied from Apache Solr and add some tweaks to resolve unneeded dependency: * This class (Apache license) is copied from Apache Solr, adding some tweaks to
* https://raw.githubusercontent.com/apache/lucene-solr/releases/lucene-solr/7.1.0/solr/core/src/java/org/apache/solr * resolve an unneeded dependency. See
* /util/DateMathParser.java * <a href='https://raw.githubusercontent.com/apache/lucene-solr/releases/lucene-solr/7.1.0/solr/core/src/java/org/apache/solr/util/DateMathParser.java'>the original</a>.
* *
* <p>
* A Simple Utility class for parsing "math" like strings relating to Dates. * A Simple Utility class for parsing "math" like strings relating to Dates.
* *
* <p> * <p>
@@ -78,7 +81,7 @@ import java.util.regex.Pattern;
* "<code>setNow</code>" in the interim). The default value of 'now' is * "<code>setNow</code>" in the interim). The default value of 'now' is
* the time at the moment the <code>DateMathParser</code> instance is * the time at the moment the <code>DateMathParser</code> instance is
* constructed, unless overridden by the {@link CommonParams#NOW NOW} * constructed, unless overridden by the {@link CommonParams#NOW NOW}
* request param. * request parameter.
* </p> * </p>
* *
* <p> * <p>
@@ -88,7 +91,7 @@ import java.util.regex.Pattern;
* cascades to rounding of HOUR, MIN, MONTH, YEAR as well. The default * cascades to rounding of HOUR, MIN, MONTH, YEAR as well. The default
* <code>TimeZone</code> used is <code>UTC</code> unless overridden by the * <code>TimeZone</code> used is <code>UTC</code> unless overridden by the
* {@link CommonParams#TZ TZ} * {@link CommonParams#TZ TZ}
* request param. * request parameter.
* </p> * </p>
* *
* <p> * <p>
@@ -102,6 +105,8 @@ import java.util.regex.Pattern;
*/ */
public class DateMathParser { public class DateMathParser {
private static final Logger LOG = LogManager.getLogger();
public static final TimeZone UTC = TimeZone.getTimeZone("UTC"); public static final TimeZone UTC = TimeZone.getTimeZone("UTC");
/** /**
@@ -119,12 +124,12 @@ public class DateMathParser {
/** /**
* A mapping from (uppercased) String labels identifying time units, * A mapping from (uppercased) String labels identifying time units,
* to the corresponding {@link ChronoUnit} enum (e.g. "YEARS") used to * to the corresponding {@link ChronoUnit} value (e.g. "YEARS") used to
* set/add/roll that unit of measurement. * set/add/roll that unit of measurement.
* *
* <p> * <p>
* A single logical unit of time might be represented by multiple labels * A single logical unit of time might be represented by multiple labels
* for convenience (ie: <code>DATE==DAYS</code>, * for convenience (i.e. <code>DATE==DAYS</code>,
* <code>MILLI==MILLIS</code>) * <code>MILLI==MILLIS</code>)
* </p> * </p>
* *
@@ -220,6 +225,7 @@ public class DateMathParser {
* *
* @param now an optional fixed date to use as "NOW" * @param now an optional fixed date to use as "NOW"
* @param val the string to parse * @param val the string to parse
* @return result of applying the parsed expression to "NOW".
* @throws Exception * @throws Exception
*/ */
public static Date parseMath(Date now, String val) throws Exception { public static Date parseMath(Date now, String val) throws Exception {
@@ -308,6 +314,7 @@ public class DateMathParser {
/** /**
* Defines this instance's concept of "now". * Defines this instance's concept of "now".
* *
* @param n new value of "now".
* @see #getNow * @see #getNow
*/ */
public void setNow(Date n) { public void setNow(Date n) {
@@ -316,12 +323,12 @@ public class DateMathParser {
/** /**
* Returns a clone of this instance's concept of "now" (never null). * Returns a clone of this instance's concept of "now" (never null).
*
* If setNow was never called (or if null was specified) then this method * If setNow was never called (or if null was specified) then this method
* first defines 'now' as the value dictated by the SolrRequestInfo if it * first defines 'now' as the value dictated by the SolrRequestInfo if it
* exists -- otherwise it uses a new Date instance at the moment getNow() * exists -- otherwise it uses a new Date instance at the moment getNow()
* is first called. * is first called.
* *
* @return "now".
* @see #setNow * @see #setNow
* @see SolrRequestInfo#getNOW * @see SolrRequestInfo#getNOW
*/ */
@@ -334,9 +341,12 @@ public class DateMathParser {
} }
/** /**
* Parses a string of commands relative "now" are returns the resulting Date. * Parses a date expression relative to "now".
* *
* @throws ParseException positions in ParseExceptions are token positions, not character positions. * @param math a date expression such as "+24MONTHS".
* @return the result of applying the expression to the current time.
* @throws ParseException positions in ParseExceptions are token positions,
* not character positions.
*/ */
public Date parseMath(String math) throws ParseException { public Date parseMath(String math) throws ParseException {
/* check for No-Op */ /* check for No-Op */
@@ -344,6 +354,8 @@ public class DateMathParser {
return getNow(); return getNow();
} }
LOG.debug("parsing {}", math);
ZoneId zoneId = zone.toZoneId(); ZoneId zoneId = zone.toZoneId();
// localDateTime is a date and time local to the timezone specified // localDateTime is a date and time local to the timezone specified
LocalDateTime localDateTime = ZonedDateTime.ofInstant(getNow().toInstant(), zoneId).toLocalDateTime(); LocalDateTime localDateTime = ZonedDateTime.ofInstant(getNow().toInstant(), zoneId).toLocalDateTime();
@@ -394,11 +406,44 @@ public class DateMathParser {
} }
} }
LOG.debug("returning {}", localDateTime);
return Date.from(ZonedDateTime.of(localDateTime, zoneId).toInstant()); return Date.from(ZonedDateTime.of(localDateTime, zoneId).toInstant());
} }
private static Pattern splitter = Pattern.compile("\\b|(?<=\\d)(?=\\D)"); private static Pattern splitter = Pattern.compile("\\b|(?<=\\d)(?=\\D)");
/**
* For manual testing. With one argument, test one-argument parseMath.
* With two (or more) arguments, test two-argument parseMath.
*
* @param argv date math expressions.
* @throws java.lang.Exception passed through.
*/
public static void main(String[] argv)
throws Exception {
DateMathParser parser = new DateMathParser();
try {
Date parsed;
if (argv.length <= 0) {
System.err.println("Date math expression(s) expected.");
}
if (argv.length > 0) {
parsed = parser.parseMath(argv[0]);
System.out.format("Applied %s to implicit current time: %s%n",
argv[0], parsed.toString());
}
if (argv.length > 1) {
parsed = DateMathParser.parseMath(new Date(), argv[1]);
System.out.format("Applied %s to explicit current time: %s%n",
argv[1], parsed.toString());
}
} catch (ParseException ex) {
System.err.format("Oops: %s%n", ex.getMessage());
}
}
} }

View File

@@ -0,0 +1,42 @@
/**
* 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.util;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* Various manipulations of dates and times.
*
* @author mwood
*/
public class TimeHelpers {
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
/**
* Never instantiate this class.
*/
private TimeHelpers() {}
/**
* Set a Date's time to midnight UTC.
*
* @param from some date-time.
* @return midnight UTC of the supplied date-time.
*/
public static Date toMidnightUTC(Date from) {
GregorianCalendar calendar = new GregorianCalendar(UTC);
calendar.setTime(from);
calendar.set(GregorianCalendar.HOUR_OF_DAY, 0);
calendar.set(GregorianCalendar.MINUTE, 0);
calendar.set(GregorianCalendar.SECOND, 0);
calendar.set(GregorianCalendar.MILLISECOND, 0);
return calendar.getTime();
}
}

View File

@@ -0,0 +1,34 @@
/**
* 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.util;
import static org.junit.Assert.assertEquals;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;
import org.junit.Test;
/**
* Test {@link TimeHelpers}.
* @author Mark H. Wood <mwood@iupui.edu>
*/
public class TimeHelpersTest {
/**
* Test of toMidnightUTC method, of class TimeHelpers.
*/
@Test
public void testToMidnightUTC() {
System.out.println("toMidnightUTC");
Date from = Date.from(ZonedDateTime.of(1957, 01, 27, 04, 05, 06, 007, ZoneOffset.UTC).toInstant());
Date expResult = Date.from(ZonedDateTime.of(1957, 01, 27, 00, 00, 00, 000, ZoneOffset.UTC).toInstant());
Date result = TimeHelpers.toMidnightUTC(from);
assertEquals(expResult, result);
}
}

View File

@@ -6,7 +6,9 @@
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.app.rest.converter; package org.dspace.app.rest.converter;
import java.text.ParseException; import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.model.AccessConditionOptionRest; import org.dspace.app.rest.model.AccessConditionOptionRest;
@@ -15,6 +17,7 @@ import org.dspace.app.rest.projection.Projection;
import org.dspace.submit.model.AccessConditionConfiguration; import org.dspace.submit.model.AccessConditionConfiguration;
import org.dspace.submit.model.AccessConditionOption; import org.dspace.submit.model.AccessConditionOption;
import org.dspace.util.DateMathParser; import org.dspace.util.DateMathParser;
import org.dspace.util.TimeHelpers;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
@@ -27,21 +30,21 @@ import org.springframework.stereotype.Component;
public class SubmissionAccessOptionConverter public class SubmissionAccessOptionConverter
implements DSpaceConverter<AccessConditionConfiguration, SubmissionAccessOptionRest> { implements DSpaceConverter<AccessConditionConfiguration, SubmissionAccessOptionRest> {
DateMathParser dateMathParser = new DateMathParser();
@Override @Override
public SubmissionAccessOptionRest convert(AccessConditionConfiguration config, Projection projection) { public SubmissionAccessOptionRest convert(AccessConditionConfiguration config, Projection projection) {
SubmissionAccessOptionRest model = new SubmissionAccessOptionRest(); SubmissionAccessOptionRest model = new SubmissionAccessOptionRest();
model.setId(config.getName()); model.setId(config.getName());
model.setCanChangeDiscoverable(config.getCanChangeDiscoverable()); model.setCanChangeDiscoverable(config.getCanChangeDiscoverable());
model.setProjection(projection); model.setProjection(projection);
DateMathParser dateMathParser = new DateMathParser();
for (AccessConditionOption option : config.getOptions()) { for (AccessConditionOption option : config.getOptions()) {
AccessConditionOptionRest optionRest = new AccessConditionOptionRest(); AccessConditionOptionRest optionRest = new AccessConditionOptionRest();
optionRest.setHasStartDate(option.getHasStartDate()); optionRest.setHasStartDate(option.getHasStartDate());
optionRest.setHasEndDate(option.getHasEndDate()); optionRest.setHasEndDate(option.getHasEndDate());
if (StringUtils.isNotBlank(option.getStartDateLimit())) { if (StringUtils.isNotBlank(option.getStartDateLimit())) {
try { try {
optionRest.setMaxStartDate(dateMathParser.parseMath(option.getStartDateLimit())); Date requested = dateMathParser.parseMath(option.getStartDateLimit());
optionRest.setMaxStartDate(TimeHelpers.toMidnightUTC(requested));
} catch (ParseException e) { } catch (ParseException e) {
throw new IllegalStateException("Wrong start date limit configuration for the access condition " throw new IllegalStateException("Wrong start date limit configuration for the access condition "
+ "option named " + option.getName()); + "option named " + option.getName());
@@ -49,7 +52,8 @@ public class SubmissionAccessOptionConverter
} }
if (StringUtils.isNotBlank(option.getEndDateLimit())) { if (StringUtils.isNotBlank(option.getEndDateLimit())) {
try { try {
optionRest.setMaxEndDate(dateMathParser.parseMath(option.getEndDateLimit())); Date requested = dateMathParser.parseMath(option.getEndDateLimit());
optionRest.setMaxEndDate(TimeHelpers.toMidnightUTC(requested));
} catch (ParseException e) { } catch (ParseException e) {
throw new IllegalStateException("Wrong end date limit configuration for the access condition " throw new IllegalStateException("Wrong end date limit configuration for the access condition "
+ "option named " + option.getName()); + "option named " + option.getName());

View File

@@ -10,6 +10,7 @@ package org.dspace.app.rest.repository;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -18,11 +19,11 @@ import org.dspace.app.rest.model.AccessConditionOptionRest;
import org.dspace.app.rest.model.SubmissionUploadRest; import org.dspace.app.rest.model.SubmissionUploadRest;
import org.dspace.app.rest.projection.Projection; import org.dspace.app.rest.projection.Projection;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.service.GroupService;
import org.dspace.submit.model.AccessConditionOption; import org.dspace.submit.model.AccessConditionOption;
import org.dspace.submit.model.UploadConfiguration; import org.dspace.submit.model.UploadConfiguration;
import org.dspace.submit.model.UploadConfigurationService; import org.dspace.submit.model.UploadConfigurationService;
import org.dspace.util.DateMathParser; import org.dspace.util.DateMathParser;
import org.dspace.util.TimeHelpers;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@@ -47,11 +48,6 @@ public class SubmissionUploadRestRepository extends DSpaceRestRepository<Submiss
@Autowired @Autowired
private UploadConfigurationService uploadConfigurationService; private UploadConfigurationService uploadConfigurationService;
@Autowired
GroupService groupService;
DateMathParser dateMathParser = new DateMathParser();
@PreAuthorize("hasAuthority('AUTHENTICATED')") @PreAuthorize("hasAuthority('AUTHENTICATED')")
@Override @Override
public SubmissionUploadRest findOne(Context context, String submitName) { public SubmissionUploadRest findOne(Context context, String submitName) {
@@ -70,7 +66,7 @@ public class SubmissionUploadRestRepository extends DSpaceRestRepository<Submiss
Collection<UploadConfiguration> uploadConfigs = uploadConfigurationService.getMap().values(); Collection<UploadConfiguration> uploadConfigs = uploadConfigurationService.getMap().values();
Projection projection = utils.obtainProjection(); Projection projection = utils.obtainProjection();
List<SubmissionUploadRest> results = new ArrayList<>(); List<SubmissionUploadRest> results = new ArrayList<>();
List<String> configNames = new ArrayList<String>(); List<String> configNames = new ArrayList<>();
for (UploadConfiguration uploadConfig : uploadConfigs) { for (UploadConfiguration uploadConfig : uploadConfigs) {
if (!configNames.contains(uploadConfig.getName())) { if (!configNames.contains(uploadConfig.getName())) {
configNames.add(uploadConfig.getName()); configNames.add(uploadConfig.getName());
@@ -92,13 +88,15 @@ public class SubmissionUploadRestRepository extends DSpaceRestRepository<Submiss
private SubmissionUploadRest convert(Context context, UploadConfiguration config, Projection projection) { private SubmissionUploadRest convert(Context context, UploadConfiguration config, Projection projection) {
SubmissionUploadRest result = new SubmissionUploadRest(); SubmissionUploadRest result = new SubmissionUploadRest();
result.setProjection(projection); result.setProjection(projection);
DateMathParser dateMathParser = new DateMathParser();
for (AccessConditionOption option : config.getOptions()) { for (AccessConditionOption option : config.getOptions()) {
AccessConditionOptionRest optionRest = new AccessConditionOptionRest(); AccessConditionOptionRest optionRest = new AccessConditionOptionRest();
optionRest.setHasStartDate(option.getHasStartDate()); optionRest.setHasStartDate(option.getHasStartDate());
optionRest.setHasEndDate(option.getHasEndDate()); optionRest.setHasEndDate(option.getHasEndDate());
if (StringUtils.isNotBlank(option.getStartDateLimit())) { if (StringUtils.isNotBlank(option.getStartDateLimit())) {
try { try {
optionRest.setMaxStartDate(dateMathParser.parseMath(option.getStartDateLimit())); Date requested = dateMathParser.parseMath(option.getStartDateLimit());
optionRest.setMaxStartDate(TimeHelpers.toMidnightUTC(requested));
} catch (ParseException e) { } catch (ParseException e) {
throw new IllegalStateException("Wrong start date limit configuration for the access condition " throw new IllegalStateException("Wrong start date limit configuration for the access condition "
+ "option named " + option.getName()); + "option named " + option.getName());
@@ -106,7 +104,8 @@ public class SubmissionUploadRestRepository extends DSpaceRestRepository<Submiss
} }
if (StringUtils.isNotBlank(option.getEndDateLimit())) { if (StringUtils.isNotBlank(option.getEndDateLimit())) {
try { try {
optionRest.setMaxEndDate(dateMathParser.parseMath(option.getEndDateLimit())); Date requested = dateMathParser.parseMath(option.getEndDateLimit());
optionRest.setMaxEndDate(TimeHelpers.toMidnightUTC(requested));
} catch (ParseException e) { } catch (ParseException e) {
throw new IllegalStateException("Wrong end date limit configuration for the access condition " throw new IllegalStateException("Wrong end date limit configuration for the access condition "
+ "option named " + option.getName()); + "option named " + option.getName());

View File

@@ -6,9 +6,11 @@
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.app.rest.submit.factory.impl; package org.dspace.app.rest.submit.factory.impl;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -23,11 +25,12 @@ import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.submit.model.AccessConditionConfiguration; import org.dspace.submit.model.AccessConditionConfiguration;
import org.dspace.submit.model.AccessConditionConfigurationService; import org.dspace.submit.model.AccessConditionConfigurationService;
import org.dspace.util.TimeHelpers;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
* Submission "add" operation to add custom resource policies. * Submission "add" operation to add custom resource policies.
* *
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com) * @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/ */
public class AccessConditionAddPatchOperation extends AddPatchOperation<AccessConditionDTO> { public class AccessConditionAddPatchOperation extends AddPatchOperation<AccessConditionDTO> {
@@ -52,6 +55,18 @@ public class AccessConditionAddPatchOperation extends AddPatchOperation<AccessCo
String[] absolutePath = getAbsolutePath(path).split("/"); String[] absolutePath = getAbsolutePath(path).split("/");
List<AccessConditionDTO> accessConditions = parseAccessConditions(path, value, absolutePath); List<AccessConditionDTO> accessConditions = parseAccessConditions(path, value, absolutePath);
// Clamp access condition dates to midnight UTC
for (AccessConditionDTO condition : accessConditions) {
Date date = condition.getStartDate();
if (null != date) {
condition.setStartDate(TimeHelpers.toMidnightUTC(date));
}
date = condition.getEndDate();
if (null != date) {
condition.setEndDate(TimeHelpers.toMidnightUTC(date));
}
}
verifyAccessConditions(context, configuration, accessConditions); verifyAccessConditions(context, configuration, accessConditions);
if (absolutePath.length == 1) { if (absolutePath.length == 1) {
@@ -65,7 +80,7 @@ public class AccessConditionAddPatchOperation extends AddPatchOperation<AccessCo
} }
private List<AccessConditionDTO> parseAccessConditions(String path, Object value, String[] split) { private List<AccessConditionDTO> parseAccessConditions(String path, Object value, String[] split) {
List<AccessConditionDTO> accessConditions = new ArrayList<AccessConditionDTO>(); List<AccessConditionDTO> accessConditions = new ArrayList<>();
if (split.length == 1) { if (split.length == 1) {
accessConditions = evaluateArrayObject((LateObjectEvaluator) value); accessConditions = evaluateArrayObject((LateObjectEvaluator) value);
} else if (split.length == 2) { } else if (split.length == 2) {

View File

@@ -6,6 +6,7 @@
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.app.rest.submit.factory.impl; package org.dspace.app.rest.submit.factory.impl;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -29,6 +30,7 @@ import org.dspace.core.Context;
import org.dspace.submit.model.AccessConditionConfiguration; import org.dspace.submit.model.AccessConditionConfiguration;
import org.dspace.submit.model.AccessConditionConfigurationService; import org.dspace.submit.model.AccessConditionConfigurationService;
import org.dspace.submit.model.AccessConditionOption; import org.dspace.submit.model.AccessConditionOption;
import org.dspace.util.TimeHelpers;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -106,7 +108,7 @@ public class AccessConditionReplacePatchOperation extends ReplacePatchOperation<
return null; return null;
} }
private AccessConditionDTO createDTO(ResourcePolicy rpToReplace, String attributeReplace, String valueToReplare) private AccessConditionDTO createDTO(ResourcePolicy rpToReplace, String attributeReplace, String valueToReplace)
throws ParseException { throws ParseException {
AccessConditionDTO accessCondition = new AccessConditionDTO(); AccessConditionDTO accessCondition = new AccessConditionDTO();
accessCondition.setName(rpToReplace.getRpName()); accessCondition.setName(rpToReplace.getRpName());
@@ -114,13 +116,13 @@ public class AccessConditionReplacePatchOperation extends ReplacePatchOperation<
accessCondition.setEndDate(rpToReplace.getEndDate()); accessCondition.setEndDate(rpToReplace.getEndDate());
switch (attributeReplace) { switch (attributeReplace) {
case "name": case "name":
accessCondition.setName(valueToReplare); accessCondition.setName(valueToReplace);
return accessCondition; return accessCondition;
case "startDate": case "startDate":
accessCondition.setStartDate(parseDate(valueToReplare)); accessCondition.setStartDate(TimeHelpers.toMidnightUTC(parseDate(valueToReplace)));
return accessCondition; return accessCondition;
case "endDate": case "endDate":
accessCondition.setEndDate(parseDate(valueToReplare)); accessCondition.setEndDate(TimeHelpers.toMidnightUTC(parseDate(valueToReplace)));
return accessCondition; return accessCondition;
default: default:
throw new UnprocessableEntityException("The provided attribute: " throw new UnprocessableEntityException("The provided attribute: "
@@ -128,17 +130,17 @@ public class AccessConditionReplacePatchOperation extends ReplacePatchOperation<
} }
} }
private void updatePolicy(Context context, String valueToReplare, String attributeReplace, private void updatePolicy(Context context, String valueToReplace, String attributeReplace,
ResourcePolicy rpToReplace) throws SQLException, AuthorizeException { ResourcePolicy rpToReplace) throws SQLException, AuthorizeException {
switch (attributeReplace) { switch (attributeReplace) {
case "name": case "name":
rpToReplace.setRpName(valueToReplare); rpToReplace.setRpName(valueToReplace);
break; break;
case "startDate": case "startDate":
rpToReplace.setStartDate(parseDate(valueToReplare)); rpToReplace.setStartDate(TimeHelpers.toMidnightUTC(parseDate(valueToReplace)));
break; break;
case "endDate": case "endDate":
rpToReplace.setEndDate(parseDate(valueToReplare)); rpToReplace.setEndDate(TimeHelpers.toMidnightUTC(parseDate(valueToReplace)));
break; break;
default: default:
throw new IllegalArgumentException("Attribute to replace is not valid:" + attributeReplace); throw new IllegalArgumentException("Attribute to replace is not valid:" + attributeReplace);