mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-19 07:53:08 +00:00
Merge remote-tracking branch '4science-bitbucket/main' into CST-6751
This commit is contained in:
@@ -0,0 +1,140 @@
|
|||||||
|
/**
|
||||||
|
* 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.administer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.cli.ParseException;
|
||||||
|
import org.apache.commons.lang.time.DateUtils;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.ProcessStatus;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.scripts.DSpaceRunnable;
|
||||||
|
import org.dspace.scripts.Process;
|
||||||
|
import org.dspace.scripts.factory.ScriptServiceFactory;
|
||||||
|
import org.dspace.scripts.service.ProcessService;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
|
import org.dspace.utils.DSpace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script to cleanup the old processes in the specified state.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProcessCleaner extends DSpaceRunnable<ProcessCleanerConfiguration<ProcessCleaner>> {
|
||||||
|
|
||||||
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
private ProcessService processService;
|
||||||
|
|
||||||
|
|
||||||
|
private boolean cleanCompleted = false;
|
||||||
|
|
||||||
|
private boolean cleanFailed = false;
|
||||||
|
|
||||||
|
private boolean cleanRunning = false;
|
||||||
|
|
||||||
|
private boolean help = false;
|
||||||
|
|
||||||
|
private Integer days;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup() throws ParseException {
|
||||||
|
|
||||||
|
this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||||
|
this.processService = ScriptServiceFactory.getInstance().getProcessService();
|
||||||
|
|
||||||
|
this.help = commandLine.hasOption('h');
|
||||||
|
this.cleanFailed = commandLine.hasOption('f');
|
||||||
|
this.cleanRunning = commandLine.hasOption('r');
|
||||||
|
this.cleanCompleted = commandLine.hasOption('c') || (!cleanFailed && !cleanRunning);
|
||||||
|
|
||||||
|
this.days = configurationService.getIntProperty("process-cleaner.days", 14);
|
||||||
|
|
||||||
|
if (this.days <= 0) {
|
||||||
|
throw new IllegalStateException("The number of days must be a positive integer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalRun() throws Exception {
|
||||||
|
|
||||||
|
if (help) {
|
||||||
|
printHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context context = new Context();
|
||||||
|
|
||||||
|
try {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
performDeletion(context);
|
||||||
|
} finally {
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
context.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the processes based on the specified statuses and the configured days
|
||||||
|
* from their creation.
|
||||||
|
*/
|
||||||
|
private void performDeletion(Context context) throws SQLException, IOException, AuthorizeException {
|
||||||
|
|
||||||
|
List<ProcessStatus> statuses = getProcessToDeleteStatuses();
|
||||||
|
Date creationDate = calculateCreationDate();
|
||||||
|
|
||||||
|
handler.logInfo("Searching for processes with status: " + statuses);
|
||||||
|
List<Process> processes = processService.findByStatusAndCreationTimeOlderThan(context, statuses, creationDate);
|
||||||
|
handler.logInfo("Found " + processes.size() + " processes to be deleted");
|
||||||
|
for (Process process : processes) {
|
||||||
|
processService.delete(context, process);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.logInfo("Process cleanup completed");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of Process statuses do be deleted.
|
||||||
|
*/
|
||||||
|
private List<ProcessStatus> getProcessToDeleteStatuses() {
|
||||||
|
List<ProcessStatus> statuses = new ArrayList<ProcessStatus>();
|
||||||
|
if (cleanCompleted) {
|
||||||
|
statuses.add(ProcessStatus.COMPLETED);
|
||||||
|
}
|
||||||
|
if (cleanFailed) {
|
||||||
|
statuses.add(ProcessStatus.FAILED);
|
||||||
|
}
|
||||||
|
if (cleanRunning) {
|
||||||
|
statuses.add(ProcessStatus.RUNNING);
|
||||||
|
}
|
||||||
|
return statuses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date calculateCreationDate() {
|
||||||
|
return DateUtils.addDays(new Date(), -days);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ProcessCleanerConfiguration<ProcessCleaner> getScriptConfiguration() {
|
||||||
|
return new DSpace().getServiceManager()
|
||||||
|
.getServiceByName("process-cleaner", ProcessCleanerConfiguration.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.administer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ProcessCleaner} for CLI.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProcessCleanerCli extends ProcessCleaner {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.administer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ProcessCleanerConfiguration} for CLI.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProcessCleanerCliConfiguration extends ProcessCleanerConfiguration<ProcessCleanerCli> {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* 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.administer;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.apache.commons.cli.Options;
|
||||||
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ScriptConfiguration} for the {@link ProcessCleaner} script.
|
||||||
|
*/
|
||||||
|
public class ProcessCleanerConfiguration<T extends ProcessCleaner> extends ScriptConfiguration<T> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthorizeService authorizeService;
|
||||||
|
|
||||||
|
private Class<T> dspaceRunnableClass;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAllowedToExecute(Context context) {
|
||||||
|
try {
|
||||||
|
return authorizeService.isAdmin(context);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Options getOptions() {
|
||||||
|
if (options == null) {
|
||||||
|
|
||||||
|
Options options = new Options();
|
||||||
|
|
||||||
|
options.addOption("h", "help", false, "help");
|
||||||
|
|
||||||
|
options.addOption("r", "running", false, "delete the process with RUNNING status");
|
||||||
|
options.getOption("r").setType(boolean.class);
|
||||||
|
|
||||||
|
options.addOption("f", "failed", false, "delete the process with FAILED status");
|
||||||
|
options.getOption("f").setType(boolean.class);
|
||||||
|
|
||||||
|
options.addOption("c", "completed", false,
|
||||||
|
"delete the process with COMPLETED status (default if no statuses are specified)");
|
||||||
|
options.getOption("c").setType(boolean.class);
|
||||||
|
|
||||||
|
super.options = options;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getDspaceRunnableClass() {
|
||||||
|
return dspaceRunnableClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
|
||||||
|
this.dspaceRunnableClass = dspaceRunnableClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.content.Collection;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive request recipients from groups of the Collection which owns an Item.
|
||||||
|
* The list will include all members of the administrators group. If the
|
||||||
|
* resulting list is empty, delegates to {@link RequestItemHelpdeskStrategy}.
|
||||||
|
*
|
||||||
|
* @author Mark H. Wood <mwood@iupui.edu>
|
||||||
|
*/
|
||||||
|
public class CollectionAdministratorsRequestItemStrategy
|
||||||
|
extends RequestItemHelpdeskStrategy {
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public List<RequestItemAuthor> getRequestItemAuthor(Context context,
|
||||||
|
Item item)
|
||||||
|
throws SQLException {
|
||||||
|
List<RequestItemAuthor> recipients = new ArrayList<>();
|
||||||
|
Collection collection = item.getOwningCollection();
|
||||||
|
for (EPerson admin : collection.getAdministrators().getMembers()) {
|
||||||
|
recipients.add(new RequestItemAuthor(admin));
|
||||||
|
}
|
||||||
|
if (recipients.isEmpty()) {
|
||||||
|
return super.getRequestItemAuthor(context, item);
|
||||||
|
} else {
|
||||||
|
return recipients;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assemble a list of recipients from the results of other strategies.
|
||||||
|
* The list of strategy classes is injected as the constructor argument
|
||||||
|
* {@code strategies}.
|
||||||
|
* If the strategy list is not configured, returns an empty List.
|
||||||
|
*
|
||||||
|
* @author Mark H. Wood <mwood@iupui.edu>
|
||||||
|
*/
|
||||||
|
public class CombiningRequestItemStrategy
|
||||||
|
implements RequestItemAuthorExtractor {
|
||||||
|
/** The strategies to combine. */
|
||||||
|
private final List<RequestItemAuthorExtractor> strategies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a combination of strategies.
|
||||||
|
* @param strategies the author extraction strategies to combine.
|
||||||
|
*/
|
||||||
|
public CombiningRequestItemStrategy(@NonNull List<RequestItemAuthorExtractor> strategies) {
|
||||||
|
Assert.notNull(strategies, "Strategy list may not be null");
|
||||||
|
this.strategies = strategies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not call.
|
||||||
|
* @throws IllegalArgumentException always
|
||||||
|
*/
|
||||||
|
private CombiningRequestItemStrategy() {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public List<RequestItemAuthor> getRequestItemAuthor(Context context, Item item)
|
||||||
|
throws SQLException {
|
||||||
|
List<RequestItemAuthor> recipients = new ArrayList<>();
|
||||||
|
|
||||||
|
for (RequestItemAuthorExtractor strategy : strategies) {
|
||||||
|
recipients.addAll(strategy.getRequestItemAuthor(context, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
return recipients;
|
||||||
|
}
|
||||||
|
}
|
@@ -27,7 +27,7 @@ import org.dspace.core.Context;
|
|||||||
import org.dspace.core.ReloadableEntity;
|
import org.dspace.core.ReloadableEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object representing an Item Request
|
* Object representing an Item Request.
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "requestitem")
|
@Table(name = "requestitem")
|
||||||
@@ -94,6 +94,9 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
|||||||
this.allfiles = allfiles;
|
this.allfiles = allfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if all of the Item's files are requested.
|
||||||
|
*/
|
||||||
public boolean isAllfiles() {
|
public boolean isAllfiles() {
|
||||||
return allfiles;
|
return allfiles;
|
||||||
}
|
}
|
||||||
@@ -102,6 +105,9 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
|||||||
this.reqMessage = reqMessage;
|
this.reqMessage = reqMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a message from the requester.
|
||||||
|
*/
|
||||||
public String getReqMessage() {
|
public String getReqMessage() {
|
||||||
return reqMessage;
|
return reqMessage;
|
||||||
}
|
}
|
||||||
@@ -110,6 +116,9 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
|||||||
this.reqName = reqName;
|
this.reqName = reqName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Human-readable name of the user requesting access.
|
||||||
|
*/
|
||||||
public String getReqName() {
|
public String getReqName() {
|
||||||
return reqName;
|
return reqName;
|
||||||
}
|
}
|
||||||
@@ -118,6 +127,9 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
|||||||
this.reqEmail = reqEmail;
|
this.reqEmail = reqEmail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return address of the user requesting access.
|
||||||
|
*/
|
||||||
public String getReqEmail() {
|
public String getReqEmail() {
|
||||||
return reqEmail;
|
return reqEmail;
|
||||||
}
|
}
|
||||||
@@ -126,6 +138,9 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
|||||||
this.token = token;
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a unique request identifier which can be emailed.
|
||||||
|
*/
|
||||||
public String getToken() {
|
public String getToken() {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
@@ -11,20 +11,31 @@ import org.dspace.eperson.EPerson;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple DTO to transfer data about the corresponding author for the Request
|
* Simple DTO to transfer data about the corresponding author for the Request
|
||||||
* Copy feature
|
* Copy feature.
|
||||||
*
|
*
|
||||||
* @author Andrea Bollini
|
* @author Andrea Bollini
|
||||||
*/
|
*/
|
||||||
public class RequestItemAuthor {
|
public class RequestItemAuthor {
|
||||||
private String fullName;
|
private final String fullName;
|
||||||
private String email;
|
private final String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an author record from given data.
|
||||||
|
*
|
||||||
|
* @param fullName the author's full name.
|
||||||
|
* @param email the author's email address.
|
||||||
|
*/
|
||||||
public RequestItemAuthor(String fullName, String email) {
|
public RequestItemAuthor(String fullName, String email) {
|
||||||
super();
|
super();
|
||||||
this.fullName = fullName;
|
this.fullName = fullName;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an author from an EPerson's metadata.
|
||||||
|
*
|
||||||
|
* @param ePerson the EPerson.
|
||||||
|
*/
|
||||||
public RequestItemAuthor(EPerson ePerson) {
|
public RequestItemAuthor(EPerson ePerson) {
|
||||||
super();
|
super();
|
||||||
this.fullName = ePerson.getFullName();
|
this.fullName = ePerson.getFullName();
|
||||||
|
@@ -8,26 +8,28 @@
|
|||||||
package org.dspace.app.requestitem;
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to abstract the strategy for select the author to contact for
|
* Interface to abstract the strategy for selecting the author to contact for
|
||||||
* request copy
|
* request copy.
|
||||||
*
|
*
|
||||||
* @author Andrea Bollini
|
* @author Andrea Bollini
|
||||||
*/
|
*/
|
||||||
public interface RequestItemAuthorExtractor {
|
public interface RequestItemAuthorExtractor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the auhtor to contact for a request copy of the give item.
|
* Retrieve the author to contact for requesting a copy of the given item.
|
||||||
*
|
*
|
||||||
* @param context DSpace context object
|
* @param context DSpace context object
|
||||||
* @param item item to request
|
* @param item item to request
|
||||||
* @return An object containing name an email address to send the request to
|
* @return Names and email addresses to send the request to.
|
||||||
* or null if no valid email address was found.
|
|
||||||
* @throws SQLException if database error
|
* @throws SQLException if database error
|
||||||
*/
|
*/
|
||||||
public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException;
|
@NonNull
|
||||||
|
public List<RequestItemAuthor> getRequestItemAuthor(Context context, Item item)
|
||||||
|
throws SQLException;
|
||||||
}
|
}
|
||||||
|
@@ -72,28 +72,48 @@ public class RequestItemEmailNotifier {
|
|||||||
static public void sendRequest(Context context, RequestItem ri, String responseLink)
|
static public void sendRequest(Context context, RequestItem ri, String responseLink)
|
||||||
throws IOException, SQLException {
|
throws IOException, SQLException {
|
||||||
// Who is making this request?
|
// Who is making this request?
|
||||||
RequestItemAuthor author = requestItemAuthorExtractor
|
List<RequestItemAuthor> authors = requestItemAuthorExtractor
|
||||||
.getRequestItemAuthor(context, ri.getItem());
|
.getRequestItemAuthor(context, ri.getItem());
|
||||||
String authorEmail = author.getEmail();
|
|
||||||
String authorName = author.getFullName();
|
|
||||||
|
|
||||||
// Build an email to the approver.
|
// Build an email to the approver.
|
||||||
Email email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
|
Email email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
|
||||||
"request_item.author"));
|
"request_item.author"));
|
||||||
email.addRecipient(authorEmail);
|
for (RequestItemAuthor author : authors) {
|
||||||
|
email.addRecipient(author.getEmail());
|
||||||
|
}
|
||||||
email.setReplyTo(ri.getReqEmail()); // Requester's address
|
email.setReplyTo(ri.getReqEmail()); // Requester's address
|
||||||
|
|
||||||
email.addArgument(ri.getReqName()); // {0} Requester's name
|
email.addArgument(ri.getReqName()); // {0} Requester's name
|
||||||
|
|
||||||
email.addArgument(ri.getReqEmail()); // {1} Requester's address
|
email.addArgument(ri.getReqEmail()); // {1} Requester's address
|
||||||
|
|
||||||
email.addArgument(ri.isAllfiles() // {2} All bitstreams or just one?
|
email.addArgument(ri.isAllfiles() // {2} All bitstreams or just one?
|
||||||
? I18nUtil.getMessage("itemRequest.all") : ri.getBitstream().getName());
|
? I18nUtil.getMessage("itemRequest.all") : ri.getBitstream().getName());
|
||||||
email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle()));
|
|
||||||
|
email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle())); // {3}
|
||||||
|
|
||||||
email.addArgument(ri.getItem().getName()); // {4} requested item's title
|
email.addArgument(ri.getItem().getName()); // {4} requested item's title
|
||||||
|
|
||||||
email.addArgument(ri.getReqMessage()); // {5} message from requester
|
email.addArgument(ri.getReqMessage()); // {5} message from requester
|
||||||
|
|
||||||
email.addArgument(responseLink); // {6} Link back to DSpace for action
|
email.addArgument(responseLink); // {6} Link back to DSpace for action
|
||||||
email.addArgument(authorName); // {7} corresponding author name
|
|
||||||
email.addArgument(authorEmail); // {8} corresponding author email
|
StringBuilder names = new StringBuilder();
|
||||||
email.addArgument(configurationService.getProperty("dspace.name"));
|
StringBuilder addresses = new StringBuilder();
|
||||||
email.addArgument(configurationService.getProperty("mail.helpdesk"));
|
for (RequestItemAuthor author : authors) {
|
||||||
|
if (names.length() > 0) {
|
||||||
|
names.append("; ");
|
||||||
|
addresses.append("; ");
|
||||||
|
}
|
||||||
|
names.append(author.getFullName());
|
||||||
|
addresses.append(author.getEmail());
|
||||||
|
}
|
||||||
|
email.addArgument(names.toString()); // {7} corresponding author name
|
||||||
|
email.addArgument(addresses.toString()); // {8} corresponding author email
|
||||||
|
|
||||||
|
email.addArgument(configurationService.getProperty("dspace.name")); // {9}
|
||||||
|
|
||||||
|
email.addArgument(configurationService.getProperty("mail.helpdesk")); // {10}
|
||||||
|
|
||||||
// Send the email.
|
// Send the email.
|
||||||
try {
|
try {
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
package org.dspace.app.requestitem;
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
@@ -16,11 +18,11 @@ import org.dspace.core.I18nUtil;
|
|||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.service.EPersonService;
|
import org.dspace.eperson.service.EPersonService;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RequestItem strategy to allow DSpace support team's helpdesk to receive requestItem request
|
* RequestItem strategy to allow DSpace support team's helpdesk to receive requestItem request.
|
||||||
* With this enabled, then the Item author/submitter doesn't receive the request, but the helpdesk instead does.
|
* With this enabled, then the Item author/submitter doesn't receive the request, but the helpdesk instead does.
|
||||||
*
|
*
|
||||||
* Failover to the RequestItemSubmitterStrategy, which means the submitter would get the request if there is no
|
* Failover to the RequestItemSubmitterStrategy, which means the submitter would get the request if there is no
|
||||||
@@ -33,19 +35,24 @@ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy {
|
|||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
protected EPersonService ePersonService;
|
protected EPersonService ePersonService;
|
||||||
|
|
||||||
|
@Autowired(required = true)
|
||||||
|
private ConfigurationService configuration;
|
||||||
|
|
||||||
public RequestItemHelpdeskStrategy() {
|
public RequestItemHelpdeskStrategy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException {
|
@NonNull
|
||||||
ConfigurationService configurationService
|
public List<RequestItemAuthor> getRequestItemAuthor(Context context, Item item)
|
||||||
= DSpaceServicesFactory.getInstance().getConfigurationService();
|
throws SQLException {
|
||||||
boolean helpdeskOverridesSubmitter = configurationService
|
boolean helpdeskOverridesSubmitter = configuration
|
||||||
.getBooleanProperty("request.item.helpdesk.override", false);
|
.getBooleanProperty("request.item.helpdesk.override", false);
|
||||||
String helpDeskEmail = configurationService.getProperty("mail.helpdesk");
|
String helpDeskEmail = configuration.getProperty("mail.helpdesk");
|
||||||
|
|
||||||
if (helpdeskOverridesSubmitter && StringUtils.isNotBlank(helpDeskEmail)) {
|
if (helpdeskOverridesSubmitter && StringUtils.isNotBlank(helpDeskEmail)) {
|
||||||
return getHelpDeskPerson(context, helpDeskEmail);
|
List<RequestItemAuthor> authors = new ArrayList<>(1);
|
||||||
|
authors.add(getHelpDeskPerson(context, helpDeskEmail));
|
||||||
|
return authors;
|
||||||
} else {
|
} else {
|
||||||
//Fallback to default logic (author of Item) if helpdesk isn't fully enabled or setup
|
//Fallback to default logic (author of Item) if helpdesk isn't fully enabled or setup
|
||||||
return super.getRequestItemAuthor(context, item);
|
return super.getRequestItemAuthor(context, item);
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
package org.dspace.app.requestitem;
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -16,12 +18,13 @@ import org.dspace.content.MetadataValue;
|
|||||||
import org.dspace.content.service.ItemService;
|
import org.dspace.content.service.ItemService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.core.I18nUtil;
|
import org.dspace.core.I18nUtil;
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to look to an item metadata for the corresponding author name and email.
|
* Try to look to an item metadata for the corresponding author name and email.
|
||||||
* Failover to the RequestItemSubmitterStrategy
|
* Failover to the RequestItemSubmitterStrategy.
|
||||||
*
|
*
|
||||||
* @author Andrea Bollini
|
* @author Andrea Bollini
|
||||||
*/
|
*/
|
||||||
@@ -30,6 +33,9 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy {
|
|||||||
protected String emailMetadata;
|
protected String emailMetadata;
|
||||||
protected String fullNameMetadata;
|
protected String fullNameMetadata;
|
||||||
|
|
||||||
|
@Autowired(required = true)
|
||||||
|
protected ConfigurationService configurationService;
|
||||||
|
|
||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
protected ItemService itemService;
|
protected ItemService itemService;
|
||||||
|
|
||||||
@@ -37,59 +43,72 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
|
@NonNull
|
||||||
|
public List<RequestItemAuthor> getRequestItemAuthor(Context context, Item item)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
RequestItemAuthor author = null;
|
List<RequestItemAuthor> authors;
|
||||||
if (emailMetadata != null) {
|
if (emailMetadata != null) {
|
||||||
List<MetadataValue> vals = itemService.getMetadataByMetadataString(item, emailMetadata);
|
List<MetadataValue> vals = itemService.getMetadataByMetadataString(item, emailMetadata);
|
||||||
if (vals.size() > 0) {
|
List<MetadataValue> nameVals;
|
||||||
String email = vals.iterator().next().getValue();
|
if (null != fullNameMetadata) {
|
||||||
String fullname = null;
|
nameVals = itemService.getMetadataByMetadataString(item, fullNameMetadata);
|
||||||
if (fullNameMetadata != null) {
|
} else {
|
||||||
List<MetadataValue> nameVals = itemService.getMetadataByMetadataString(item, fullNameMetadata);
|
nameVals = Collections.EMPTY_LIST;
|
||||||
if (nameVals.size() > 0) {
|
}
|
||||||
fullname = nameVals.iterator().next().getValue();
|
boolean useNames = vals.size() == nameVals.size();
|
||||||
|
if (!vals.isEmpty()) {
|
||||||
|
authors = new ArrayList<>(vals.size());
|
||||||
|
for (int authorIndex = 0; authorIndex < vals.size(); authorIndex++) {
|
||||||
|
String email = vals.get(authorIndex).getValue();
|
||||||
|
String fullname = null;
|
||||||
|
if (useNames) {
|
||||||
|
fullname = nameVals.get(authorIndex).getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(fullname)) {
|
||||||
|
fullname = I18nUtil.getMessage(
|
||||||
|
"org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed",
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
RequestItemAuthor author = new RequestItemAuthor(
|
||||||
|
fullname, email);
|
||||||
|
authors.add(author);
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(fullname)) {
|
return authors;
|
||||||
fullname = I18nUtil
|
} else {
|
||||||
.getMessage(
|
return Collections.EMPTY_LIST;
|
||||||
"org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed",
|
|
||||||
context);
|
|
||||||
}
|
|
||||||
author = new RequestItemAuthor(fullname, email);
|
|
||||||
return author;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Uses the basic strategy to look for the original submitter
|
// Uses the basic strategy to look for the original submitter
|
||||||
author = super.getRequestItemAuthor(context, item);
|
authors = super.getRequestItemAuthor(context, item);
|
||||||
// Is the author or their email null. If so get the help desk or admin name and email
|
|
||||||
if (null == author || null == author.getEmail()) {
|
// Remove from the list authors that do not have email addresses.
|
||||||
String email = null;
|
for (RequestItemAuthor author : authors) {
|
||||||
String name = null;
|
if (null == author.getEmail()) {
|
||||||
|
authors.remove(author);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authors.isEmpty()) { // No author email addresses! Fall back
|
||||||
//First get help desk name and email
|
//First get help desk name and email
|
||||||
email = DSpaceServicesFactory.getInstance()
|
String email = configurationService.getProperty("mail.helpdesk");
|
||||||
.getConfigurationService().getProperty("mail.helpdesk");
|
String name = configurationService.getProperty("mail.helpdesk.name");
|
||||||
name = DSpaceServicesFactory.getInstance()
|
|
||||||
.getConfigurationService().getProperty("mail.helpdesk.name");
|
|
||||||
// If help desk mail is null get the mail and name of admin
|
// If help desk mail is null get the mail and name of admin
|
||||||
if (email == null) {
|
if (email == null) {
|
||||||
email = DSpaceServicesFactory.getInstance()
|
email = configurationService.getProperty("mail.admin");
|
||||||
.getConfigurationService().getProperty("mail.admin");
|
name = configurationService.getProperty("mail.admin.name");
|
||||||
name = DSpaceServicesFactory.getInstance()
|
|
||||||
.getConfigurationService().getProperty("mail.admin.name");
|
|
||||||
}
|
}
|
||||||
author = new RequestItemAuthor(name, email);
|
authors.add(new RequestItemAuthor(name, email));
|
||||||
}
|
}
|
||||||
|
return authors;
|
||||||
}
|
}
|
||||||
return author;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEmailMetadata(String emailMetadata) {
|
public void setEmailMetadata(@NonNull String emailMetadata) {
|
||||||
this.emailMetadata = emailMetadata;
|
this.emailMetadata = emailMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFullNameMetadata(String fullNameMetadata) {
|
public void setFullNameMetadata(@NonNull String fullNameMetadata) {
|
||||||
this.fullNameMetadata = fullNameMetadata;
|
this.fullNameMetadata = fullNameMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,10 +8,13 @@
|
|||||||
package org.dspace.app.requestitem;
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic strategy that looks to the original submitter.
|
* Basic strategy that looks to the original submitter.
|
||||||
@@ -24,21 +27,23 @@ public class RequestItemSubmitterStrategy implements RequestItemAuthorExtractor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the submitter of an Item as RequestItemAuthor or null if the
|
* Returns the submitter of an Item as RequestItemAuthor or an empty List if
|
||||||
* Submitter is deleted.
|
* the Submitter is deleted.
|
||||||
*
|
*
|
||||||
* @return The submitter of the item or null if the submitter is deleted
|
* @return The submitter of the item or empty List if the submitter is deleted
|
||||||
* @throws SQLException if database error
|
* @throws SQLException if database error
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
|
@NonNull
|
||||||
|
public List<RequestItemAuthor> getRequestItemAuthor(Context context, Item item)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
EPerson submitter = item.getSubmitter();
|
EPerson submitter = item.getSubmitter();
|
||||||
RequestItemAuthor author = null;
|
List<RequestItemAuthor> authors = new ArrayList<>(1);
|
||||||
if (null != submitter) {
|
if (null != submitter) {
|
||||||
author = new RequestItemAuthor(
|
RequestItemAuthor author = new RequestItemAuthor(
|
||||||
submitter.getFullName(), submitter.getEmail());
|
submitter.getFullName(), submitter.getEmail());
|
||||||
|
authors.add(author);
|
||||||
}
|
}
|
||||||
return author;
|
return authors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ import com.rometools.modules.opensearch.OpenSearchModule;
|
|||||||
import com.rometools.modules.opensearch.entity.OSQuery;
|
import com.rometools.modules.opensearch.entity.OSQuery;
|
||||||
import com.rometools.modules.opensearch.impl.OpenSearchModuleImpl;
|
import com.rometools.modules.opensearch.impl.OpenSearchModuleImpl;
|
||||||
import com.rometools.rome.io.FeedException;
|
import com.rometools.rome.io.FeedException;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.util.service.OpenSearchService;
|
import org.dspace.app.util.service.OpenSearchService;
|
||||||
import org.dspace.content.DSpaceObject;
|
import org.dspace.content.DSpaceObject;
|
||||||
@@ -96,7 +97,7 @@ public class OpenSearchServiceImpl implements OpenSearchService {
|
|||||||
* Get base search UI URL (websvc.opensearch.uicontext)
|
* Get base search UI URL (websvc.opensearch.uicontext)
|
||||||
*/
|
*/
|
||||||
protected String getBaseSearchUIURL() {
|
protected String getBaseSearchUIURL() {
|
||||||
return configurationService.getProperty("dspace.server.url") + "/" +
|
return configurationService.getProperty("dspace.ui.url") + "/" +
|
||||||
configurationService.getProperty("websvc.opensearch.uicontext");
|
configurationService.getProperty("websvc.opensearch.uicontext");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +178,9 @@ public class OpenSearchServiceImpl implements OpenSearchService {
|
|||||||
OSQuery osq = new OSQuery();
|
OSQuery osq = new OSQuery();
|
||||||
osq.setRole("request");
|
osq.setRole("request");
|
||||||
try {
|
try {
|
||||||
osq.setSearchTerms(URLEncoder.encode(query, "UTF-8"));
|
if (StringUtils.isNotBlank(query)) {
|
||||||
|
osq.setSearchTerms(URLEncoder.encode(query, "UTF-8"));
|
||||||
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.authorize;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.dspace.authorize.service.PasswordValidatorService;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link PasswordValidatorService} that verifies if the given
|
||||||
|
* passowrd matches the configured pattern.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*/
|
||||||
|
public class RegexPasswordValidator implements PasswordValidatorService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPasswordValidationEnabled() {
|
||||||
|
return isNotBlank(getPasswordValidationPattern());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPasswordValid(String password) {
|
||||||
|
if (!isPasswordValidationEnabled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern pattern = Pattern.compile(getPasswordValidationPattern());
|
||||||
|
return pattern.matcher(password).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPasswordValidationPattern() {
|
||||||
|
return configurationService.getProperty("authentication-password.regex-validation.pattern");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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.authorize;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.authorize.service.PasswordValidatorService;
|
||||||
|
import org.dspace.authorize.service.ValidatePasswordService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic implementation for validation password robustness.
|
||||||
|
*
|
||||||
|
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||||
|
*/
|
||||||
|
public class ValidatePasswordServiceImpl implements ValidatePasswordService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private List<PasswordValidatorService> validators;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPasswordValid(String password) {
|
||||||
|
return validators.stream()
|
||||||
|
.filter(passwordValidator -> passwordValidator.isPasswordValidationEnabled())
|
||||||
|
.allMatch(passwordValidator -> passwordValidator.isPasswordValid(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.authorize.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for classes that validate a given password with a specific
|
||||||
|
* strategy.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*/
|
||||||
|
public interface PasswordValidatorService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the password validator is active.
|
||||||
|
*/
|
||||||
|
public boolean isPasswordValidationEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks whether the password is valid
|
||||||
|
*
|
||||||
|
* @param password password to validate
|
||||||
|
*/
|
||||||
|
public boolean isPasswordValid(String password);
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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.authorize.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Services to use during Validating of password.
|
||||||
|
*
|
||||||
|
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||||
|
*/
|
||||||
|
public interface ValidatePasswordService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks whether the password is valid based on the configured
|
||||||
|
* rules/strategies.
|
||||||
|
*
|
||||||
|
* @param password password to validate
|
||||||
|
*/
|
||||||
|
public boolean isPasswordValid(String password);
|
||||||
|
|
||||||
|
}
|
@@ -8,8 +8,10 @@
|
|||||||
package org.dspace.content.dao;
|
package org.dspace.content.dao;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.content.ProcessStatus;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.core.GenericDAO;
|
import org.dspace.core.GenericDAO;
|
||||||
import org.dspace.scripts.Process;
|
import org.dspace.scripts.Process;
|
||||||
@@ -81,4 +83,18 @@ public interface ProcessDAO extends GenericDAO<Process> {
|
|||||||
|
|
||||||
int countTotalWithParameters(Context context, ProcessQueryParameterContainer processQueryParameterContainer)
|
int countTotalWithParameters(Context context, ProcessQueryParameterContainer processQueryParameterContainer)
|
||||||
throws SQLException;
|
throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all the processes with one of the given status and with a creation time
|
||||||
|
* older than the specified date.
|
||||||
|
*
|
||||||
|
* @param context The relevant DSpace context
|
||||||
|
* @param statuses the statuses of the processes to search for
|
||||||
|
* @param date the creation date to search for
|
||||||
|
* @return The list of all Processes which match requirements
|
||||||
|
* @throws SQLException If something goes wrong
|
||||||
|
*/
|
||||||
|
List<Process> findByStatusAndCreationTimeOlderThan(Context context, List<ProcessStatus> statuses, Date date)
|
||||||
|
throws SQLException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.content.dao.impl;
|
package org.dspace.content.dao.impl;
|
||||||
|
|
||||||
|
import static org.dspace.scripts.Process_.CREATION_TIME;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -17,6 +20,7 @@ import javax.persistence.criteria.Predicate;
|
|||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.dspace.content.ProcessStatus;
|
||||||
import org.dspace.content.dao.ProcessDAO;
|
import org.dspace.content.dao.ProcessDAO;
|
||||||
import org.dspace.core.AbstractHibernateDAO;
|
import org.dspace.core.AbstractHibernateDAO;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
@@ -147,6 +151,23 @@ public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Process> findByStatusAndCreationTimeOlderThan(Context context, List<ProcessStatus> statuses,
|
||||||
|
Date date) throws SQLException {
|
||||||
|
|
||||||
|
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||||
|
CriteriaQuery<Process> criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
|
||||||
|
|
||||||
|
Root<Process> processRoot = criteriaQuery.from(Process.class);
|
||||||
|
criteriaQuery.select(processRoot);
|
||||||
|
|
||||||
|
Predicate creationTimeLessThanGivenDate = criteriaBuilder.lessThan(processRoot.get(CREATION_TIME), date);
|
||||||
|
Predicate statusIn = processRoot.get(Process_.PROCESS_STATUS).in(statuses);
|
||||||
|
criteriaQuery.where(criteriaBuilder.and(creationTimeLessThanGivenDate, statusIn));
|
||||||
|
|
||||||
|
return list(context, criteriaQuery, false, Process.class, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
package org.dspace.curate;
|
package org.dspace.ctask.general;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -18,6 +18,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
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.factory.AuthorizeServiceFactory;
|
||||||
|
import org.dspace.authorize.service.ResourcePolicyService;
|
||||||
import org.dspace.content.Bitstream;
|
import org.dspace.content.Bitstream;
|
||||||
import org.dspace.content.Bundle;
|
import org.dspace.content.Bundle;
|
||||||
import org.dspace.content.DSpaceObject;
|
import org.dspace.content.DSpaceObject;
|
||||||
@@ -26,6 +29,10 @@ import org.dspace.content.factory.ContentServiceFactory;
|
|||||||
import org.dspace.content.service.BitstreamService;
|
import org.dspace.content.service.BitstreamService;
|
||||||
import org.dspace.content.service.BundleService;
|
import org.dspace.content.service.BundleService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.curate.AbstractCurationTask;
|
||||||
|
import org.dspace.curate.Curator;
|
||||||
|
import org.dspace.curate.Distributive;
|
||||||
|
import org.dspace.curate.Mutative;
|
||||||
import org.dspace.disseminate.factory.DisseminateServiceFactory;
|
import org.dspace.disseminate.factory.DisseminateServiceFactory;
|
||||||
import org.dspace.disseminate.service.CitationDocumentService;
|
import org.dspace.disseminate.service.CitationDocumentService;
|
||||||
|
|
||||||
@@ -67,6 +74,10 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
|
|
||||||
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
||||||
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
|
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
|
||||||
|
protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance()
|
||||||
|
.getResourcePolicyService();
|
||||||
|
|
||||||
|
private Map<String,Bitstream> displayMap = new HashMap<String,Bitstream>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
@@ -95,10 +106,13 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
protected void performItem(Item item) throws SQLException {
|
protected void performItem(Item item) throws SQLException {
|
||||||
//Determine if the DISPLAY bundle exits. If not, create it.
|
//Determine if the DISPLAY bundle exits. If not, create it.
|
||||||
List<Bundle> dBundles = itemService.getBundles(item, CitationPage.DISPLAY_BUNDLE_NAME);
|
List<Bundle> dBundles = itemService.getBundles(item, CitationPage.DISPLAY_BUNDLE_NAME);
|
||||||
|
Bundle original = itemService.getBundles(item, "ORIGINAL").get(0);
|
||||||
Bundle dBundle = null;
|
Bundle dBundle = null;
|
||||||
if (dBundles == null || dBundles.isEmpty()) {
|
if (dBundles == null || dBundles.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
dBundle = bundleService.create(Curator.curationContext(), item, CitationPage.DISPLAY_BUNDLE_NAME);
|
dBundle = bundleService.create(Curator.curationContext(), item, CitationPage.DISPLAY_BUNDLE_NAME);
|
||||||
|
// don't inherit now otherwise they will be copied over the moved bitstreams
|
||||||
|
resourcePolicyService.removeAllPolicies(Curator.curationContext(), dBundle);
|
||||||
} catch (AuthorizeException e) {
|
} catch (AuthorizeException e) {
|
||||||
log.error("User not authroized to create bundle on item \"{}\": {}",
|
log.error("User not authroized to create bundle on item \"{}\": {}",
|
||||||
item::getName, e::getMessage);
|
item::getName, e::getMessage);
|
||||||
@@ -110,7 +124,6 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
|
|
||||||
//Create a map of the bitstreams in the displayBundle. This is used to
|
//Create a map of the bitstreams in the displayBundle. This is used to
|
||||||
//check if the bundle being cited is already in the display bundle.
|
//check if the bundle being cited is already in the display bundle.
|
||||||
Map<String, Bitstream> displayMap = new HashMap<>();
|
|
||||||
for (Bitstream bs : dBundle.getBitstreams()) {
|
for (Bitstream bs : dBundle.getBitstreams()) {
|
||||||
displayMap.put(bs.getName(), bs);
|
displayMap.put(bs.getName(), bs);
|
||||||
}
|
}
|
||||||
@@ -128,6 +141,8 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
pBundle = bundleService.create(Curator.curationContext(), item, CitationPage.PRESERVATION_BUNDLE_NAME);
|
pBundle = bundleService.create(Curator.curationContext(), item, CitationPage.PRESERVATION_BUNDLE_NAME);
|
||||||
|
// don't inherit now otherwise they will be copied over the moved bitstreams
|
||||||
|
resourcePolicyService.removeAllPolicies(Curator.curationContext(), pBundle);
|
||||||
} catch (AuthorizeException e) {
|
} catch (AuthorizeException e) {
|
||||||
log.error("User not authroized to create bundle on item \""
|
log.error("User not authroized to create bundle on item \""
|
||||||
+ item.getName() + "\": " + e.getMessage());
|
+ item.getName() + "\": " + e.getMessage());
|
||||||
@@ -160,7 +175,10 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
citationDocument.makeCitedDocument(Curator.curationContext(), bitstream).getLeft());
|
citationDocument.makeCitedDocument(Curator.curationContext(), bitstream).getLeft());
|
||||||
//Add the cited document to the approiate bundle
|
//Add the cited document to the approiate bundle
|
||||||
this.addCitedPageToItem(citedInputStream, bundle, pBundle,
|
this.addCitedPageToItem(citedInputStream, bundle, pBundle,
|
||||||
dBundle, displayMap, item, bitstream);
|
dBundle, item, bitstream);
|
||||||
|
// now set the policies of the preservation and display bundle
|
||||||
|
clonePolicies(Curator.curationContext(), original, pBundle);
|
||||||
|
clonePolicies(Curator.curationContext(), original, dBundle);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//Could be many things, but nothing that should be
|
//Could be many things, but nothing that should be
|
||||||
//expected.
|
//expected.
|
||||||
@@ -203,8 +221,6 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
* @param pBundle The preservation bundle. The original document should be
|
* @param pBundle The preservation bundle. The original document should be
|
||||||
* put in here if it is not already.
|
* put in here if it is not already.
|
||||||
* @param dBundle The display bundle. The cited document gets put in here.
|
* @param dBundle The display bundle. The cited document gets put in here.
|
||||||
* @param displayMap The map of bitstream names to bitstreams in the display
|
|
||||||
* bundle.
|
|
||||||
* @param item The item containing the bundles being used.
|
* @param item The item containing the bundles being used.
|
||||||
* @param bitstream The original source bitstream.
|
* @param bitstream The original source bitstream.
|
||||||
* @throws SQLException if database error
|
* @throws SQLException if database error
|
||||||
@@ -212,7 +228,7 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
* @throws IOException if IO error
|
* @throws IOException if IO error
|
||||||
*/
|
*/
|
||||||
protected void addCitedPageToItem(InputStream citedDoc, Bundle bundle, Bundle pBundle,
|
protected void addCitedPageToItem(InputStream citedDoc, Bundle bundle, Bundle pBundle,
|
||||||
Bundle dBundle, Map<String,Bitstream> displayMap, Item item,
|
Bundle dBundle, Item item,
|
||||||
Bitstream bitstream) throws SQLException, AuthorizeException, IOException {
|
Bitstream bitstream) throws SQLException, AuthorizeException, IOException {
|
||||||
//If we are modifying a file that is not in the
|
//If we are modifying a file that is not in the
|
||||||
//preservation bundle then we have to move it there.
|
//preservation bundle then we have to move it there.
|
||||||
@@ -240,7 +256,8 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
citedBitstream.setName(context, bitstream.getName());
|
citedBitstream.setName(context, bitstream.getName());
|
||||||
bitstreamService.setFormat(context, citedBitstream, bitstream.getFormat(Curator.curationContext()));
|
bitstreamService.setFormat(context, citedBitstream, bitstream.getFormat(Curator.curationContext()));
|
||||||
citedBitstream.setDescription(context, bitstream.getDescription());
|
citedBitstream.setDescription(context, bitstream.getDescription());
|
||||||
|
displayMap.put(bitstream.getName(), citedBitstream);
|
||||||
|
clonePolicies(context, bitstream, citedBitstream);
|
||||||
this.resBuilder.append(" Added ")
|
this.resBuilder.append(" Added ")
|
||||||
.append(citedBitstream.getName())
|
.append(citedBitstream.getName())
|
||||||
.append(" to the ")
|
.append(" to the ")
|
||||||
@@ -252,4 +269,16 @@ public class CitationPage extends AbstractCurationTask {
|
|||||||
itemService.update(context, item);
|
itemService.update(context, item);
|
||||||
this.status = Curator.CURATE_SUCCESS;
|
this.status = Curator.CURATE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clonePolicies(Context context, DSpaceObject source,DSpaceObject target)
|
||||||
|
throws SQLException, AuthorizeException {
|
||||||
|
resourcePolicyService.removeAllPolicies(context, target);
|
||||||
|
for (ResourcePolicy rp: source.getResourcePolicies()) {
|
||||||
|
ResourcePolicy newPolicy = resourcePolicyService.clone(context, rp);
|
||||||
|
newPolicy.setdSpaceObject(target);
|
||||||
|
newPolicy.setAction(rp.getAction());
|
||||||
|
resourcePolicyService.update(context, newPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@@ -15,6 +15,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -33,6 +34,7 @@ import org.dspace.content.dto.MetadataValueDTO;
|
|||||||
import org.dspace.external.OpenAIRERestConnector;
|
import org.dspace.external.OpenAIRERestConnector;
|
||||||
import org.dspace.external.model.ExternalDataObject;
|
import org.dspace.external.model.ExternalDataObject;
|
||||||
import org.dspace.external.provider.AbstractExternalDataProvider;
|
import org.dspace.external.provider.AbstractExternalDataProvider;
|
||||||
|
import org.dspace.importer.external.metadatamapping.MetadataFieldConfig;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,13 +42,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
* will deal with the OpenAIRE External Data lookup
|
* will deal with the OpenAIRE External Data lookup
|
||||||
*
|
*
|
||||||
* @author paulo-graca
|
* @author paulo-graca
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
||||||
|
|
||||||
/**
|
|
||||||
* log4j logger
|
|
||||||
*/
|
|
||||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(OpenAIREFundingDataProvider.class);
|
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(OpenAIREFundingDataProvider.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,6 +52,16 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
*/
|
*/
|
||||||
protected static final String PREFIX = "info:eu-repo/grantAgreement";
|
protected static final String PREFIX = "info:eu-repo/grantAgreement";
|
||||||
|
|
||||||
|
private static final String TITLE = "dcTitle";
|
||||||
|
private static final String SUBJECT = "dcSubject";
|
||||||
|
private static final String AWARD_URI = "awardURI";
|
||||||
|
private static final String FUNDER_NAME = "funderName";
|
||||||
|
private static final String SPATIAL = "coverageSpatial";
|
||||||
|
private static final String AWARD_NUMBER = "awardNumber";
|
||||||
|
private static final String FUNDER_ID = "funderIdentifier";
|
||||||
|
private static final String FUNDING_STREAM = "fundingStream";
|
||||||
|
private static final String TITLE_ALTERNATIVE = "titleAlternative";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rows default limit
|
* rows default limit
|
||||||
*/
|
*/
|
||||||
@@ -69,11 +77,9 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
*/
|
*/
|
||||||
protected OpenAIRERestConnector connector;
|
protected OpenAIRERestConnector connector;
|
||||||
|
|
||||||
/**
|
protected Map<String, MetadataFieldConfig> metadataFields;
|
||||||
* required method
|
|
||||||
*/
|
public void init() throws IOException {}
|
||||||
public void init() throws IOException {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSourceIdentifier() {
|
public String getSourceIdentifier() {
|
||||||
@@ -266,14 +272,22 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, MetadataFieldConfig> getMetadataFields() {
|
||||||
|
return metadataFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetadataFields(Map<String, MetadataFieldConfig> metadataFields) {
|
||||||
|
this.metadataFields = metadataFields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenAIRE Funding External Data Builder Class
|
* OpenAIRE Funding External Data Builder Class
|
||||||
*
|
*
|
||||||
* @author pgraca
|
* @author pgraca
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static class ExternalDataObjectBuilder {
|
public class ExternalDataObjectBuilder {
|
||||||
ExternalDataObject externalDataObject;
|
|
||||||
|
private ExternalDataObject externalDataObject;
|
||||||
|
|
||||||
public ExternalDataObjectBuilder(Project project) {
|
public ExternalDataObjectBuilder(Project project) {
|
||||||
String funderIdPrefix = "urn:openaire:";
|
String funderIdPrefix = "urn:openaire:";
|
||||||
@@ -283,46 +297,42 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
for (FundingTreeType fundingTree : projectHelper.getFundingTreeTypes()) {
|
for (FundingTreeType fundingTree : projectHelper.getFundingTreeTypes()) {
|
||||||
FunderType funder = fundingTree.getFunder();
|
FunderType funder = fundingTree.getFunder();
|
||||||
// Funder name
|
// Funder name
|
||||||
this.addFunderName(funder.getName());
|
this.addMetadata(metadataFields.get(FUNDER_NAME), funder.getName());
|
||||||
// Funder Id - convert it to an urn
|
// Funder Id - convert it to an urn
|
||||||
this.addFunderID(funderIdPrefix + funder.getId());
|
this.addMetadata(metadataFields.get(FUNDER_ID), funderIdPrefix + funder.getId());
|
||||||
// Jurisdiction
|
// Jurisdiction
|
||||||
this.addFunderJuristiction(funder.getJurisdiction());
|
this.addMetadata(metadataFields.get(SPATIAL), funder.getJurisdiction());
|
||||||
|
|
||||||
FundingHelper fundingHelper = new FundingHelper(
|
FundingHelper fundingHelper = new FundingHelper(
|
||||||
fundingTree.getFundingLevel2OrFundingLevel1OrFundingLevel0());
|
fundingTree.getFundingLevel2OrFundingLevel1OrFundingLevel0());
|
||||||
|
|
||||||
// Funding description
|
// Funding description
|
||||||
for (FundingType funding : fundingHelper.getFirstAvailableFunding()) {
|
for (FundingType funding : fundingHelper.getFirstAvailableFunding()) {
|
||||||
this.addFundingStream(funding.getDescription());
|
this.addMetadata(metadataFields.get(FUNDING_STREAM), funding.getDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
for (String title : projectHelper.getTitles()) {
|
for (String title : projectHelper.getTitles()) {
|
||||||
this.addAwardTitle(title);
|
this.addMetadata(metadataFields.get(TITLE), title);
|
||||||
this.setDisplayValue(title);
|
this.setDisplayValue(title);
|
||||||
this.setValue(title);
|
this.setValue(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code
|
// Code
|
||||||
for (String code : projectHelper.getCodes()) {
|
for (String code : projectHelper.getCodes()) {
|
||||||
this.addAwardNumber(code);
|
this.addMetadata(metadataFields.get(AWARD_NUMBER), code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Website url
|
// Website url
|
||||||
for (String url : projectHelper.getWebsiteUrls()) {
|
for (String url : projectHelper.getWebsiteUrls()) {
|
||||||
this.addAwardURI(url);
|
this.addMetadata(metadataFields.get(AWARD_URI), url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acronyms
|
// Acronyms
|
||||||
for (String acronym : projectHelper.getAcronyms()) {
|
for (String acronym : projectHelper.getAcronyms()) {
|
||||||
this.addFundingItemAcronym(acronym);
|
this.addMetadata(metadataFields.get(TITLE_ALTERNATIVE), acronym);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
for (String keyword : projectHelper.getKeywords()) {
|
for (String keyword : projectHelper.getKeywords()) {
|
||||||
this.addSubject(keyword);
|
this.addMetadata(metadataFields.get(SUBJECT), keyword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,7 +376,6 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
* @return ExternalDataObjectBuilder
|
* @return ExternalDataObjectBuilder
|
||||||
*/
|
*/
|
||||||
public ExternalDataObjectBuilder setId(String id) {
|
public ExternalDataObjectBuilder setId(String id) {
|
||||||
|
|
||||||
// we use base64 encoding in order to use slashes / and other
|
// we use base64 encoding in order to use slashes / and other
|
||||||
// characters that must be escaped for the <:entry-id>
|
// characters that must be escaped for the <:entry-id>
|
||||||
String base64Id = Base64.getEncoder().encodeToString(id.getBytes());
|
String base64Id = Base64.getEncoder().encodeToString(id.getBytes());
|
||||||
@@ -374,128 +383,10 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public ExternalDataObjectBuilder addMetadata(MetadataFieldConfig metadataField, String value) {
|
||||||
* Add metadata dc.identifier
|
this.externalDataObject.addMetadata(new MetadataValueDTO(metadataField.getSchema(),
|
||||||
*
|
metadataField.getElement(),
|
||||||
* @param metadata identifier
|
metadataField.getQualifier(), null, value));
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addIdentifier(String identifier) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "identifier", null, null, identifier));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata project.funder.name
|
|
||||||
*
|
|
||||||
* @param metadata funderName
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addFunderName(String funderName) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("project", "funder", "name", null, funderName));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata project.funder.identifier
|
|
||||||
*
|
|
||||||
* @param metadata funderId
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addFunderID(String funderID) {
|
|
||||||
this.externalDataObject
|
|
||||||
.addMetadata(new MetadataValueDTO("project", "funder", "identifier", null, funderID));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata dc.title
|
|
||||||
*
|
|
||||||
* @param metadata awardTitle
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addAwardTitle(String awardTitle) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "title", null, null, awardTitle));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata oaire.fundingStream
|
|
||||||
*
|
|
||||||
* @param metadata fundingStream
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addFundingStream(String fundingStream) {
|
|
||||||
this.externalDataObject
|
|
||||||
.addMetadata(new MetadataValueDTO("oaire", "fundingStream", null, null, fundingStream));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata oaire.awardNumber
|
|
||||||
*
|
|
||||||
* @param metadata awardNumber
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addAwardNumber(String awardNumber) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("oaire", "awardNumber", null, null, awardNumber));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata oaire.awardURI
|
|
||||||
*
|
|
||||||
* @param metadata websiteUrl
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addAwardURI(String websiteUrl) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("oaire", "awardURI", null, null, websiteUrl));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata dc.title.alternative
|
|
||||||
*
|
|
||||||
* @param metadata fundingItemAcronym
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addFundingItemAcronym(String fundingItemAcronym) {
|
|
||||||
this.externalDataObject
|
|
||||||
.addMetadata(new MetadataValueDTO("dc", "title", "alternative", null, fundingItemAcronym));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata dc.coverage.spatial
|
|
||||||
*
|
|
||||||
* @param metadata funderJuristiction
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addFunderJuristiction(String funderJuristiction) {
|
|
||||||
this.externalDataObject
|
|
||||||
.addMetadata(new MetadataValueDTO("dc", "coverage", "spatial", null, funderJuristiction));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata dc.description
|
|
||||||
*
|
|
||||||
* @param metadata description
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addDescription(String description) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "description", null, null, description));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata dc.subject
|
|
||||||
*
|
|
||||||
* @param metadata subject
|
|
||||||
* @return ExternalDataObjectBuilder
|
|
||||||
*/
|
|
||||||
public ExternalDataObjectBuilder addSubject(String subject) {
|
|
||||||
this.externalDataObject.addMetadata(new MetadataValueDTO("dc", "subject", null, null, subject));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,4 +399,5 @@ public class OpenAIREFundingDataProvider extends AbstractExternalDataProvider {
|
|||||||
return this.externalDataObject;
|
return this.externalDataObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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.importer.external.metadatamapping.contributor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.dspace.importer.external.metadatamapping.MetadataFieldMapping;
|
||||||
|
import org.dspace.importer.external.metadatamapping.MetadatumDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class used to split another MetadataContributor's output into distinct values.
|
||||||
|
* The split is performed by matching a regular expression against the wrapped MetadataContributor's output.
|
||||||
|
*
|
||||||
|
* @author Philipp Rumpf (philipp.rumpf@uni-bamberg.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SplitMetadataContributor<T> implements MetadataContributor<T> {
|
||||||
|
private final MetadataContributor<T> innerContributor;
|
||||||
|
private final String regex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param innerContributor The MetadataContributor whose output is split
|
||||||
|
* @param regex A regular expression matching the separator between different values
|
||||||
|
*/
|
||||||
|
public SplitMetadataContributor(MetadataContributor<T> innerContributor, String regex) {
|
||||||
|
this.innerContributor = innerContributor;
|
||||||
|
this.regex = regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMetadataFieldMapping(MetadataFieldMapping<T, MetadataContributor<T>> rt) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each metadatum returned by the wrapped MetadataContributor is split into one or more metadata values
|
||||||
|
* based on the provided regular expression.
|
||||||
|
*
|
||||||
|
* @param t The recordType object to retrieve metadata from
|
||||||
|
* @return The collection of processed metadata values
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<MetadatumDTO> contributeMetadata(T t) {
|
||||||
|
Collection<MetadatumDTO> metadata = innerContributor.contributeMetadata(t);
|
||||||
|
ArrayList<MetadatumDTO> splitMetadata = new ArrayList<>();
|
||||||
|
for (MetadatumDTO metadatumDTO : metadata) {
|
||||||
|
String[] split = metadatumDTO.getValue().split(regex);
|
||||||
|
for (String splitItem : split) {
|
||||||
|
MetadatumDTO splitMetadatumDTO = new MetadatumDTO();
|
||||||
|
splitMetadatumDTO.setSchema(metadatumDTO.getSchema());
|
||||||
|
splitMetadatumDTO.setElement(metadatumDTO.getElement());
|
||||||
|
splitMetadatumDTO.setQualifier(metadatumDTO.getQualifier());
|
||||||
|
splitMetadatumDTO.setValue(splitItem);
|
||||||
|
splitMetadata.add(splitMetadatumDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return splitMetadata;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.passwordvalidation.factory;
|
||||||
|
|
||||||
|
import org.dspace.authorize.service.PasswordValidatorService;
|
||||||
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract factory to get services for the passwordvalidation package,
|
||||||
|
* use PasswordValidationFactory.getInstance() to retrieve an implementation.
|
||||||
|
*
|
||||||
|
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||||
|
*/
|
||||||
|
public abstract class PasswordValidationFactory {
|
||||||
|
|
||||||
|
public abstract PasswordValidatorService getPasswordValidationService();
|
||||||
|
|
||||||
|
public static PasswordValidationFactory getInstance() {
|
||||||
|
return DSpaceServicesFactory.getInstance()
|
||||||
|
.getServiceManager()
|
||||||
|
.getServiceByName("validationPasswordFactory", PasswordValidationFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.passwordvalidation.factory;
|
||||||
|
|
||||||
|
import org.dspace.authorize.service.PasswordValidatorService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory implementation to get services for the PasswordValidation package,
|
||||||
|
* use PasswordValidationFactory.getInstance() to retrieve an implementation.
|
||||||
|
*
|
||||||
|
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||||
|
*/
|
||||||
|
public class PasswordValidationFactoryImpl extends PasswordValidationFactory {
|
||||||
|
|
||||||
|
@Autowired(required = true)
|
||||||
|
private PasswordValidatorService PasswordValidatorService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PasswordValidatorService getPasswordValidationService() {
|
||||||
|
return PasswordValidatorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -305,6 +305,12 @@ public class ProcessServiceImpl implements ProcessService {
|
|||||||
tempFile.delete();
|
tempFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Process> findByStatusAndCreationTimeOlderThan(Context context, List<ProcessStatus> statuses,
|
||||||
|
Date date) throws SQLException {
|
||||||
|
return this.processDAO.findByStatusAndCreationTimeOlderThan(context, statuses, date);
|
||||||
|
}
|
||||||
|
|
||||||
private String formatLogLine(int processId, String scriptName, String output, ProcessLogLevel processLogLevel) {
|
private String formatLogLine(int processId, String scriptName, String output, ProcessLogLevel processLogLevel) {
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@@ -10,11 +10,13 @@ package org.dspace.scripts.service;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.Bitstream;
|
import org.dspace.content.Bitstream;
|
||||||
|
import org.dspace.content.ProcessStatus;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
@@ -240,4 +242,17 @@ public interface ProcessService {
|
|||||||
*/
|
*/
|
||||||
void createLogBitstream(Context context, Process process)
|
void createLogBitstream(Context context, Process process)
|
||||||
throws IOException, SQLException, AuthorizeException;
|
throws IOException, SQLException, AuthorizeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all the processes with one of the given status and with a creation time
|
||||||
|
* older than the specified date.
|
||||||
|
*
|
||||||
|
* @param context The relevant DSpace context
|
||||||
|
* @param statuses the statuses of the processes to search for
|
||||||
|
* @param date the creation date to search for
|
||||||
|
* @return The list of all Processes which match requirements
|
||||||
|
* @throws AuthorizeException If something goes wrong
|
||||||
|
*/
|
||||||
|
List<Process> findByStatusAndCreationTimeOlderThan(Context context, List<ProcessStatus> statuses, Date date)
|
||||||
|
throws SQLException;
|
||||||
}
|
}
|
||||||
|
@@ -120,3 +120,4 @@ org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException.message = Refused
|
|||||||
org.dspace.app.rest.exception.EPersonNameNotProvidedException.message = The eperson.firstname and eperson.lastname values need to be filled in
|
org.dspace.app.rest.exception.EPersonNameNotProvidedException.message = The eperson.firstname and eperson.lastname values need to be filled in
|
||||||
org.dspace.app.rest.exception.GroupNameNotProvidedException.message = Cannot create group, no group name is provided
|
org.dspace.app.rest.exception.GroupNameNotProvidedException.message = Cannot create group, no group name is provided
|
||||||
org.dspace.app.rest.exception.GroupHasPendingWorkflowTasksException.message = Cannot delete group, the associated workflow role still has pending tasks
|
org.dspace.app.rest.exception.GroupHasPendingWorkflowTasksException.message = Cannot delete group, the associated workflow role still has pending tasks
|
||||||
|
org.dspace.app.rest.exception.PasswordNotValidException.message = New password is invalid. Valid passwords must be at least 8 characters long!
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://www.springframework.org/schema/util
|
||||||
|
http://www.springframework.org/schema/util/spring-util.xsd"
|
||||||
default-lazy-init="true">
|
default-lazy-init="true">
|
||||||
|
|
||||||
<bean id="mockOpenAIRERestConnector" class="org.dspace.external.MockOpenAIRERestConnector">
|
<bean id="mockOpenAIRERestConnector" class="org.dspace.external.MockOpenAIRERestConnector">
|
||||||
@@ -15,11 +19,71 @@
|
|||||||
init-method="init">
|
init-method="init">
|
||||||
<property name="sourceIdentifier" value="openAIREFunding" />
|
<property name="sourceIdentifier" value="openAIREFunding" />
|
||||||
<property name="connector" ref="mockOpenAIRERestConnector" />
|
<property name="connector" ref="mockOpenAIRERestConnector" />
|
||||||
|
<property name="metadataFields" ref="mapOfmetadata"/>
|
||||||
<property name="supportedEntityTypes">
|
<property name="supportedEntityTypes">
|
||||||
<list>
|
<list>
|
||||||
<value>Project</value>
|
<value>Project</value>
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<util:map id="mapOfmetadata"
|
||||||
|
map-class="java.util.HashMap" key-type="java.lang.String" value-type="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<entry key="awardNumber" value-ref="openaireAwardNumber" />
|
||||||
|
<entry key="fundingStream" value-ref="openaireFundingStream" />
|
||||||
|
<entry key="awardURI" value-ref="openaireAwardURI" />
|
||||||
|
<entry key="funderName" value-ref="openaireFunderName" />
|
||||||
|
<entry key="funderIdentifier" value-ref="openaireFunderIdentifier" />
|
||||||
|
<entry key="dcTitle" value-ref="openaireTitle" />
|
||||||
|
<entry key="titleAlternative" value-ref="openaireTitleAlternative" />
|
||||||
|
<entry key="dcIdentifier" value-ref="openaireIdentifier" />
|
||||||
|
<entry key="coverageSpatial" value-ref="openaireSpatial" />
|
||||||
|
<entry key="dcDescription" value-ref="openaireDescription" />
|
||||||
|
<entry key="dcSubject" value-ref="openaireSubject" />
|
||||||
|
</util:map>
|
||||||
|
|
||||||
|
<bean id="openaireAwardNumber" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="oaire.awardNumber"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireFundingStream" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="oaire.fundingStream"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireAwardURI" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="oaire.awardURI"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireFunderName" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="project.funder.name"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireFunderIdentifier" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="project.funder.identifier"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireTitle" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.title"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireTitleAlternative" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.title.alternative"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireIdentifier" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.identifier"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireSpatial" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.coverage.spatial"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireDescription" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.description"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireSubject" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.subject"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
@@ -64,7 +64,12 @@
|
|||||||
<property name="description" value="Perform the bulk synchronization of all the BATCH configured ORCID entities placed in the ORCID queue"/>
|
<property name="description" value="Perform the bulk synchronization of all the BATCH configured ORCID entities placed in the ORCID queue"/>
|
||||||
<property name="dspaceRunnableClass" value="org.dspace.orcid.script.OrcidBulkPush"/>
|
<property name="dspaceRunnableClass" value="org.dspace.orcid.script.OrcidBulkPush"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="process-cleaner" class="org.dspace.administer.ProcessCleanerCliConfiguration">
|
||||||
|
<property name="description" value="Cleanup all the old processes in the specified state"/>
|
||||||
|
<property name="dspaceRunnableClass" value="org.dspace.administer.ProcessCleanerCli"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!-- Keep as last script; for test ScriptRestRepository#findOneScriptByNameTest -->
|
<!-- Keep as last script; for test ScriptRestRepository#findOneScriptByNameTest -->
|
||||||
<bean id="mock-script" class="org.dspace.scripts.MockDSpaceRunnableScriptConfiguration" scope="prototype">
|
<bean id="mock-script" class="org.dspace.scripts.MockDSpaceRunnableScriptConfiguration" scope="prototype">
|
||||||
<property name="description" value="Mocking a script for testing purposes" />
|
<property name="description" value="Mocking a script for testing purposes" />
|
||||||
|
@@ -0,0 +1,380 @@
|
|||||||
|
/**
|
||||||
|
* 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.administer;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang.time.DateUtils.addDays;
|
||||||
|
import static org.dspace.content.ProcessStatus.COMPLETED;
|
||||||
|
import static org.dspace.content.ProcessStatus.FAILED;
|
||||||
|
import static org.dspace.content.ProcessStatus.RUNNING;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||||
|
import org.dspace.app.launcher.ScriptLauncher;
|
||||||
|
import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
|
||||||
|
import org.dspace.builder.ProcessBuilder;
|
||||||
|
import org.dspace.content.ProcessStatus;
|
||||||
|
import org.dspace.scripts.Process;
|
||||||
|
import org.dspace.scripts.factory.ScriptServiceFactory;
|
||||||
|
import org.dspace.scripts.service.ProcessService;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link ProcessCleaner}.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProcessCleanerIT extends AbstractIntegrationTestWithDatabase {
|
||||||
|
|
||||||
|
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||||
|
|
||||||
|
private ProcessService processService = ScriptServiceFactory.getInstance().getProcessService();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithoutProcessToDelete() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
|
||||||
|
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [COMPLETED]"));
|
||||||
|
assertThat(messages, hasItem("Found 0 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithoutSpecifiedStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
|
||||||
|
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [COMPLETED]"));
|
||||||
|
assertThat(messages, hasItem("Found 2 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), notNullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithCompletedStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-c" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
|
||||||
|
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [COMPLETED]"));
|
||||||
|
assertThat(messages, hasItem("Found 2 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), notNullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithRunningStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
Process process_8 = buildProcess(RUNNING, addDays(new Date(), -9));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-r" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
|
||||||
|
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [RUNNING]"));
|
||||||
|
assertThat(messages, hasItem("Found 2 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_8.getID()), nullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithFailedStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
Process process_8 = buildProcess(FAILED, addDays(new Date(), -9));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-f" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
|
||||||
|
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [FAILED]"));
|
||||||
|
assertThat(messages, hasItem("Found 2 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_8.getID()), nullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithCompletedAndFailedStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
Process process_8 = buildProcess(FAILED, addDays(new Date(), -9));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-c", "-f" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [COMPLETED, FAILED]"));
|
||||||
|
assertThat(messages, hasItem("Found 4 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_8.getID()), nullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithCompletedAndRunningStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
Process process_8 = buildProcess(RUNNING, addDays(new Date(), -9));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-c", "-r" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [COMPLETED, RUNNING]"));
|
||||||
|
assertThat(messages, hasItem("Found 4 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_8.getID()), nullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithFailedAndRunningStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
Process process_8 = buildProcess(RUNNING, addDays(new Date(), -9));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-f", "-r" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [FAILED, RUNNING]"));
|
||||||
|
assertThat(messages, hasItem("Found 3 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_8.getID()), nullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithCompletedFailedAndRunningStatus() throws Exception {
|
||||||
|
|
||||||
|
Process process_1 = buildProcess(COMPLETED, addDays(new Date(), -2));
|
||||||
|
Process process_2 = buildProcess(RUNNING, addDays(new Date(), -1));
|
||||||
|
Process process_3 = buildProcess(FAILED, addDays(new Date(), -3));
|
||||||
|
Process process_4 = buildProcess(COMPLETED, addDays(new Date(), -6));
|
||||||
|
Process process_5 = buildProcess(COMPLETED, addDays(new Date(), -8));
|
||||||
|
Process process_6 = buildProcess(RUNNING, addDays(new Date(), -7));
|
||||||
|
Process process_7 = buildProcess(FAILED, addDays(new Date(), -8));
|
||||||
|
Process process_8 = buildProcess(RUNNING, addDays(new Date(), -9));
|
||||||
|
|
||||||
|
configurationService.setProperty("process-cleaner.days", 5);
|
||||||
|
|
||||||
|
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||||
|
|
||||||
|
String[] args = new String[] { "process-cleaner", "-f", "-r", "-c" };
|
||||||
|
ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
|
||||||
|
|
||||||
|
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
|
||||||
|
assertThat(messages, hasSize(3));
|
||||||
|
assertThat(messages, hasItem("Searching for processes with status: [COMPLETED, FAILED, RUNNING]"));
|
||||||
|
assertThat(messages, hasItem("Found 5 processes to be deleted"));
|
||||||
|
assertThat(messages, hasItem("Process cleanup completed"));
|
||||||
|
|
||||||
|
assertThat(processService.find(context, process_1.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_2.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_3.getID()), notNullValue());
|
||||||
|
assertThat(processService.find(context, process_4.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_5.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_6.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_7.getID()), nullValue());
|
||||||
|
assertThat(processService.find(context, process_8.getID()), nullValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Process buildProcess(ProcessStatus processStatus, Date creationTime) throws SQLException {
|
||||||
|
return ProcessBuilder.createProcess(context, admin, "test", List.of())
|
||||||
|
.withProcessStatus(processStatus)
|
||||||
|
.withCreationTime(creationTime)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.content.Collection;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Mark H. Wood <mwood@iupui.edu>
|
||||||
|
*/
|
||||||
|
public class CollectionAdministratorsRequestItemStrategyTest {
|
||||||
|
private static final String NAME = "John Q. Public";
|
||||||
|
private static final String EMAIL = "jqpublic@example.com";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of getRequestItemAuthor method, of class CollectionAdministratorsRequestItemStrategy.
|
||||||
|
* @throws java.lang.Exception passed through.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetRequestItemAuthor()
|
||||||
|
throws Exception {
|
||||||
|
System.out.println("getRequestItemAuthor");
|
||||||
|
|
||||||
|
Context context = Mockito.mock(Context.class);
|
||||||
|
|
||||||
|
EPerson eperson1 = Mockito.mock(EPerson.class);
|
||||||
|
Mockito.when(eperson1.getEmail()).thenReturn(EMAIL);
|
||||||
|
Mockito.when(eperson1.getFullName()).thenReturn(NAME);
|
||||||
|
|
||||||
|
Group group1 = Mockito.mock(Group.class);
|
||||||
|
Mockito.when(group1.getMembers()).thenReturn(List.of(eperson1));
|
||||||
|
|
||||||
|
Collection collection1 = Mockito.mock(Collection.class);
|
||||||
|
Mockito.when(collection1.getAdministrators()).thenReturn(group1);
|
||||||
|
|
||||||
|
Item item = Mockito.mock(Item.class);
|
||||||
|
Mockito.when(item.getOwningCollection()).thenReturn(collection1);
|
||||||
|
Mockito.when(item.getSubmitter()).thenReturn(eperson1);
|
||||||
|
|
||||||
|
CollectionAdministratorsRequestItemStrategy instance = new CollectionAdministratorsRequestItemStrategy();
|
||||||
|
List<RequestItemAuthor> result = instance.getRequestItemAuthor(context,
|
||||||
|
item);
|
||||||
|
assertEquals("Should be one author", 1, result.size());
|
||||||
|
assertEquals("Name should match " + NAME, NAME, result.get(0).getFullName());
|
||||||
|
assertEquals("Email should match " + EMAIL, EMAIL, result.get(0).getEmail());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.requestitem;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Mark H. Wood <mwood@iupui.edu>
|
||||||
|
*/
|
||||||
|
public class CombiningRequestItemStrategyTest {
|
||||||
|
/**
|
||||||
|
* Test of getRequestItemAuthor method, of class CombiningRequestItemStrategy.
|
||||||
|
* @throws java.lang.Exception passed through.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetRequestItemAuthor()
|
||||||
|
throws Exception {
|
||||||
|
System.out.println("getRequestItemAuthor");
|
||||||
|
Context context = null;
|
||||||
|
|
||||||
|
Item item = Mockito.mock(Item.class);
|
||||||
|
RequestItemAuthor author1 = new RequestItemAuthor("Pat Paulsen", "ppaulsen@example.com");
|
||||||
|
RequestItemAuthor author2 = new RequestItemAuthor("Alfred E. Neuman", "aeneuman@example.com");
|
||||||
|
RequestItemAuthor author3 = new RequestItemAuthor("Alias Undercover", "aundercover@example.com");
|
||||||
|
|
||||||
|
RequestItemAuthorExtractor strategy1 = Mockito.mock(RequestItemHelpdeskStrategy.class);
|
||||||
|
Mockito.when(strategy1.getRequestItemAuthor(context, item)).thenReturn(List.of(author1));
|
||||||
|
|
||||||
|
RequestItemAuthorExtractor strategy2 = Mockito.mock(RequestItemMetadataStrategy.class);
|
||||||
|
Mockito.when(strategy2.getRequestItemAuthor(context, item)).thenReturn(List.of(author2, author3));
|
||||||
|
|
||||||
|
List<RequestItemAuthorExtractor> strategies = List.of(strategy1, strategy2);
|
||||||
|
|
||||||
|
CombiningRequestItemStrategy instance = new CombiningRequestItemStrategy(strategies);
|
||||||
|
List<RequestItemAuthor> result = instance.getRequestItemAuthor(context,
|
||||||
|
item);
|
||||||
|
assertThat(result, containsInAnyOrder(author1, author2, author3));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* 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.authorize;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import org.dspace.AbstractIntegrationTest;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link RegexPasswordValidator}.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class RegexPasswordValidatorTest extends AbstractIntegrationTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private RegexPasswordValidator regexPasswordValidator;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
when(configurationService.getProperty("authentication-password.regex-validation.pattern"))
|
||||||
|
.thenReturn("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^\\da-zA-Z]).{8,15}$");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidPassword() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TestPassword01!"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidPasswordForMissingSpecialCharacter() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TestPassword01"), is(false));
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TestPassword01?"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidPasswordForMissingNumber() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TestPassword!"), is(false));
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TestPassword1!"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidPasswordForMissingUppercaseCharacter() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("testpassword01!"), is(false));
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("testPassword01!"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidPasswordForMissingLowercaseCharacter() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TESTPASSWORD01!"), is(false));
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("TESTPASSWORd01!"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidPasswordForTooShortValue() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("Test01!"), is(false));
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("Test012!"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidPasswordForTooLongValue() {
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("ThisIsAVeryLongPassword01!"), is(false));
|
||||||
|
assertThat(regexPasswordValidator.isPasswordValid("IsAPassword012!"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -11,6 +11,7 @@ import java.io.IOException;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -60,6 +61,11 @@ public class ProcessBuilder extends AbstractBuilder<Process, ProcessService> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProcessBuilder withCreationTime(Date creationTime) {
|
||||||
|
process.setCreationTime(creationTime);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ProcessBuilder withStartAndEndTime(String startTime, String endTime) throws ParseException {
|
public ProcessBuilder withStartAndEndTime(String startTime, String endTime) throws ParseException {
|
||||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
|
||||||
process.setStartTime(simpleDateFormat.parse(startTime));
|
process.setStartTime(simpleDateFormat.parse(startTime));
|
||||||
|
@@ -163,6 +163,7 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
|||||||
EPersonNameNotProvidedException.class,
|
EPersonNameNotProvidedException.class,
|
||||||
GroupNameNotProvidedException.class,
|
GroupNameNotProvidedException.class,
|
||||||
GroupHasPendingWorkflowTasksException.class,
|
GroupHasPendingWorkflowTasksException.class,
|
||||||
|
PasswordNotValidException.class,
|
||||||
})
|
})
|
||||||
protected void handleCustomUnprocessableEntityException(HttpServletRequest request, HttpServletResponse response,
|
protected void handleCustomUnprocessableEntityException(HttpServletRequest request, HttpServletResponse response,
|
||||||
TranslatableException ex) throws IOException {
|
TranslatableException ex) throws IOException {
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.exception;
|
||||||
|
|
||||||
|
import org.dspace.core.I18nUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides an exception to be used when trying to create an EPerson
|
||||||
|
* with password that not match regular expression configured in this
|
||||||
|
* variable "authentication-password.regex-validation.pattern" in dspace.cfg or during the patch of password.
|
||||||
|
*
|
||||||
|
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||||
|
*/
|
||||||
|
public class PasswordNotValidException extends UnprocessableEntityException implements TranslatableException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4294543847989250566L;
|
||||||
|
|
||||||
|
public static final String MESSAGE_KEY = "org.dspace.app.rest.exception.PasswordNotValidException.message";
|
||||||
|
|
||||||
|
public PasswordNotValidException() {
|
||||||
|
super(I18nUtil.getMessage(MESSAGE_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PasswordNotValidException(Throwable cause) {
|
||||||
|
super(I18nUtil.getMessage(MESSAGE_KEY), cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageKey() {
|
||||||
|
return MESSAGE_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -21,9 +21,9 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.dspace.app.rest.DiscoverableEndpointsService;
|
import org.dspace.app.rest.DiscoverableEndpointsService;
|
||||||
import org.dspace.app.rest.Parameter;
|
import org.dspace.app.rest.Parameter;
|
||||||
import org.dspace.app.rest.SearchRestMethod;
|
import org.dspace.app.rest.SearchRestMethod;
|
||||||
import org.dspace.app.rest.authorization.AuthorizationFeatureService;
|
|
||||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||||
import org.dspace.app.rest.exception.EPersonNameNotProvidedException;
|
import org.dspace.app.rest.exception.EPersonNameNotProvidedException;
|
||||||
|
import org.dspace.app.rest.exception.PasswordNotValidException;
|
||||||
import org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException;
|
import org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException;
|
||||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||||
import org.dspace.app.rest.model.EPersonRest;
|
import org.dspace.app.rest.model.EPersonRest;
|
||||||
@@ -34,7 +34,7 @@ import org.dspace.app.rest.model.patch.Patch;
|
|||||||
import org.dspace.app.util.AuthorizeUtil;
|
import org.dspace.app.util.AuthorizeUtil;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
import org.dspace.content.service.SiteService;
|
import org.dspace.authorize.service.ValidatePasswordService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.EmptyWorkflowGroupException;
|
import org.dspace.eperson.EmptyWorkflowGroupException;
|
||||||
@@ -74,10 +74,7 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
|||||||
private AccountService accountService;
|
private AccountService accountService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthorizationFeatureService authorizationFeatureService;
|
private ValidatePasswordService validatePasswordService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private SiteService siteService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RegistrationDataService registrationDataService;
|
private RegistrationDataService registrationDataService;
|
||||||
@@ -129,6 +126,9 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
|||||||
eperson.setEmail(epersonRest.getEmail());
|
eperson.setEmail(epersonRest.getEmail());
|
||||||
eperson.setNetid(epersonRest.getNetid());
|
eperson.setNetid(epersonRest.getNetid());
|
||||||
if (epersonRest.getPassword() != null) {
|
if (epersonRest.getPassword() != null) {
|
||||||
|
if (!validatePasswordService.isPasswordValid(epersonRest.getPassword())) {
|
||||||
|
throw new PasswordNotValidException();
|
||||||
|
}
|
||||||
es.setPassword(eperson, epersonRest.getPassword());
|
es.setPassword(eperson, epersonRest.getPassword());
|
||||||
}
|
}
|
||||||
es.update(context, eperson);
|
es.update(context, eperson);
|
||||||
|
@@ -15,7 +15,9 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
@@ -229,14 +231,20 @@ public class RequestItemRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for authorized user
|
// Check for authorized user
|
||||||
RequestItemAuthor authorizer;
|
List<RequestItemAuthor> authorizers;
|
||||||
try {
|
try {
|
||||||
authorizer = requestItemAuthorExtractor.getRequestItemAuthor(context, ri.getItem());
|
authorizers = requestItemAuthorExtractor.getRequestItemAuthor(context, ri.getItem());
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOG.warn("Failed to find an authorizer: {}", ex.getMessage());
|
LOG.warn("Failed to find an authorizer: {}", ex.getMessage());
|
||||||
authorizer = new RequestItemAuthor("", "");
|
authorizers = Collections.EMPTY_LIST;
|
||||||
}
|
}
|
||||||
if (!authorizer.getEmail().equals(context.getCurrentUser().getEmail())) {
|
|
||||||
|
boolean authorized = false;
|
||||||
|
String requester = context.getCurrentUser().getEmail();
|
||||||
|
for (RequestItemAuthor authorizer : authorizers) {
|
||||||
|
authorized |= authorizer.getEmail().equals(requester);
|
||||||
|
}
|
||||||
|
if (!authorized) {
|
||||||
throw new AuthorizeException("Not authorized to approve this request");
|
throw new AuthorizeException("Not authorized to approve this request");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,9 +12,11 @@ import java.sql.SQLException;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||||
|
import org.dspace.app.rest.exception.PasswordNotValidException;
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
import org.dspace.app.util.AuthorizeUtil;
|
import org.dspace.app.util.AuthorizeUtil;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.authorize.service.ValidatePasswordService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||||
@@ -53,6 +55,9 @@ public class EPersonPasswordAddOperation<R> extends PatchOperation<R> {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AccountService accountService;
|
private AccountService accountService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ValidatePasswordService validatePasswordService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R perform(Context context, R object, Operation operation) {
|
public R perform(Context context, R object, Operation operation) {
|
||||||
checkOperationValue(operation.getValue());
|
checkOperationValue(operation.getValue());
|
||||||
@@ -66,7 +71,13 @@ public class EPersonPasswordAddOperation<R> extends PatchOperation<R> {
|
|||||||
if (StringUtils.isNotBlank(token)) {
|
if (StringUtils.isNotBlank(token)) {
|
||||||
verifyAndDeleteToken(context, eperson, token, operation);
|
verifyAndDeleteToken(context, eperson, token, operation);
|
||||||
}
|
}
|
||||||
ePersonService.setPassword(eperson, (String) operation.getValue());
|
|
||||||
|
String newPassword = (String) operation.getValue();
|
||||||
|
if (!validatePasswordService.isPasswordValid(newPassword)) {
|
||||||
|
throw new PasswordNotValidException();
|
||||||
|
}
|
||||||
|
|
||||||
|
ePersonService.setPassword(eperson, newPassword);
|
||||||
return object;
|
return object;
|
||||||
} else {
|
} else {
|
||||||
throw new DSpaceBadRequestException(this.getClass().getName() + " does not support this operation");
|
throw new DSpaceBadRequestException(this.getClass().getName() + " does not support this operation");
|
||||||
|
@@ -54,20 +54,7 @@ public class OpenSearchControllerIT extends AbstractControllerIntegrationTest {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML is an open issue in OpenSearch, so skip this test at the moment
|
// there is no searchHtmlTest here as the html search is redirected to the angular UI
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
public void searchHtmlTest() throws Exception {
|
|
||||||
//When we call the root endpoint
|
|
||||||
getClient().perform(get("/opensearch/search")
|
|
||||||
.param("query", "cats")
|
|
||||||
.param("format", "html"))
|
|
||||||
//The status has to be 200 OK
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
//We expect the content type to be "application/atom+xml;charset=UTF-8"
|
|
||||||
.andExpect(content().contentType("text/html;charset=UTF-8"))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void searchRssTest() throws Exception {
|
public void searchRssTest() throws Exception {
|
||||||
@@ -201,17 +188,23 @@ public class OpenSearchControllerIT extends AbstractControllerIntegrationTest {
|
|||||||
public void serviceDocumentTest() throws Exception {
|
public void serviceDocumentTest() throws Exception {
|
||||||
//When we call the root endpoint
|
//When we call the root endpoint
|
||||||
getClient().perform(get("/opensearch/service"))
|
getClient().perform(get("/opensearch/service"))
|
||||||
//The status has to be 200 OK
|
// The status has to be 200 OK
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
// and the contentType has to be an opensearchdescription
|
// and the contentType has to be an opensearchdescription
|
||||||
.andExpect(content().contentType("application/opensearchdescription+xml;charset=UTF-8"))
|
.andExpect(content().contentType("application/opensearchdescription+xml;charset=UTF-8"))
|
||||||
// and there need to be some values taken from the test configuration
|
// and there need to be some values taken from the test configuration
|
||||||
.andExpect(xpath("OpenSearchDescription/ShortName").string("DSpace"))
|
.andExpect(xpath("OpenSearchDescription/ShortName").string("DSpace"))
|
||||||
.andExpect(xpath("OpenSearchDescription/LongName").string("DSpace at My University"))
|
.andExpect(xpath("OpenSearchDescription/LongName").string("DSpace at My University"))
|
||||||
.andExpect(xpath("OpenSearchDescription/Description")
|
.andExpect(xpath("OpenSearchDescription/Description")
|
||||||
.string("DSpace at My University DSpace repository")
|
.string("DSpace at My University DSpace repository"))
|
||||||
)
|
.andExpect(xpath("OpenSearchDescription/Url[@type='text/html']/@template")
|
||||||
;
|
.string("http://localhost:4000/search?query={searchTerms}"))
|
||||||
|
.andExpect(xpath("OpenSearchDescription/Url[@type='application/atom+xml; charset=UTF-8']/@template")
|
||||||
|
.string("http://localhost/opensearch/search?"
|
||||||
|
+ "query={searchTerms}&start={startIndex?}&rpp={count?}&format=atom"))
|
||||||
|
.andExpect(xpath("OpenSearchDescription/Url[@type='application/rss+xml; charset=UTF-8']/@template")
|
||||||
|
.string("http://localhost/opensearch/search?"
|
||||||
|
+ "query={searchTerms}&start={startIndex?}&rpp={count?}&format=rss"));
|
||||||
/* Expected response for the service document is:
|
/* Expected response for the service document is:
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
@@ -224,9 +217,9 @@ public class OpenSearchControllerIT extends AbstractControllerIntegrationTest {
|
|||||||
<Tags>IR DSpace</Tags>
|
<Tags>IR DSpace</Tags>
|
||||||
<Contact>dspace-help@myu.edu</Contact>
|
<Contact>dspace-help@myu.edu</Contact>
|
||||||
<Image height="16" width="16" type="image/vnd.microsoft.icon">http://www.dspace.org/images/favicon.ico</Image>
|
<Image height="16" width="16" type="image/vnd.microsoft.icon">http://www.dspace.org/images/favicon.ico</Image>
|
||||||
<Url type="text/html" template="http://localhost:8080/simple-search?query={searchTerms}" />
|
<Url type="text/html" template="http://localhost:4000/search?query={searchTerms}" />
|
||||||
<Url type="application/atom+xml; charset=UTF-8" template="http://localhost:8080/open-search/?query={searchTerms}&start={startIndex?}&rpp={count?}&format=atom" />
|
<Url type="application/atom+xml; charset=UTF-8" template="http://localhost:8080/server/opensearch/search?query={searchTerms}&start={startIndex?}&rpp={count?}&format=atom" />
|
||||||
<Url type="application/rss+xml; charset=UTF-8" template="http://localhost:8080/open-search/?query={searchTerms}&start={startIndex?}&rpp={count?}&format=rss" />
|
<Url type="application/rss+xml; charset=UTF-8" template="http://localhost:8080/server/opensearch/search?query={searchTerms}&start={startIndex?}&rpp={count?}&format=rss" />
|
||||||
</OpenSearchDescription>
|
</OpenSearchDescription>
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@@ -72,17 +72,14 @@ import org.dspace.core.I18nUtil;
|
|||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.eperson.PasswordHash;
|
import org.dspace.eperson.PasswordHash;
|
||||||
import org.dspace.eperson.dao.RegistrationDataDAO;
|
|
||||||
import org.dspace.eperson.service.AccountService;
|
import org.dspace.eperson.service.AccountService;
|
||||||
import org.dspace.eperson.service.EPersonService;
|
import org.dspace.eperson.service.EPersonService;
|
||||||
import org.dspace.eperson.service.RegistrationDataService;
|
import org.dspace.eperson.service.RegistrationDataService;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.workflow.WorkflowService;
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
|
||||||
public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -94,11 +91,6 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EPersonService ePersonService;
|
private EPersonService ePersonService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private WorkflowService workflowService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RegistrationDataDAO registrationDataDAO;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
@@ -1289,7 +1281,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void patchPassword() throws Exception {
|
public void patchPassword() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
@@ -1386,7 +1378,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void patchPasswordForNonAdminUser() throws Exception {
|
public void patchPasswordForNonAdminUser() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
@@ -1564,7 +1556,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void patchPasswordNotInitialised() throws Exception {
|
public void patchPasswordNotInitialised() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
@@ -2009,6 +2001,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void patchReplacePasswordWithToken() throws Exception {
|
public void patchReplacePasswordWithToken() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
@@ -2222,7 +2215,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void postEPersonWithTokenWithoutEmailProperty() throws Exception {
|
public void postEPersonWithTokenWithoutEmailProperty() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
String newRegisterEmail = "new-register@fake-email.com";
|
String newRegisterEmail = "new-register@fake-email.com";
|
||||||
@@ -2286,7 +2279,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void postEPersonWithTokenWithEmailProperty() throws Exception {
|
public void postEPersonWithTokenWithEmailProperty() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
String newRegisterEmail = "new-register@fake-email.com";
|
String newRegisterEmail = "new-register@fake-email.com";
|
||||||
@@ -2348,7 +2341,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void postEPersonWithTokenWithEmailAndSelfRegisteredProperty() throws Exception {
|
public void postEPersonWithTokenWithEmailAndSelfRegisteredProperty() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
String newRegisterEmail = "new-register@fake-email.com";
|
String newRegisterEmail = "new-register@fake-email.com";
|
||||||
@@ -2801,7 +2794,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void postEPersonWithTokenWithEmailPropertyAnonUser() throws Exception {
|
public void postEPersonWithTokenWithEmailPropertyAnonUser() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "");
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
String newRegisterEmail = "new-register@fake-email.com";
|
String newRegisterEmail = "new-register@fake-email.com";
|
||||||
@@ -3129,4 +3122,199 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Test
|
||||||
|
public void validatePasswordRobustnessContainingAtLeastAnUpperCaseCharUnprocessableTest() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "^(?=.*[A-Z])");
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
String newRegisterEmail = "new-register@fake-email.com";
|
||||||
|
RegistrationRest registrationRest = new RegistrationRest();
|
||||||
|
registrationRest.setEmail(newRegisterEmail);
|
||||||
|
|
||||||
|
getClient().perform(post("/api/eperson/registrations")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(mapper.writeValueAsBytes(registrationRest)))
|
||||||
|
.andExpect(status().isCreated());
|
||||||
|
|
||||||
|
String newRegisterToken = registrationDataService.findByEmail(context, newRegisterEmail).getToken();
|
||||||
|
|
||||||
|
EPersonRest ePersonRest = new EPersonRest();
|
||||||
|
MetadataRest metadataRest = new MetadataRest();
|
||||||
|
ePersonRest.setCanLogIn(true);
|
||||||
|
MetadataValueRest surname = new MetadataValueRest();
|
||||||
|
surname.setValue("Misha");
|
||||||
|
metadataRest.put("eperson.lastname", surname);
|
||||||
|
MetadataValueRest firstname = new MetadataValueRest();
|
||||||
|
firstname.setValue("Boychuk");
|
||||||
|
metadataRest.put("eperson.firstname", firstname);
|
||||||
|
ePersonRest.setMetadata(metadataRest);
|
||||||
|
ePersonRest.setPassword("lowercasepassword");
|
||||||
|
|
||||||
|
mapper.setAnnotationIntrospector(new IgnoreJacksonWriteOnlyAccess());
|
||||||
|
|
||||||
|
try {
|
||||||
|
getClient().perform(post("/api/eperson/epersons")
|
||||||
|
.param("token", newRegisterToken)
|
||||||
|
.content(mapper.writeValueAsBytes(ePersonRest))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isUnprocessableEntity());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
registrationDataService.deleteByToken(context, newRegisterToken);
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validatePasswordRobustnessContainingAtLeastAnUpperCaseCharTest() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "^(?=.*[A-Z])");
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
String newRegisterEmail = "new-register@fake-email.com";
|
||||||
|
RegistrationRest registrationRest = new RegistrationRest();
|
||||||
|
registrationRest.setEmail(newRegisterEmail);
|
||||||
|
|
||||||
|
getClient().perform(post("/api/eperson/registrations")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(mapper.writeValueAsBytes(registrationRest)))
|
||||||
|
.andExpect(status().isCreated());
|
||||||
|
|
||||||
|
String newRegisterToken = registrationDataService.findByEmail(context, newRegisterEmail).getToken();
|
||||||
|
|
||||||
|
EPersonRest ePersonRest = new EPersonRest();
|
||||||
|
MetadataRest metadataRest = new MetadataRest();
|
||||||
|
ePersonRest.setCanLogIn(true);
|
||||||
|
MetadataValueRest surname = new MetadataValueRest();
|
||||||
|
surname.setValue("Boychuk");
|
||||||
|
metadataRest.put("eperson.lastname", surname);
|
||||||
|
MetadataValueRest firstname = new MetadataValueRest();
|
||||||
|
firstname.setValue("Misha");
|
||||||
|
metadataRest.put("eperson.firstname", firstname);
|
||||||
|
ePersonRest.setMetadata(metadataRest);
|
||||||
|
ePersonRest.setPassword("Lowercasepassword");
|
||||||
|
AtomicReference<UUID> idRef = new AtomicReference<UUID>();
|
||||||
|
|
||||||
|
mapper.setAnnotationIntrospector(new IgnoreJacksonWriteOnlyAccess());
|
||||||
|
|
||||||
|
try {
|
||||||
|
getClient().perform(post("/api/eperson/epersons")
|
||||||
|
.param("token", newRegisterToken)
|
||||||
|
.content(mapper.writeValueAsBytes(ePersonRest))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("$", Matchers.allOf(
|
||||||
|
hasJsonPath("$.uuid", not(empty())),
|
||||||
|
hasJsonPath("$.type", is("eperson")),
|
||||||
|
hasJsonPath("$._links.self.href", not(empty())),
|
||||||
|
hasJsonPath("$.metadata", Matchers.allOf(
|
||||||
|
matchMetadata("eperson.firstname", "Misha"),
|
||||||
|
matchMetadata("eperson.lastname", "Boychuk"))))))
|
||||||
|
.andDo(result -> idRef.set(UUID.fromString(read(result.getResponse().getContentAsString(), "$.id"))));
|
||||||
|
|
||||||
|
EPerson createdEPerson = ePersonService.find(context, UUID.fromString(String.valueOf(idRef.get())));
|
||||||
|
assertTrue(ePersonService.checkPassword(context, createdEPerson, "Lowercasepassword"));
|
||||||
|
assertNull(registrationDataService.findByToken(context, newRegisterToken));
|
||||||
|
} finally {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
registrationDataService.deleteByToken(context, newRegisterToken);
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
EPersonBuilder.deleteEPerson(idRef.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validatePasswordRobustnessContainingAtLeastAnUppercaseCharPatchUnprocessableTest() throws Exception {
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withNameInMetadata("John", "Doe")
|
||||||
|
.withEmail("Johndoe@example.com")
|
||||||
|
.withPassword("TestPassword")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "^(?=.*[A-Z])");
|
||||||
|
|
||||||
|
String newPassword = "newpassword";
|
||||||
|
|
||||||
|
List<Operation> ops = new ArrayList<Operation>();
|
||||||
|
AddOperation addOperation = new AddOperation("/password", newPassword);
|
||||||
|
ops.add(addOperation);
|
||||||
|
String patchBody = getPatchContent(ops);
|
||||||
|
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
// updates password
|
||||||
|
getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||||
|
.andExpect(status().isUnprocessableEntity());
|
||||||
|
|
||||||
|
// can't login with new password
|
||||||
|
token = getAuthToken(ePerson.getEmail(), newPassword);
|
||||||
|
getClient(token).perform(get("/api/authn/status"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.okay", is(true)))
|
||||||
|
.andExpect(jsonPath("$.authenticated", is(false)))
|
||||||
|
.andExpect(jsonPath("$.type", is("status")));
|
||||||
|
|
||||||
|
// login with origin password
|
||||||
|
token = getAuthToken(ePerson.getEmail(), "TestPassword");
|
||||||
|
getClient(token).perform(get("/api/authn/status"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.okay", is(true)))
|
||||||
|
.andExpect(jsonPath("$.authenticated", is(true)))
|
||||||
|
.andExpect(jsonPath("$.type", is("status")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validatePasswordRobustnessContainingAtLeastAnUppercaseCharPatchTest() throws Exception {
|
||||||
|
configurationService.setProperty("authentication-password.regex-validation.pattern", "^(?=.*[A-Z])");
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withNameInMetadata("John", "Doe")
|
||||||
|
.withEmail("Johndoe@example.com")
|
||||||
|
.withPassword("TestPassword")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
String newPassword = "Newpassword";
|
||||||
|
|
||||||
|
List<Operation> ops = new ArrayList<Operation>();
|
||||||
|
AddOperation addOperation = new AddOperation("/password", newPassword);
|
||||||
|
ops.add(addOperation);
|
||||||
|
String patchBody = getPatchContent(ops);
|
||||||
|
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
// updates password
|
||||||
|
getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
// login with new password
|
||||||
|
token = getAuthToken(ePerson.getEmail(), newPassword);
|
||||||
|
getClient(token).perform(get("/api/authn/status"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.okay", is(true)))
|
||||||
|
.andExpect(jsonPath("$.authenticated", is(true)))
|
||||||
|
.andExpect(jsonPath("$.type", is("status")));
|
||||||
|
|
||||||
|
// can't login with old password
|
||||||
|
token = getAuthToken(ePerson.getEmail(), "TestPassword");
|
||||||
|
getClient(token).perform(get("/api/authn/status"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.okay", is(true)))
|
||||||
|
.andExpect(jsonPath("$.authenticated", is(false)))
|
||||||
|
.andExpect(jsonPath("$.type", is("status")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -994,6 +994,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
}
|
}
|
||||||
bibtex.close();
|
bibtex.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file
|
* Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file
|
||||||
@@ -1187,6 +1188,112 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
bibtex.close();
|
bibtex.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
/**
|
||||||
|
* Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void createSingleWorkspaceItemFromBibtexFileWithMultipleAuthorsTest() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
//** GIVEN **
|
||||||
|
//1. A community-collection structure with one parent community with sub-community and two collections.
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
|
||||||
|
.withName("Sub Community")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 1")
|
||||||
|
.withSubmitterGroup(eperson)
|
||||||
|
.build();
|
||||||
|
Collection col2 = CollectionBuilder.createCollection(context, child1)
|
||||||
|
.withName("Collection 2")
|
||||||
|
.withSubmitterGroup(eperson)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InputStream bibtex = getClass().getResourceAsStream("bibtex-test-multiple-authors.bib");
|
||||||
|
final MockMultipartFile bibtexFile = new MockMultipartFile("file",
|
||||||
|
"/local/path/bibtex-test-multiple-authors.bib",
|
||||||
|
"application/x-bibtex", bibtex);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
AtomicReference<List<Integer>> idRef = new AtomicReference<>();
|
||||||
|
String authToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
try {
|
||||||
|
// create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1)
|
||||||
|
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||||
|
.file(bibtexFile))
|
||||||
|
// create should return 200, 201 (created) is better for single resource
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0]" +
|
||||||
|
".sections.traditionalpageone['dc.title'][0].value",
|
||||||
|
is("My Article")))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0]" +
|
||||||
|
".sections.traditionalpageone['dc.contributor.author'][0].value",
|
||||||
|
is("A. Nauthor")))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0]" +
|
||||||
|
".sections.traditionalpageone['dc.contributor.author'][1].value",
|
||||||
|
is("A. Nother")))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0]" +
|
||||||
|
".sections.traditionalpageone['dc.contributor.author'][2].value",
|
||||||
|
is("A. Third")))
|
||||||
|
.andExpect(
|
||||||
|
jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
|
||||||
|
is(col1.getID().toString())))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
|
||||||
|
+ ".metadata['dc.source'][0].value",
|
||||||
|
is("/local/path/bibtex-test-multiple-authors.bib")))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
|
||||||
|
+ ".metadata['dc.title'][0].value",
|
||||||
|
is("bibtex-test-multiple-authors.bib")))
|
||||||
|
.andExpect(
|
||||||
|
jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
|
||||||
|
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
|
||||||
|
"$._embedded.workspaceitems[*].id")));
|
||||||
|
} finally {
|
||||||
|
if (idRef != null && idRef.get() != null) {
|
||||||
|
for (int i : idRef.get()) {
|
||||||
|
WorkspaceItemBuilder.deleteWorkspaceItem(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a workspaceitem from a single bibliographic entry file explicitly in the col2
|
||||||
|
try {
|
||||||
|
getClient(authToken).perform(multipart("/api/submission/workspaceitems")
|
||||||
|
.file(bibtexFile)
|
||||||
|
.param("owningCollection", col2.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0]" +
|
||||||
|
".sections.traditionalpageone['dc.title'][0].value",
|
||||||
|
is("My Article")))
|
||||||
|
.andExpect(
|
||||||
|
jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id",
|
||||||
|
is(col2.getID().toString())))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0]"
|
||||||
|
+ ".metadata['dc.source'][0].value",
|
||||||
|
is("/local/path/bibtex-test-multiple-authors.bib")))
|
||||||
|
.andExpect(jsonPath("$._embedded.workspaceitems[0].sections.upload"
|
||||||
|
+ ".files[0].metadata['dc.title'][0].value",
|
||||||
|
is("bibtex-test-multiple-authors.bib")))
|
||||||
|
.andExpect(
|
||||||
|
jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist())
|
||||||
|
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(),
|
||||||
|
"$._embedded.workspaceitems[*].id")));
|
||||||
|
} finally {
|
||||||
|
if (idRef != null && idRef.get() != null) {
|
||||||
|
for (int i : idRef.get()) {
|
||||||
|
WorkspaceItemBuilder.deleteWorkspaceItem(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bibtex.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* Test the creation of workspaceitems POSTing to the resource collection endpoint a csv file
|
* Test the creation of workspaceitems POSTing to the resource collection endpoint a csv file
|
||||||
|
@@ -142,10 +142,10 @@ public class DeleteEPersonSubmitterIT extends AbstractControllerIntegrationTest
|
|||||||
|
|
||||||
|
|
||||||
Item item = itemService.find(context, installItem.getID());
|
Item item = itemService.find(context, installItem.getID());
|
||||||
RequestItemAuthor requestItemAuthor = requestItemAuthorExtractor.getRequestItemAuthor(context, item);
|
List<RequestItemAuthor> requestItemAuthor = requestItemAuthorExtractor.getRequestItemAuthor(context, item);
|
||||||
|
|
||||||
assertEquals("Help Desk", requestItemAuthor.getFullName());
|
assertEquals("Help Desk", requestItemAuthor.get(0).getFullName());
|
||||||
assertEquals("dspace-help@myu.edu", requestItemAuthor.getEmail());
|
assertEquals("dspace-help@myu.edu", requestItemAuthor.get(0).getEmail());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,7 +171,7 @@ public class DeleteEPersonSubmitterIT extends AbstractControllerIntegrationTest
|
|||||||
|
|
||||||
Item item = installItemService.installItem(context, wsi);
|
Item item = installItemService.installItem(context, wsi);
|
||||||
|
|
||||||
List<Operation> opsToWithDraw = new ArrayList<Operation>();
|
List<Operation> opsToWithDraw = new ArrayList<>();
|
||||||
ReplaceOperation replaceOperationToWithDraw = new ReplaceOperation("/withdrawn", true);
|
ReplaceOperation replaceOperationToWithDraw = new ReplaceOperation("/withdrawn", true);
|
||||||
opsToWithDraw.add(replaceOperationToWithDraw);
|
opsToWithDraw.add(replaceOperationToWithDraw);
|
||||||
String patchBodyToWithdraw = getPatchContent(opsToWithDraw);
|
String patchBodyToWithdraw = getPatchContent(opsToWithDraw);
|
||||||
@@ -191,7 +191,7 @@ public class DeleteEPersonSubmitterIT extends AbstractControllerIntegrationTest
|
|||||||
|
|
||||||
assertNull(retrieveItemSubmitter(item.getID()));
|
assertNull(retrieveItemSubmitter(item.getID()));
|
||||||
|
|
||||||
List<Operation> opsToReinstate = new ArrayList<Operation>();
|
List<Operation> opsToReinstate = new ArrayList<>();
|
||||||
ReplaceOperation replaceOperationToReinstate = new ReplaceOperation("/withdrawn", false);
|
ReplaceOperation replaceOperationToReinstate = new ReplaceOperation("/withdrawn", false);
|
||||||
opsToReinstate.add(replaceOperationToReinstate);
|
opsToReinstate.add(replaceOperationToReinstate);
|
||||||
String patchBodyToReinstate = getPatchContent(opsToReinstate);
|
String patchBodyToReinstate = getPatchContent(opsToReinstate);
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
@misc{ Nobody01,
|
||||||
|
author = "A. Nauthor and A. Nother and A. Third",
|
||||||
|
title = "My Article",
|
||||||
|
year = "2006" }
|
@@ -1320,10 +1320,10 @@ webui.feed.item.author = dc.contributor.author
|
|||||||
# so even if Syndication Feeds are not enabled, they must be configured
|
# so even if Syndication Feeds are not enabled, they must be configured
|
||||||
# enable open search
|
# enable open search
|
||||||
websvc.opensearch.enable = true
|
websvc.opensearch.enable = true
|
||||||
# url used in service document
|
|
||||||
websvc.opensearch.svccontext = opensearch
|
|
||||||
# context for html request URLs - change only for non-standard servlet mapping
|
# context for html request URLs - change only for non-standard servlet mapping
|
||||||
websvc.opensearch.uicontext = simple-search
|
websvc.opensearch.uicontext = search
|
||||||
|
# context for xml request URLs - change only for non-standard servlet mapping
|
||||||
|
websvc.opensearch.svccontext = opensearch/search
|
||||||
# present autodiscovery link in every page head
|
# present autodiscovery link in every page head
|
||||||
websvc.opensearch.autolink = true
|
websvc.opensearch.autolink = true
|
||||||
# number of hours to retain results before recalculating
|
# number of hours to retain results before recalculating
|
||||||
@@ -1342,8 +1342,8 @@ websvc.opensearch.samplequery = photosynthesis
|
|||||||
# tags used to describe search service
|
# tags used to describe search service
|
||||||
websvc.opensearch.tags = IR DSpace
|
websvc.opensearch.tags = IR DSpace
|
||||||
# result formats offered - use 1 or more comma-separated from: html,atom,rss
|
# result formats offered - use 1 or more comma-separated from: html,atom,rss
|
||||||
# NB: html is not supported in DSpace7, use normal search module instead
|
# html uses the normal search module
|
||||||
websvc.opensearch.formats = atom,rss
|
websvc.opensearch.formats = html,atom,rss
|
||||||
|
|
||||||
|
|
||||||
#### Content Inline Disposition Threshold ####
|
#### Content Inline Disposition Threshold ####
|
||||||
@@ -1557,6 +1557,13 @@ solr-database-resync.time-until-reindex = 600000
|
|||||||
# Keep in mind, changing the schedule requires rebooting your servlet container, e.g. Tomcat.
|
# Keep in mind, changing the schedule requires rebooting your servlet container, e.g. Tomcat.
|
||||||
solr-database-resync.cron = 0 15 2 * * ?
|
solr-database-resync.cron = 0 15 2 * * ?
|
||||||
|
|
||||||
|
#----------------------------------------------------------#
|
||||||
|
#----------PROCESS CLEANER SCRIPT CONFIGURATION------------#
|
||||||
|
#----------------------------------------------------------#
|
||||||
|
# Processes older than this number of days will be deleted when the "process-cleaner" script is next run.
|
||||||
|
# Default is 14 (i.e. processes that are two weeks or older will be deleted)
|
||||||
|
# process-cleaner.days = 14
|
||||||
|
|
||||||
#------------------------------------------------------------------#
|
#------------------------------------------------------------------#
|
||||||
#-------------------MODULE CONFIGURATIONS--------------------------#
|
#-------------------MODULE CONFIGURATIONS--------------------------#
|
||||||
#------------------------------------------------------------------#
|
#------------------------------------------------------------------#
|
||||||
|
@@ -26,3 +26,24 @@
|
|||||||
# SHA-256, SHA-384, and SHA-512 should be available, but you may have
|
# SHA-256, SHA-384, and SHA-512 should be available, but you may have
|
||||||
# installed others. If not set, SHA-512 will be used.
|
# installed others. If not set, SHA-512 will be used.
|
||||||
# authentication-password.digestAlgorithm = SHA-512
|
# authentication-password.digestAlgorithm = SHA-512
|
||||||
|
|
||||||
|
###### Validate Password Robustness Configuration ######
|
||||||
|
# (by default is enabled, to disable, either comment out this configuration or set it to an empty value)
|
||||||
|
# This regular expression is used to validate password during creation of EPerson
|
||||||
|
# or during the patch of password.
|
||||||
|
# NOTE: when you configure a custom regex, you will also need to update the text of
|
||||||
|
# "org.dspace.app.rest.exception.PasswordNotValidException.message" in Messages.properties to describe the minimum requirements.
|
||||||
|
#
|
||||||
|
# The following regex applies subsequent rules: ^(?=.*?[a-z])(?=.*?[A-Z])(?=\\S*?[0-9])(?=\\S*?[!?$@#$%^&+=]).{8\,15}$
|
||||||
|
# 1) (?=.*?[a-z]) - the password must contain at least one lowercase character
|
||||||
|
# 2) (?=.*?[A-Z]) - the password must contain at least one uppercase character
|
||||||
|
# 3) (?=\\S*?[0-9]) - the password must contain at least one numeric character
|
||||||
|
# 4) (?=\\S*?[!?$@#$%^&+=]) - the password must contain at least one of the following special character: !?$@#$%^&+=
|
||||||
|
# 5) {8\,15} - the password must be at least 8 and at most 15 characters long
|
||||||
|
# REMARK: {8\,15} - the slash in this regex is an exception of the Apache library, as "," is a special character,
|
||||||
|
# consequently to interpret it correctly you have to add the slash in front
|
||||||
|
|
||||||
|
# By default, DSpace just requires a password of 8 or more characters.
|
||||||
|
# However, we recommend most sites consider either increasing the required length or complexity (see example above)
|
||||||
|
authentication-password.regex-validation.pattern = ^.{8\,}$
|
||||||
|
|
||||||
|
@@ -15,6 +15,7 @@ plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.RequiredM
|
|||||||
#plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.MicrosoftTranslator = translate
|
#plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.MicrosoftTranslator = translate
|
||||||
plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.MetadataValueLinkChecker = checklinks
|
plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.MetadataValueLinkChecker = checklinks
|
||||||
plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.RegisterDOI = registerdoi
|
plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.RegisterDOI = registerdoi
|
||||||
|
#plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.CitationPage = citationpage
|
||||||
# add new tasks here (or in additional config files)
|
# add new tasks here (or in additional config files)
|
||||||
|
|
||||||
## task queue implementation
|
## task queue implementation
|
||||||
|
@@ -40,9 +40,14 @@
|
|||||||
<property name="key" value="journal" />
|
<property name="key" value="journal" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="bibtexAuthorsContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleMetadataContributor">
|
<bean id="bibtexAuthorsContrib" class="org.dspace.importer.external.metadatamapping.contributor.SplitMetadataContributor">
|
||||||
<property name="field" ref="dcAuthors"/>
|
<constructor-arg name="innerContributor">
|
||||||
<property name="key" value="author" />
|
<bean class="org.dspace.importer.external.metadatamapping.contributor.SimpleMetadataContributor">
|
||||||
|
<property name="field" ref="dcAuthors"/>
|
||||||
|
<property name="key" value="author" />
|
||||||
|
</bean>
|
||||||
|
</constructor-arg>
|
||||||
|
<constructor-arg name="regex" value="\sand\s"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="bibtexTitleContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleMetadataContributor">
|
<bean id="bibtexTitleContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleMetadataContributor">
|
||||||
|
@@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
<bean id="versionServiceFactory" class="org.dspace.versioning.factory.VersionServiceFactoryImpl"/>
|
<bean id="versionServiceFactory" class="org.dspace.versioning.factory.VersionServiceFactoryImpl"/>
|
||||||
|
|
||||||
|
<bean id="validationPasswordFactory" class="org.dspace.passwordvalidation.factory.PasswordValidationFactoryImpl"/>
|
||||||
|
|
||||||
<!--Configurable workflow services -->
|
<!--Configurable workflow services -->
|
||||||
<bean id="workflowServiceFactory" class="org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactoryImpl"/>
|
<bean id="workflowServiceFactory" class="org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactoryImpl"/>
|
||||||
|
|
||||||
|
@@ -143,5 +143,8 @@
|
|||||||
<bean class="org.dspace.authenticate.OidcAuthenticationBean" id="oidcAuthentication"/>
|
<bean class="org.dspace.authenticate.OidcAuthenticationBean" id="oidcAuthentication"/>
|
||||||
<bean class="org.dspace.authenticate.oidc.impl.OidcClientImpl" />
|
<bean class="org.dspace.authenticate.oidc.impl.OidcClientImpl" />
|
||||||
|
|
||||||
|
<bean class="org.dspace.authorize.ValidatePasswordServiceImpl"/>
|
||||||
|
<bean class="org.dspace.authorize.RegexPasswordValidator" />
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://www.springframework.org/schema/util
|
||||||
|
http://www.springframework.org/schema/util/spring-util.xsd"
|
||||||
default-lazy-init="true">
|
default-lazy-init="true">
|
||||||
|
|
||||||
<bean id="openAIRERestConnector" class="org.dspace.external.OpenAIRERestConnector">
|
<bean id="openAIRERestConnector" class="org.dspace.external.OpenAIRERestConnector">
|
||||||
@@ -10,17 +14,65 @@
|
|||||||
<property name="clientId" value="${openaire.token.clientId}"/>
|
<property name="clientId" value="${openaire.token.clientId}"/>
|
||||||
<property name="clientSecret" value="${openaire.token.clientSecret}"/>
|
<property name="clientSecret" value="${openaire.token.clientSecret}"/>
|
||||||
</bean>
|
</bean>
|
||||||
<bean
|
|
||||||
class="org.dspace.external.provider.impl.OpenAIREFundingDataProvider"
|
<bean class="org.dspace.external.provider.impl.OpenAIREFundingDataProvider" init-method="init">
|
||||||
init-method="init">
|
|
||||||
<property name="sourceIdentifier" value="openAIREFunding" />
|
<property name="sourceIdentifier" value="openAIREFunding" />
|
||||||
<property name="connector" ref="openAIRERestConnector" />
|
<property name="connector" ref="openAIRERestConnector" />
|
||||||
|
<property name="metadataFields" ref="mapOfmetadata"/>
|
||||||
<property name="supportedEntityTypes">
|
<property name="supportedEntityTypes">
|
||||||
<list>
|
<list>
|
||||||
<value>Project</value>
|
<value>Project</value>
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
</beans>
|
|
||||||
|
|
||||||
|
<util:map id="mapOfmetadata"
|
||||||
|
map-class="java.util.HashMap" key-type="java.lang.String" value-type="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<entry key="awardNumber" value-ref="openaireAwardNumber" />
|
||||||
|
<entry key="fundingStream" value-ref="openaireFundingStream" />
|
||||||
|
<entry key="awardURI" value-ref="openaireAwardURI" />
|
||||||
|
<entry key="funderName" value-ref="openaireFunderName" />
|
||||||
|
<entry key="funderIdentifier" value-ref="openaireFunderIdentifier" />
|
||||||
|
<entry key="dcTitle" value-ref="openaireTitle" />
|
||||||
|
<entry key="titleAlternative" value-ref="openaireTitleAlternative" />
|
||||||
|
<entry key="coverageSpatial" value-ref="openaireSpatial" />
|
||||||
|
<entry key="dcSubject" value-ref="openaireSubject" />
|
||||||
|
</util:map>
|
||||||
|
|
||||||
|
<bean id="openaireAwardNumber" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="oaire.awardNumber"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireFundingStream" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="oaire.fundingStream"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireAwardURI" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="oaire.awardURI"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireFunderName" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="project.funder.name"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireFunderIdentifier" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="project.funder.identifier"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireTitle" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.title"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireTitleAlternative" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.title.alternative"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireSpatial" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.coverage.spatial"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openaireSubject" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.subject"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
@@ -8,25 +8,65 @@
|
|||||||
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
|
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
|
||||||
default-autowire-candidates="*Service,*DAO,javax.sql.DataSource">
|
default-autowire-candidates="*Service,*DAO,javax.sql.DataSource">
|
||||||
|
|
||||||
|
<description>
|
||||||
|
Strategies for determining who receives Request Copy emails.
|
||||||
|
A copy request "strategy" class produces a list of addresses to which a
|
||||||
|
request email should be sent. Each strategy gets its addresses from a
|
||||||
|
different source. Select the one that meets your need, or use the
|
||||||
|
CombiningRequestItemStrategy to meld the lists from two or more other
|
||||||
|
strategies.
|
||||||
|
</description>
|
||||||
|
|
||||||
<context:annotation-config /> <!-- allows us to use Spring annotations in beans -->
|
<context:annotation-config /> <!-- allows us to use Spring annotations in beans -->
|
||||||
|
|
||||||
<bean class="org.dspace.app.requestitem.RequestItemMetadataStrategy"
|
<!-- Select the implementation to be used. -->
|
||||||
id="org.dspace.app.requestitem.RequestItemAuthorExtractor"
|
<alias alias='org.dspace.app.requestitem.RequestItemAuthorExtractor'
|
||||||
autowire-candidate='true'>
|
name='org.dspace.app.requestitem.RequestItemMetadataStrategy'/>
|
||||||
<!--
|
|
||||||
Uncomment these properties if you want lookup in metadata the email and
|
|
||||||
the name of the author to contact for request copy.
|
|
||||||
If you don't configure that or if the requested item doesn't have these
|
|
||||||
metadata, the submitter data are used as fail over.
|
|
||||||
|
|
||||||
<property name="emailMetadata" value="schema.element.qualifier" />
|
<!-- Get recipients from an item metadata field. -->
|
||||||
<property name="fullNameMetadata" value="schema.element.qualifier" />
|
<bean class="org.dspace.app.requestitem.RequestItemMetadataStrategy"
|
||||||
-->
|
id="org.dspace.app.requestitem.RequestItemMetadataStrategy"
|
||||||
|
autowire-candidate="true">
|
||||||
|
<!--
|
||||||
|
Uncomment these properties if you want lookup in metadata the email
|
||||||
|
and the name of the author to contact for request copy.
|
||||||
|
If you don't configure that or if the requested item doesn't have
|
||||||
|
these metadata, the submitter data are used as fail over.
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
|
||||||
|
<property name="emailMetadata"
|
||||||
|
value="schema.element.qualifier" />
|
||||||
|
<property name="fullNameMetadata"
|
||||||
|
value="schema.element.qualifier" />
|
||||||
|
-->
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- HelpDesk to instead get RequestItem emails-->
|
<!-- HelpDesk to instead get RequestItem emails-->
|
||||||
<!--<bean class="org.dspace.app.requestitem.RequestItemHelpdeskStrategy"
|
<!--
|
||||||
id="org.dspace.app.requestitem.RequestItemAuthorExtractor"
|
<bean class="org.dspace.app.requestitem.RequestItemHelpdeskStrategy"
|
||||||
autowire-candidate='true'></bean>-->
|
id="org.dspace.app.requestitem.RequestItemHelpdeskStrategy"/>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Send request emails to administrators of an Item's owning Collection. -->
|
||||||
|
<!--
|
||||||
|
<bean class='org.dspace.app.requestitem.CollectionAdministratorsRequestItemStrategy'
|
||||||
|
id='org.dspace.app.requestitem.CollectionAdministratorsRequestItemStrategy'/>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Execute multiple strategies and concatenate their lists of recipients.
|
||||||
|
Mail will go to all members of the combined list. -->
|
||||||
|
<!--
|
||||||
|
<bean class='org.dspace.app.requestitem.CombiningRequestItemStrategy'
|
||||||
|
id='org.dspace.app.requestitem.CombiningRequestItemStrategy'
|
||||||
|
autowire='no'>
|
||||||
|
<constructor-arg>
|
||||||
|
<description>A list of references to RequestItemAuthorExtractor beans</description>
|
||||||
|
<list>
|
||||||
|
<ref bean='org.dspace.app.requestitem.RequestItemMetadataStrategy'/>
|
||||||
|
<ref bean='org.dspace.app.requestitem.CollectionAdministratorsRequestItemStrategy'/>
|
||||||
|
</list>
|
||||||
|
</constructor-arg>
|
||||||
|
</bean>
|
||||||
|
-->
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -50,6 +50,11 @@
|
|||||||
<property name="description" value="Manage the OAI-PMH harvesting of external collections"/>
|
<property name="description" value="Manage the OAI-PMH harvesting of external collections"/>
|
||||||
<property name="dspaceRunnableClass" value="org.dspace.app.harvest.HarvestCli"/>
|
<property name="dspaceRunnableClass" value="org.dspace.app.harvest.HarvestCli"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="process-cleaner" class="org.dspace.administer.ProcessCleanerCliConfiguration">
|
||||||
|
<property name="description" value="Cleanup all the old processes in the specified state"/>
|
||||||
|
<property name="dspaceRunnableClass" value="org.dspace.administer.ProcessCleanerCli"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="filter-media" class="org.dspace.app.mediafilter.MediaFilterScriptConfiguration">
|
<bean id="filter-media" class="org.dspace.app.mediafilter.MediaFilterScriptConfiguration">
|
||||||
<property name="description" value="Perform the media filtering to extract full text from documents and to create thumbnails"/>
|
<property name="description" value="Perform the media filtering to extract full text from documents and to create thumbnails"/>
|
||||||
|
@@ -39,6 +39,11 @@
|
|||||||
<property name="dspaceRunnableClass" value="org.dspace.app.harvest.Harvest"/>
|
<property name="dspaceRunnableClass" value="org.dspace.app.harvest.Harvest"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="process-cleaner" class="org.dspace.administer.ProcessCleanerConfiguration" primary="true">
|
||||||
|
<property name="description" value="Cleanup all the old processes in the specified state"/>
|
||||||
|
<property name="dspaceRunnableClass" value="org.dspace.administer.ProcessCleaner"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="orcid-bulk-push" class="org.dspace.orcid.script.OrcidBulkPushScriptConfiguration" primary="true">
|
<bean id="orcid-bulk-push" class="org.dspace.orcid.script.OrcidBulkPushScriptConfiguration" primary="true">
|
||||||
<property name="description" value="Perform the bulk synchronization of all the BATCH configured ORCID entities placed in the ORCID queue"/>
|
<property name="description" value="Perform the bulk synchronization of all the BATCH configured ORCID entities placed in the ORCID queue"/>
|
||||||
<property name="dspaceRunnableClass" value="org.dspace.orcid.script.OrcidBulkPush"/>
|
<property name="dspaceRunnableClass" value="org.dspace.orcid.script.OrcidBulkPush"/>
|
||||||
|
Reference in New Issue
Block a user