mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-15 22:13:08 +00:00
Merge branch 'main' into w2p-99200_request-copy-bugfix
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.alerts;
|
||||
|
||||
/**
|
||||
* Enum representing the options for allowing sessions:
|
||||
* ALLOW_ALL_SESSIONS - Will allow all users to log in and continue their sessions
|
||||
* ALLOW_CURRENT_SESSIONS_ONLY - Will prevent non admin users from logging in, however logged-in users
|
||||
* will remain logged in
|
||||
* ALLOW_ADMIN_SESSIONS_ONLY - Only admin users can log in, non admin sessions will be interrupted
|
||||
*
|
||||
* NOTE: This functionality can be stored in the database, but no support is present right now to interrupt and prevent
|
||||
* sessions.
|
||||
*/
|
||||
public enum AllowSessionsEnum {
|
||||
ALLOW_ALL_SESSIONS("all"),
|
||||
ALLOW_CURRENT_SESSIONS_ONLY("current"),
|
||||
ALLOW_ADMIN_SESSIONS_ONLY("admin");
|
||||
|
||||
private String allowSessionsType;
|
||||
|
||||
AllowSessionsEnum(String allowSessionsType) {
|
||||
this.allowSessionsType = allowSessionsType;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return allowSessionsType;
|
||||
}
|
||||
|
||||
public static AllowSessionsEnum fromString(String alertAllowSessionType) {
|
||||
if (alertAllowSessionType == null) {
|
||||
return AllowSessionsEnum.ALLOW_ALL_SESSIONS;
|
||||
}
|
||||
|
||||
switch (alertAllowSessionType) {
|
||||
case "all":
|
||||
return AllowSessionsEnum.ALLOW_ALL_SESSIONS;
|
||||
case "current":
|
||||
return AllowSessionsEnum.ALLOW_CURRENT_SESSIONS_ONLY;
|
||||
case "admin" :
|
||||
return AllowSessionsEnum.ALLOW_ADMIN_SESSIONS_ONLY;
|
||||
default:
|
||||
throw new IllegalArgumentException("No corresponding enum value for provided string: "
|
||||
+ alertAllowSessionType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
179
dspace-api/src/main/java/org/dspace/alerts/SystemWideAlert.java
Normal file
179
dspace-api/src/main/java/org/dspace/alerts/SystemWideAlert.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* 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.alerts;
|
||||
|
||||
import java.util.Date;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
/**
|
||||
* Database object representing system-wide alerts
|
||||
*/
|
||||
@Entity
|
||||
@Cacheable
|
||||
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, include = "non-lazy")
|
||||
@Table(name = "systemwidealert")
|
||||
public class SystemWideAlert implements ReloadableEntity<Integer> {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "alert_id_seq")
|
||||
@SequenceGenerator(name = "alert_id_seq", sequenceName = "alert_id_seq", allocationSize = 1)
|
||||
@Column(name = "alert_id", unique = true, nullable = false)
|
||||
private Integer alertId;
|
||||
|
||||
@Column(name = "message", nullable = false)
|
||||
private String message;
|
||||
|
||||
@Column(name = "allow_sessions")
|
||||
private String allowSessions;
|
||||
|
||||
@Column(name = "countdown_to")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date countdownTo;
|
||||
|
||||
@Column(name = "active")
|
||||
private boolean active;
|
||||
|
||||
protected SystemWideAlert() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the ID that the system-wide alert holds within the database
|
||||
*
|
||||
* @return The ID that the system-wide alert holds within the database
|
||||
*/
|
||||
@Override
|
||||
public Integer getID() {
|
||||
return alertId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ID for the system-wide alert
|
||||
*
|
||||
* @param alertID The ID to set
|
||||
*/
|
||||
public void setID(final Integer alertID) {
|
||||
this.alertId = alertID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message of the system-wide alert
|
||||
*
|
||||
* @return the message of the system-wide alert
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message of the system-wide alert
|
||||
*
|
||||
* @param message The message to set
|
||||
*/
|
||||
public void setMessage(final String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve what kind of sessions are allowed while the system-wide alert is active
|
||||
*
|
||||
* @return what kind of sessions are allowed while the system-wide alert is active
|
||||
*/
|
||||
public AllowSessionsEnum getAllowSessions() {
|
||||
return AllowSessionsEnum.fromString(allowSessions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set what kind of sessions are allowed while the system-wide alert is active
|
||||
*
|
||||
* @param allowSessions Integer representing what kind of sessions are allowed
|
||||
*/
|
||||
public void setAllowSessions(AllowSessionsEnum allowSessions) {
|
||||
this.allowSessions = allowSessions.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the date to which will be count down when the system-wide alert is active
|
||||
*
|
||||
* @return the date to which will be count down when the system-wide alert is active
|
||||
*/
|
||||
public Date getCountdownTo() {
|
||||
return countdownTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date to which will be count down when the system-wide alert is active
|
||||
*
|
||||
* @param countdownTo The date to which will be count down
|
||||
*/
|
||||
public void setCountdownTo(final Date countdownTo) {
|
||||
this.countdownTo = countdownTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the system-wide alert is active
|
||||
*
|
||||
* @return whether the system-wide alert is active
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the system-wide alert is active
|
||||
*
|
||||
* @param active Whether the system-wide alert is active
|
||||
*/
|
||||
public void setActive(final boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if <code>other</code> is the same SystemWideAlert
|
||||
* as this object, <code>false</code> otherwise
|
||||
*
|
||||
* @param other object to compare to
|
||||
* @return <code>true</code> if object passed in represents the same
|
||||
* system-wide alert as this object
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof SystemWideAlert &&
|
||||
new EqualsBuilder().append(this.getID(), ((SystemWideAlert) other).getID())
|
||||
.append(this.getMessage(), ((SystemWideAlert) other).getMessage())
|
||||
.append(this.getAllowSessions(), ((SystemWideAlert) other).getAllowSessions())
|
||||
.append(this.getCountdownTo(), ((SystemWideAlert) other).getCountdownTo())
|
||||
.append(this.isActive(), ((SystemWideAlert) other).isActive())
|
||||
.isEquals());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(this.getID())
|
||||
.append(this.getMessage())
|
||||
.append(this.getAllowSessions())
|
||||
.append(this.getCountdownTo())
|
||||
.append(this.isActive())
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.alerts;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.alerts.dao.SystemWideAlertDAO;
|
||||
import org.dspace.alerts.service.SystemWideAlertService;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* The implementation for the {@link SystemWideAlertService} class
|
||||
*/
|
||||
public class SystemWideAlertServiceImpl implements SystemWideAlertService {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SystemWideAlertService.class);
|
||||
|
||||
|
||||
@Autowired
|
||||
private SystemWideAlertDAO systemWideAlertDAO;
|
||||
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
@Override
|
||||
public SystemWideAlert create(final Context context, final String message,
|
||||
final AllowSessionsEnum allowSessionsType,
|
||||
final Date countdownTo, final boolean active) throws SQLException,
|
||||
AuthorizeException {
|
||||
if (!authorizeService.isAdmin(context)) {
|
||||
throw new AuthorizeException(
|
||||
"Only administrators can create a system-wide alert");
|
||||
}
|
||||
SystemWideAlert systemWideAlert = new SystemWideAlert();
|
||||
systemWideAlert.setMessage(message);
|
||||
systemWideAlert.setAllowSessions(allowSessionsType);
|
||||
systemWideAlert.setCountdownTo(countdownTo);
|
||||
systemWideAlert.setActive(active);
|
||||
|
||||
SystemWideAlert createdAlert = systemWideAlertDAO.create(context, systemWideAlert);
|
||||
log.info(LogHelper.getHeader(context, "system_wide_alert_create",
|
||||
"System Wide Alert has been created with message: '" + message + "' and ID "
|
||||
+ createdAlert.getID() + " and allowSessionsType " + allowSessionsType +
|
||||
" and active set to " + active));
|
||||
|
||||
|
||||
return createdAlert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemWideAlert find(final Context context, final int alertId) throws SQLException {
|
||||
return systemWideAlertDAO.findByID(context, SystemWideAlert.class, alertId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemWideAlert> findAll(final Context context) throws SQLException {
|
||||
return systemWideAlertDAO.findAll(context, SystemWideAlert.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemWideAlert> findAll(final Context context, final int limit, final int offset) throws SQLException {
|
||||
return systemWideAlertDAO.findAll(context, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemWideAlert> findAllActive(final Context context, final int limit, final int offset)
|
||||
throws SQLException {
|
||||
return systemWideAlertDAO.findAllActive(context, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final Context context, final SystemWideAlert systemWideAlert)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
if (!authorizeService.isAdmin(context)) {
|
||||
throw new AuthorizeException(
|
||||
"Only administrators can create a system-wide alert");
|
||||
}
|
||||
systemWideAlertDAO.delete(context, systemWideAlert);
|
||||
log.info(LogHelper.getHeader(context, "system_wide_alert_create",
|
||||
"System Wide Alert with ID " + systemWideAlert.getID() + " has been deleted"));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final Context context, final SystemWideAlert systemWideAlert)
|
||||
throws SQLException, AuthorizeException {
|
||||
if (!authorizeService.isAdmin(context)) {
|
||||
throw new AuthorizeException(
|
||||
"Only administrators can create a system-wide alert");
|
||||
}
|
||||
systemWideAlertDAO.save(context, systemWideAlert);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNonAdminUserLogin(Context context) throws SQLException {
|
||||
List<SystemWideAlert> active = findAllActive(context, 1, 0);
|
||||
if (active == null || active.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return active.get(0).getAllowSessions() == AllowSessionsEnum.ALLOW_ALL_SESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUserMaintainSession(Context context, EPerson ePerson) throws SQLException {
|
||||
if (authorizeService.isAdmin(context, ePerson)) {
|
||||
return true;
|
||||
}
|
||||
List<SystemWideAlert> active = findAllActive(context, 1, 0);
|
||||
if (active == null || active.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return active.get(0).getAllowSessions() != AllowSessionsEnum.ALLOW_ADMIN_SESSIONS_ONLY;
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.alerts.dao;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.alerts.SystemWideAlert;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.GenericDAO;
|
||||
|
||||
/**
|
||||
* This is the Data Access Object for the {@link SystemWideAlert} object
|
||||
*/
|
||||
public interface SystemWideAlertDAO extends GenericDAO<SystemWideAlert> {
|
||||
|
||||
/**
|
||||
* Returns a list of all SystemWideAlert objects in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param limit The limit for the amount of SystemWideAlerts returned
|
||||
* @param offset The offset for the Processes to be returned
|
||||
* @return The list of all SystemWideAlert objects in the Database
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<SystemWideAlert> findAll(Context context, int limit, int offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns a list of all active SystemWideAlert objects in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param limit The limit for the amount of SystemWideAlerts returned
|
||||
* @param offset The offset for the Processes to be returned
|
||||
* @return The list of all SystemWideAlert objects in the Database
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<SystemWideAlert> findAllActive(Context context, int limit, int offset) throws SQLException;
|
||||
|
||||
|
||||
}
|
@@ -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.alerts.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.dspace.alerts.SystemWideAlert;
|
||||
import org.dspace.alerts.SystemWideAlert_;
|
||||
import org.dspace.alerts.dao.SystemWideAlertDAO;
|
||||
import org.dspace.core.AbstractHibernateDAO;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* Implementation class for the {@link SystemWideAlertDAO}
|
||||
*/
|
||||
public class SystemWideAlertDAOImpl extends AbstractHibernateDAO<SystemWideAlert> implements SystemWideAlertDAO {
|
||||
|
||||
public List<SystemWideAlert> findAll(final Context context, final int limit, final int offset) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, SystemWideAlert.class);
|
||||
Root<SystemWideAlert> alertRoot = criteriaQuery.from(SystemWideAlert.class);
|
||||
criteriaQuery.select(alertRoot);
|
||||
|
||||
return list(context, criteriaQuery, false, SystemWideAlert.class, limit, offset);
|
||||
}
|
||||
|
||||
public List<SystemWideAlert> findAllActive(final Context context, final int limit, final int offset)
|
||||
throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, SystemWideAlert.class);
|
||||
Root<SystemWideAlert> alertRoot = criteriaQuery.from(SystemWideAlert.class);
|
||||
criteriaQuery.select(alertRoot);
|
||||
criteriaQuery.where(criteriaBuilder.equal(alertRoot.get(SystemWideAlert_.active), true));
|
||||
|
||||
return list(context, criteriaQuery, false, SystemWideAlert.class, limit, offset);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* 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.alerts.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.alerts.AllowSessionsEnum;
|
||||
import org.dspace.alerts.SystemWideAlert;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
|
||||
/**
|
||||
* An interface for the SystemWideAlertService with methods regarding the SystemWideAlert workload
|
||||
*/
|
||||
public interface SystemWideAlertService {
|
||||
|
||||
/**
|
||||
* This method will create a SystemWideAlert object in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param message The message of the system-wide alert
|
||||
* @param allowSessionsType Which sessions need to be allowed for the system-wide alert
|
||||
* @param countdownTo The date to which to count down to when the system-wide alert is active
|
||||
* @param active Whether the system-wide alert os active
|
||||
* @return The created SystemWideAlert object
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
SystemWideAlert create(Context context, String message, AllowSessionsEnum allowSessionsType,
|
||||
Date countdownTo, boolean active
|
||||
) throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* This method will retrieve a SystemWideAlert object from the Database with the given ID
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param alertId The alert id on which we'll search for in the database
|
||||
* @return The system-wide alert that holds the given alert id
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
SystemWideAlert find(Context context, int alertId) throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns a list of all SystemWideAlert objects in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @return The list of all SystemWideAlert objects in the Database
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<SystemWideAlert> findAll(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns a list of all SystemWideAlert objects in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param limit The limit for the amount of system-wide alerts returned
|
||||
* @param offset The offset for the system-wide alerts to be returned
|
||||
* @return The list of all SystemWideAlert objects in the Database
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<SystemWideAlert> findAll(Context context, int limit, int offset) throws SQLException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of all active SystemWideAlert objects in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @return The list of all active SystemWideAlert objects in the database
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<SystemWideAlert> findAllActive(Context context, int limit, int offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* This method will delete the given SystemWideAlert object from the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param systemWideAlert The SystemWideAlert object to be deleted
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
void delete(Context context, SystemWideAlert systemWideAlert)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
|
||||
/**
|
||||
* This method will be used to update the given SystemWideAlert object in the database
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @param systemWideAlert The SystemWideAlert object to be updated
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
void update(Context context, SystemWideAlert systemWideAlert) throws SQLException, AuthorizeException;
|
||||
|
||||
|
||||
/**
|
||||
* Verifies if the user connected to the current context can retain its session
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @return if the user connected to the current context can retain its session
|
||||
*/
|
||||
boolean canUserMaintainSession(Context context, EPerson ePerson) throws SQLException;
|
||||
|
||||
|
||||
/**
|
||||
* Verifies if a non admin user can log in
|
||||
*
|
||||
* @param context The relevant DSpace context
|
||||
* @return if a non admin user can log in
|
||||
*/
|
||||
boolean canNonAdminUserLogin(Context context) throws SQLException;
|
||||
}
|
@@ -736,7 +736,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
|
||||
collection.getID(), collection.getHandle(), getIdentifiers(context, collection)));
|
||||
|
||||
// remove subscriptions - hmm, should this be in Subscription.java?
|
||||
subscribeService.deleteByCollection(context, collection);
|
||||
subscribeService.deleteByDspaceObject(context, collection);
|
||||
|
||||
// Remove Template Item
|
||||
removeTemplateItem(context, collection);
|
||||
|
@@ -36,6 +36,7 @@ import org.dspace.core.I18nUtil;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.service.IdentifierService;
|
||||
@@ -73,7 +74,8 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
|
||||
protected SiteService siteService;
|
||||
@Autowired(required = true)
|
||||
protected IdentifierService identifierService;
|
||||
|
||||
@Autowired(required = true)
|
||||
protected SubscribeService subscribeService;
|
||||
protected CommunityServiceImpl() {
|
||||
super();
|
||||
|
||||
@@ -217,12 +219,12 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
|
||||
|
||||
@Override
|
||||
public Bitstream setLogo(Context context, Community community, InputStream is)
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
// Check authorisation
|
||||
// authorized to remove the logo when DELETE rights
|
||||
// authorized when canEdit
|
||||
if (!((is == null) && authorizeService.authorizeActionBoolean(
|
||||
context, community, Constants.DELETE))) {
|
||||
context, community, Constants.DELETE))) {
|
||||
canEdit(context, community);
|
||||
}
|
||||
|
||||
@@ -242,7 +244,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
|
||||
// now create policy for logo bitstream
|
||||
// to match our READ policy
|
||||
List<ResourcePolicy> policies = authorizeService
|
||||
.getPoliciesActionFilter(context, community, Constants.READ);
|
||||
.getPoliciesActionFilter(context, community, Constants.READ);
|
||||
authorizeService.addPolicies(context, policies, newLogo);
|
||||
|
||||
log.info(LogHelper.getHeader(context, "set_logo",
|
||||
@@ -549,6 +551,8 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
|
||||
context.addEvent(new Event(Event.DELETE, Constants.COMMUNITY, community.getID(), community.getHandle(),
|
||||
getIdentifiers(context, community)));
|
||||
|
||||
subscribeService.deleteByDspaceObject(context, community);
|
||||
|
||||
// Remove collections
|
||||
Iterator<Collection> collections = community.getCollections().iterator();
|
||||
|
||||
|
@@ -10,9 +10,14 @@ package org.dspace.content;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.FilterUtils;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.InstallItemService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
@@ -20,6 +25,7 @@ import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.embargo.service.EmbargoService;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.identifier.Identifier;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.service.IdentifierService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -42,9 +48,11 @@ public class InstallItemServiceImpl implements InstallItemService {
|
||||
protected IdentifierService identifierService;
|
||||
@Autowired(required = true)
|
||||
protected ItemService itemService;
|
||||
@Autowired(required = false)
|
||||
|
||||
Logger log = LogManager.getLogger(InstallItemServiceImpl.class);
|
||||
|
||||
protected InstallItemServiceImpl() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,10 +67,14 @@ public class InstallItemServiceImpl implements InstallItemService {
|
||||
AuthorizeException {
|
||||
Item item = is.getItem();
|
||||
Collection collection = is.getCollection();
|
||||
// Get map of filters to use for identifier types.
|
||||
Map<Class<? extends Identifier>, Filter> filters = FilterUtils.getIdentifierFilters(false);
|
||||
try {
|
||||
if (suppliedHandle == null) {
|
||||
identifierService.register(c, item);
|
||||
// Register with the filters we've set up
|
||||
identifierService.register(c, item, filters);
|
||||
} else {
|
||||
// This will register the handle but a pending DOI won't be compatible and so won't be registered
|
||||
identifierService.register(c, item, suppliedHandle);
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
|
@@ -61,6 +61,7 @@ import org.dspace.discovery.indexobject.IndexableItem;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.harvest.HarvestedItem;
|
||||
import org.dspace.harvest.service.HarvestedItemService;
|
||||
@@ -163,6 +164,9 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
@Autowired(required = true)
|
||||
private RequestItemService requestItemService;
|
||||
|
||||
@Autowired(required = true)
|
||||
protected SubscribeService subscribeService;
|
||||
|
||||
protected ItemServiceImpl() {
|
||||
super();
|
||||
}
|
||||
@@ -769,7 +773,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
|
||||
|
||||
log.info(LogHelper.getHeader(context, "delete_item", "item_id="
|
||||
+ item.getID()));
|
||||
|
||||
//remove subscription related with it
|
||||
subscribeService.deleteByDspaceObject(context, item);
|
||||
// Remove relationships
|
||||
for (Relationship relationship : relationshipService.findByItem(context, item, -1, -1, false, false)) {
|
||||
relationshipService.forceDelete(context, relationship, false, false);
|
||||
|
@@ -24,6 +24,8 @@ import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.dao.WorkspaceItemDAO;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.FilterUtils;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
@@ -32,6 +34,13 @@ import org.dspace.core.Context;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.identifier.DOI;
|
||||
import org.dspace.identifier.DOIIdentifierProvider;
|
||||
import org.dspace.identifier.Identifier;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.factory.IdentifierServiceFactory;
|
||||
import org.dspace.identifier.service.DOIService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.workflow.WorkflowItem;
|
||||
import org.dspace.workflow.WorkflowService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -58,6 +67,8 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
|
||||
protected ItemService itemService;
|
||||
@Autowired(required = true)
|
||||
protected WorkflowService workflowService;
|
||||
@Autowired(required = true)
|
||||
protected DOIService doiService;
|
||||
|
||||
|
||||
protected WorkspaceItemServiceImpl() {
|
||||
@@ -160,6 +171,26 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
|
||||
}
|
||||
|
||||
itemService.update(context, item);
|
||||
|
||||
// If configured, register identifiers (eg handle, DOI) now. This is typically used with the Show Identifiers
|
||||
// submission step which previews minted handles and DOIs during the submission process. Default: false
|
||||
if (DSpaceServicesFactory.getInstance().getConfigurationService()
|
||||
.getBooleanProperty("identifiers.submission.register", false)) {
|
||||
try {
|
||||
// Get map of filters to use for identifier types, while the item is in progress
|
||||
Map<Class<? extends Identifier>, Filter> filters = FilterUtils.getIdentifierFilters(true);
|
||||
IdentifierServiceFactory.getInstance().getIdentifierService().register(context, item, filters);
|
||||
// Look for a DOI and move it to PENDING
|
||||
DOI doi = doiService.findDOIByDSpaceObject(context, item);
|
||||
if (doi != null) {
|
||||
doi.setStatus(DOIIdentifierProvider.PENDING);
|
||||
doiService.update(context, doi);
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
log.error("Could not register identifier(s) for item {}: {}", item.getID(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
workspaceItem.setItem(item);
|
||||
|
||||
log.info(LogHelper.getHeader(context, "create_workspace_item",
|
||||
|
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.content.crosswalk;
|
||||
|
||||
import static org.dspace.content.Item.ANY;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.handle.factory.HandleServiceFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Creates a String to be sent as email body for subscriptions
|
||||
*
|
||||
* @author Alba Aliu
|
||||
*/
|
||||
public class SubscriptionDsoMetadataForEmailCompose implements StreamDisseminationCrosswalk {
|
||||
|
||||
private List<String> metadata = new ArrayList<>();
|
||||
|
||||
@Autowired
|
||||
private ItemService itemService;
|
||||
|
||||
@Override
|
||||
public boolean canDisseminate(Context context, DSpaceObject dso) {
|
||||
return Objects.nonNull(dso) && dso.getType() == Constants.ITEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disseminate(Context context, DSpaceObject dso, OutputStream out) throws SQLException {
|
||||
if (dso.getType() == Constants.ITEM) {
|
||||
Item item = (Item) dso;
|
||||
PrintStream printStream = new PrintStream(out);
|
||||
for (String actualMetadata : metadata) {
|
||||
String[] splitted = actualMetadata.split("\\.");
|
||||
String qualifier = null;
|
||||
if (splitted.length == 1) {
|
||||
qualifier = splitted[2];
|
||||
}
|
||||
var metadataValue = itemService.getMetadataFirstValue(item, splitted[0], splitted[1], qualifier, ANY);
|
||||
printStream.print(metadataValue + " ");
|
||||
}
|
||||
String itemURL = HandleServiceFactory.getInstance()
|
||||
.getHandleService()
|
||||
.resolveToURL(context, item.getHandle());
|
||||
printStream.print(itemURL);
|
||||
printStream.print("\n");
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMIMEType() {
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
public List<String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(List<String> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
}
|
@@ -33,6 +33,7 @@ import org.dspace.content.service.RelationshipTypeService;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.content.service.SupervisedItemService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.workflow.factory.WorkflowServiceFactory;
|
||||
|
||||
@@ -75,6 +76,8 @@ public abstract class ContentServiceFactory {
|
||||
|
||||
public abstract SiteService getSiteService();
|
||||
|
||||
public abstract SubscribeService getSubscribeService();
|
||||
|
||||
/**
|
||||
* Return the implementation of the RelationshipTypeService interface
|
||||
*
|
||||
@@ -114,11 +117,7 @@ public abstract class ContentServiceFactory {
|
||||
}
|
||||
|
||||
public <T extends DSpaceObject> DSpaceObjectService<T> getDSpaceObjectService(T dso) {
|
||||
// No need to worry when supressing, as long as our "getDSpaceObjectManager" method is properly implemented
|
||||
// no casting issues should occur
|
||||
@SuppressWarnings("unchecked")
|
||||
DSpaceObjectService<T> manager = getDSpaceObjectService(dso.getType());
|
||||
return manager;
|
||||
return getDSpaceObjectService(dso.getType());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@@ -30,6 +30,7 @@ import org.dspace.content.service.RelationshipTypeService;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.content.service.SupervisedItemService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
@@ -71,7 +72,8 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory {
|
||||
private SupervisedItemService supervisedItemService;
|
||||
@Autowired(required = true)
|
||||
private SiteService siteService;
|
||||
|
||||
@Autowired(required = true)
|
||||
private SubscribeService subscribeService;
|
||||
@Autowired(required = true)
|
||||
private RelationshipService relationshipService;
|
||||
@Autowired(required = true)
|
||||
@@ -158,6 +160,11 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory {
|
||||
return siteService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscribeService getSubscribeService() {
|
||||
return subscribeService ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelationshipTypeService getRelationshipTypeService() {
|
||||
return relationshipTypeService;
|
||||
|
@@ -18,10 +18,10 @@ import org.dspace.core.Context;
|
||||
* statement as a property (unlike an operator) and takes no parameters (unlike a condition)
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class DefaultFilter implements Filter {
|
||||
private LogicalStatement statement;
|
||||
private String name;
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
|
||||
/**
|
||||
@@ -44,4 +44,15 @@ public class DefaultFilter implements Filter {
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return this.statement.getResult(context, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
log.debug("Initialize bean " + name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ package org.dspace.content.logic;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* The interface for Filter currently doesn't add anything to LogicalStatement but inherits from it
|
||||
@@ -22,7 +23,7 @@ import org.dspace.core.Context;
|
||||
* @author Kim Shepherd
|
||||
* @see org.dspace.content.logic.DefaultFilter
|
||||
*/
|
||||
public interface Filter extends LogicalStatement {
|
||||
public interface Filter extends LogicalStatement, BeanNameAware {
|
||||
/**
|
||||
* Get the result of logical evaluation for an item
|
||||
* @param context DSpace context
|
||||
@@ -32,4 +33,11 @@ public interface Filter extends LogicalStatement {
|
||||
*/
|
||||
@Override
|
||||
boolean getResult(Context context, Item item) throws LogicalStatementException;
|
||||
|
||||
/**
|
||||
* Get the name of a filter. This can be used by filters which make use of BeanNameAware
|
||||
* to return the bean name.
|
||||
* @return the id/name of this spring bean
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
|
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.content.logic;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.identifier.DOI;
|
||||
import org.dspace.identifier.Handle;
|
||||
import org.dspace.identifier.Identifier;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* General utility methods for logical item filtering
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class FilterUtils {
|
||||
|
||||
@Autowired(required = true)
|
||||
ConfigurationService configurationService;
|
||||
|
||||
/**
|
||||
* Get a Filter by configuration property name
|
||||
* For example, if a module has implemented "my-feature.filter" configuration property
|
||||
* this method will return a filter with the ID specified by the configuration property
|
||||
* @param property DSpace configuration property name (Apache Commons config)
|
||||
* @return Filter object, with a bean ID configured for this property key, or null
|
||||
*/
|
||||
public static Filter getFilterFromConfiguration(String property) {
|
||||
String filterName = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(property);
|
||||
if (filterName != null) {
|
||||
return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(filterName, Filter.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Filter by configuration property name
|
||||
* For example, if a module has implemented "my-feature.filter" configuration property
|
||||
* this method will return a filter with the ID specified by the configuration property
|
||||
* @param property DSpace configuration property name (Apache Commons config)
|
||||
* @return Filter object, with a bean ID configured for this property key, or default filter
|
||||
*/
|
||||
public static Filter getFilterFromConfiguration(String property, Filter defaultFilter) {
|
||||
Filter filter = getFilterFromConfiguration(property);
|
||||
if (filter != null) {
|
||||
return filter;
|
||||
}
|
||||
return defaultFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of identifier types and filters to use when creating workspace or archived items
|
||||
* This is used by services installing new archived or workspace items to filter by identifier type
|
||||
* as some filters should apply to DOI creation but not Handle creation, and so on.
|
||||
* The in progress or archived status will be used to load the appropriate filter from configuration
|
||||
* <p>
|
||||
* @param inProgress
|
||||
* @return
|
||||
*/
|
||||
public static Map<Class<? extends Identifier>, Filter> getIdentifierFilters(boolean inProgress) {
|
||||
String configurationSuffix = "install";
|
||||
if (inProgress) {
|
||||
configurationSuffix = "workspace";
|
||||
}
|
||||
Map<Class<? extends Identifier>, Filter> filters = new HashMap<>();
|
||||
// Put DOI 'can we create DOI on install / workspace?' filter
|
||||
Filter filter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter." + configurationSuffix);
|
||||
// A null filter should be handled safely by the identifier provier (default, or "always true")
|
||||
filters.put(DOI.class, filter);
|
||||
// This won't have an affect until handle providers implement filtering, but is an example of
|
||||
// how the filters can be used for other types
|
||||
filters.put(Handle.class, DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(
|
||||
"always_true_filter", TrueFilter.class));
|
||||
return filters;
|
||||
}
|
||||
}
|
@@ -17,7 +17,6 @@ import org.dspace.core.Context;
|
||||
* used as sub-statements in other Filters and Operators.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface LogicalStatement {
|
||||
/**
|
||||
|
@@ -12,7 +12,6 @@ package org.dspace.content.logic;
|
||||
* defined as spring beans.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class LogicalStatementException extends RuntimeException {
|
||||
|
||||
|
@@ -33,7 +33,6 @@ import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
* A command-line runner used for testing a logical filter against an item, or all items
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class TestLogicRunner {
|
||||
|
||||
|
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.content.logic;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* Extremely simple filter that always returns true!
|
||||
* Useful to pass to methods that expect a filter, in order to effectively say "all items".
|
||||
* This could be configured in Spring XML but it is more stable and reliable to have it hard-coded here
|
||||
* so that any broken configuration doesn't silently break parts of DSpace that expect it to work.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class TrueFilter implements Filter {
|
||||
private String name;
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
log.debug("Initialize bean " + name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@@ -23,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
* Abstract class for conditions, to implement the basic getter and setter parameters
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class AbstractCondition implements Condition {
|
||||
|
||||
|
@@ -18,7 +18,6 @@ import org.dspace.core.Context;
|
||||
* A condition to evaluate an item based on how many bitstreams it has in a particular bundle
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class BitstreamCountCondition extends AbstractCondition {
|
||||
/**
|
||||
|
@@ -22,7 +22,6 @@ import org.dspace.core.Context;
|
||||
* operator is not a condition but also a logical statement.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Condition extends LogicalStatement {
|
||||
|
||||
|
@@ -23,7 +23,6 @@ import org.dspace.core.Context;
|
||||
* if the item belongs to any of them.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class InCollectionCondition extends AbstractCondition {
|
||||
private static Logger log = LogManager.getLogger(InCollectionCondition.class);
|
||||
|
@@ -24,7 +24,6 @@ import org.dspace.core.Context;
|
||||
* if the item belongs to any of them.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class InCommunityCondition extends AbstractCondition {
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
|
@@ -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.content.logic.condition;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that returns true if the item is archived
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class IsArchivedCondition extends AbstractCondition {
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
|
||||
/**
|
||||
* Return true if item is archived
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
log.debug("Result of isArchived is " + item.isArchived());
|
||||
return item.isArchived();
|
||||
}
|
||||
}
|
@@ -17,7 +17,6 @@ import org.dspace.core.Context;
|
||||
* A condition that returns true if the item is withdrawn
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class IsWithdrawnCondition extends AbstractCondition {
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
|
@@ -23,7 +23,6 @@ import org.dspace.core.Context;
|
||||
* in a given metadata field
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class MetadataValueMatchCondition extends AbstractCondition {
|
||||
|
||||
|
@@ -23,7 +23,6 @@ import org.dspace.core.Context;
|
||||
* in a given metadata field
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class MetadataValuesMatchCondition extends AbstractCondition {
|
||||
|
||||
|
@@ -25,7 +25,6 @@ import org.dspace.core.Context;
|
||||
* can perform the action on a given item
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class ReadableByGroupCondition extends AbstractCondition {
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
|
@@ -22,7 +22,6 @@ import org.dspace.core.Context;
|
||||
* as a logical result
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class AbstractOperator implements LogicalStatement {
|
||||
|
||||
|
@@ -19,7 +19,6 @@ import org.dspace.core.Context;
|
||||
* true if all sub-statements return true
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class And extends AbstractOperator {
|
||||
|
||||
|
@@ -18,7 +18,6 @@ import org.dspace.core.Context;
|
||||
* An operator that implements NAND by negating an AND operation
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Nand extends AbstractOperator {
|
||||
|
||||
|
@@ -19,7 +19,6 @@ import org.dspace.core.Context;
|
||||
* Not can have one sub-statement only, while and, or, nor, ... can have multiple sub-statements.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Not implements LogicalStatement {
|
||||
|
||||
|
@@ -19,7 +19,6 @@ import org.dspace.core.Context;
|
||||
* true if one or more sub-statements return true
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Or extends AbstractOperator {
|
||||
|
||||
|
@@ -13,11 +13,15 @@ import java.sql.SQLException;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.FilterUtils;
|
||||
import org.dspace.content.logic.TrueFilter;
|
||||
import org.dspace.curate.AbstractCurationTask;
|
||||
import org.dspace.curate.Curator;
|
||||
import org.dspace.identifier.DOIIdentifierProvider;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.doi.DOIIdentifierNotApplicableException;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
@@ -39,6 +43,7 @@ public class RegisterDOI extends AbstractCurationTask {
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(RegisterDOI.class);
|
||||
// DOI provider
|
||||
private DOIIdentifierProvider provider;
|
||||
private Filter trueFilter;
|
||||
|
||||
/**
|
||||
* Initialise the curation task and read configuration, instantiate the DOI provider
|
||||
@@ -46,14 +51,14 @@ public class RegisterDOI extends AbstractCurationTask {
|
||||
@Override
|
||||
public void init(Curator curator, String taskId) throws IOException {
|
||||
super.init(curator, taskId);
|
||||
// Get 'skip filter' behaviour from configuration, with a default value of 'true'
|
||||
skipFilter = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".skip-filter", true);
|
||||
// Get distribution behaviour from configuration, with a default value of 'false'
|
||||
distributed = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".distributed", false);
|
||||
log.debug("PLUGIN_PREFIX = " + PLUGIN_PREFIX + ", skipFilter = " + skipFilter +
|
||||
", distributed = " + distributed);
|
||||
// Instantiate DOI provider singleton
|
||||
provider = new DSpace().getSingletonService(DOIIdentifierProvider.class);
|
||||
trueFilter = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(
|
||||
"always_true_filter", TrueFilter.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +123,9 @@ public class RegisterDOI extends AbstractCurationTask {
|
||||
String doi = null;
|
||||
// Attempt DOI registration and report successes and failures
|
||||
try {
|
||||
log.debug("Registering DOI with skipFilter = " + skipFilter);
|
||||
doi = provider.register(Curator.curationContext(), item, skipFilter);
|
||||
Filter filter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter.curation",
|
||||
trueFilter);
|
||||
doi = provider.register(Curator.curationContext(), item, filter);
|
||||
if (doi != null) {
|
||||
String message = "New DOI minted in database for item " + item.getHandle() + ": " + doi
|
||||
+ ". This DOI will be registered online with the DOI provider when the queue is next run";
|
||||
|
@@ -139,4 +139,23 @@ public class DiscoveryConfigurationService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of all DiscoveryConfiguration objects where key starts with prefixConfigurationName
|
||||
*
|
||||
* @param prefixConfigurationName string as prefix key
|
||||
*/
|
||||
public List<DiscoveryConfiguration> getDiscoveryConfigurationWithPrefixName(final String prefixConfigurationName) {
|
||||
List<DiscoveryConfiguration> discoveryConfigurationList = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(prefixConfigurationName)) {
|
||||
for (String key : map.keySet()) {
|
||||
if (key.equals(prefixConfigurationName) || key.startsWith(prefixConfigurationName)) {
|
||||
DiscoveryConfiguration config = map.get(key);
|
||||
discoveryConfigurationList.add(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
return discoveryConfigurationList;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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.discovery.configuration;
|
||||
|
||||
/**
|
||||
* This class extends {@link DiscoveryConfiguration} and add method for set parameters
|
||||
* to filter query list
|
||||
*
|
||||
* @author Danilo Di Nuzzo (danilo.dinuzzo at 4science.it)
|
||||
*/
|
||||
public class DiscoveryRelatedItemConfiguration extends DiscoveryConfiguration {}
|
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.discovery.configuration;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
*
|
||||
* Extension of {@link DiscoverySortFieldConfiguration} used to configure sorting
|
||||
* taking advantage of solr function feature.
|
||||
*
|
||||
* Order is evaluated by mean of function parameter value and passed in arguments as input.
|
||||
*
|
||||
* @author Corrado Lombardi (corrado.lombardi at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class DiscoverySortFunctionConfiguration extends DiscoverySortFieldConfiguration {
|
||||
|
||||
public static final String SORT_FUNCTION = "sort_function";
|
||||
private String function;
|
||||
private List<String> arguments;
|
||||
private String id;
|
||||
|
||||
public void setFunction(final String function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
public void setArguments(final List<String> arguments) {
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return SORT_FUNCTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMetadataField() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function to be used by solr to sort result
|
||||
* @param functionArgs variable arguments to be inserted in function
|
||||
* @return
|
||||
*/
|
||||
public String getFunction(final Serializable... functionArgs) {
|
||||
final String args = String.join(",", Optional.ofNullable(arguments).orElse(Collections.emptyList()));
|
||||
final String result = function + "(" + args + ")";
|
||||
return MessageFormat.format(result, functionArgs);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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.eperson;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
|
||||
/**
|
||||
* This enum holds all the possible frequency types
|
||||
* that can be used in "subscription-send" script
|
||||
*
|
||||
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||
*/
|
||||
public enum FrequencyType {
|
||||
DAY("D"),
|
||||
WEEK("W"),
|
||||
MONTH("M");
|
||||
|
||||
private String shortName;
|
||||
|
||||
private FrequencyType(String shortName) {
|
||||
this.shortName = shortName;
|
||||
}
|
||||
|
||||
public static String findLastFrequency(String frequency) {
|
||||
String startDate = "";
|
||||
String endDate = "";
|
||||
Calendar cal = Calendar.getInstance();
|
||||
// Full ISO 8601 is e.g.
|
||||
SimpleDateFormat fullIsoStart = new SimpleDateFormat("yyyy-MM-dd'T'00:00:00'Z'");
|
||||
SimpleDateFormat fullIsoEnd = new SimpleDateFormat("yyyy-MM-dd'T'23:59:59'Z'");
|
||||
switch (frequency) {
|
||||
case "D":
|
||||
cal.add(Calendar.DAY_OF_MONTH, -1);
|
||||
endDate = fullIsoEnd.format(cal.getTime());
|
||||
startDate = fullIsoStart.format(cal.getTime());
|
||||
break;
|
||||
case "M":
|
||||
int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
|
||||
cal.add(Calendar.DAY_OF_MONTH, -dayOfMonth);
|
||||
endDate = fullIsoEnd.format(cal.getTime());
|
||||
cal.add(Calendar.MONTH, -1);
|
||||
cal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
startDate = fullIsoStart.format(cal.getTime());
|
||||
break;
|
||||
case "W":
|
||||
cal.add(Calendar.DAY_OF_WEEK, -1);
|
||||
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
cal.add(Calendar.DAY_OF_WEEK, -dayOfWeek);
|
||||
endDate = fullIsoEnd.format(cal.getTime());
|
||||
cal.add(Calendar.DAY_OF_WEEK, -6);
|
||||
startDate = fullIsoStart.format(cal.getTime());
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return "[" + startDate + " TO " + endDate + "]";
|
||||
}
|
||||
|
||||
public static boolean isSupportedFrequencyType(String value) {
|
||||
for (FrequencyType ft : Arrays.asList(FrequencyType.values())) {
|
||||
if (StringUtils.equals(ft.getShortName(), value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
}
|
@@ -1,432 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.eperson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.TimeZone;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.Email;
|
||||
import org.dspace.core.I18nUtil;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.dspace.handle.factory.HandleServiceFactory;
|
||||
import org.dspace.handle.service.HandleService;
|
||||
import org.dspace.search.Harvest;
|
||||
import org.dspace.search.HarvestedItemInfo;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
/**
|
||||
* CLI tool used for sending new item e-mail alerts to users
|
||||
*
|
||||
* @author Robert Tansley
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class SubscribeCLITool {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SubscribeCLITool.class);
|
||||
|
||||
private static final HandleService handleService
|
||||
= HandleServiceFactory.getInstance().getHandleService();
|
||||
private static final ItemService itemService
|
||||
= ContentServiceFactory.getInstance().getItemService();
|
||||
private static final SubscribeService subscribeService
|
||||
= EPersonServiceFactory.getInstance().getSubscribeService();
|
||||
private static final ConfigurationService configurationService
|
||||
= DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private SubscribeCLITool() { }
|
||||
|
||||
/**
|
||||
* Process subscriptions. This must be invoked only once a day. Messages are
|
||||
* only sent out when a collection has actually received new items, so that
|
||||
* people's mailboxes are not clogged with many "no new items" mails.
|
||||
* <p>
|
||||
* Yesterday's newly available items are included. If this is run at for
|
||||
* example midday, any items that have been made available during the
|
||||
* current day will not be included, but will be included in the next day's
|
||||
* run.
|
||||
* <p>
|
||||
* For example, if today's date is 2002-10-10 (in UTC) items made available
|
||||
* during 2002-10-09 (UTC) will be included.
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param test If true, do a "dry run", i.e. don't actually send email, just log the attempt
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
|
||||
*/
|
||||
public static void processDaily(Context context, boolean test) throws SQLException,
|
||||
IOException {
|
||||
// Grab the subscriptions
|
||||
|
||||
List<Subscription> subscriptions = subscribeService.findAll(context);
|
||||
|
||||
EPerson currentEPerson = null;
|
||||
List<Collection> collections = null; // List of Collections
|
||||
|
||||
// Go through the list collating subscriptions for each e-person
|
||||
for (Subscription subscription : subscriptions) {
|
||||
// Does this row relate to the same e-person as the last?
|
||||
if ((currentEPerson == null)
|
||||
|| (!subscription.getePerson().getID().equals(currentEPerson
|
||||
.getID()))) {
|
||||
// New e-person. Send mail for previous e-person
|
||||
if (currentEPerson != null) {
|
||||
|
||||
try {
|
||||
sendEmail(context, currentEPerson, collections, test);
|
||||
} catch (MessagingException me) {
|
||||
log.error("Failed to send subscription to eperson_id="
|
||||
+ currentEPerson.getID());
|
||||
log.error(me);
|
||||
}
|
||||
}
|
||||
|
||||
currentEPerson = subscription.getePerson();
|
||||
collections = new ArrayList<>();
|
||||
}
|
||||
|
||||
collections.add(subscription.getCollection());
|
||||
}
|
||||
|
||||
// Process the last person
|
||||
if (currentEPerson != null) {
|
||||
try {
|
||||
sendEmail(context, currentEPerson, collections, test);
|
||||
} catch (MessagingException me) {
|
||||
log.error("Failed to send subscription to eperson_id="
|
||||
+ currentEPerson.getID());
|
||||
log.error(me);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email to the given e-person with details of new items in the
|
||||
* given collections, items that appeared yesterday. No e-mail is sent if
|
||||
* there aren't any new items in any of the collections.
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param eperson eperson to send to
|
||||
* @param collections List of collection IDs (Integers)
|
||||
* @param test If true, do a "dry run", i.e. don't actually send email, just log the attempt
|
||||
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
|
||||
* @throws MessagingException A general class of exceptions for sending email.
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public static void sendEmail(Context context, EPerson eperson,
|
||||
List<Collection> collections, boolean test) throws IOException, MessagingException,
|
||||
SQLException {
|
||||
// Get a resource bundle according to the eperson language preferences
|
||||
Locale supportedLocale = I18nUtil.getEPersonLocale(eperson);
|
||||
ResourceBundle labels = ResourceBundle.getBundle("Messages", supportedLocale);
|
||||
|
||||
// Get the start and end dates for yesterday
|
||||
|
||||
// The date should reflect the timezone as well. Otherwise we stand to lose that information
|
||||
// in truncation and roll to an earlier date than intended.
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
|
||||
cal.setTime(new Date());
|
||||
|
||||
// What we actually want to pass to Harvest is "Midnight of yesterday in my current timezone"
|
||||
// Truncation will actually pass in "Midnight of yesterday in UTC", which will be,
|
||||
// at least in CDT, "7pm, the day before yesterday, in my current timezone".
|
||||
cal.add(Calendar.HOUR, -24);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
Date midnightYesterday = cal.getTime();
|
||||
|
||||
|
||||
// FIXME: text of email should be more configurable from an
|
||||
// i18n viewpoint
|
||||
StringBuilder emailText = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
|
||||
for (int i = 0; i < collections.size(); i++) {
|
||||
Collection c = collections.get(i);
|
||||
|
||||
try {
|
||||
boolean includeAll = configurationService
|
||||
.getBooleanProperty("harvest.includerestricted.subscription", true);
|
||||
|
||||
// we harvest all the changed item from yesterday until now
|
||||
List<HarvestedItemInfo> itemInfos = Harvest
|
||||
.harvest(context, c, new DCDate(midnightYesterday).toString(), null, 0, // Limit
|
||||
// and
|
||||
// offset
|
||||
// zero,
|
||||
// get
|
||||
// everything
|
||||
0, true, // Need item objects
|
||||
false, // But not containers
|
||||
false, // Or withdrawals
|
||||
includeAll);
|
||||
|
||||
if (configurationService.getBooleanProperty("eperson.subscription.onlynew", false)) {
|
||||
// get only the items archived yesterday
|
||||
itemInfos = filterOutModified(itemInfos);
|
||||
} else {
|
||||
// strip out the item archived today or
|
||||
// not archived yesterday and modified today
|
||||
itemInfos = filterOutToday(itemInfos);
|
||||
}
|
||||
|
||||
// Only add to buffer if there are new items
|
||||
if (itemInfos.size() > 0) {
|
||||
if (!isFirst) {
|
||||
emailText
|
||||
.append("\n---------------------------------------\n");
|
||||
} else {
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
emailText.append(labels.getString("org.dspace.eperson.Subscribe.new-items")).append(" ").append(
|
||||
c.getName()).append(": ").append(
|
||||
itemInfos.size()).append("\n\n");
|
||||
|
||||
for (int j = 0; j < itemInfos.size(); j++) {
|
||||
HarvestedItemInfo hii = (HarvestedItemInfo) itemInfos
|
||||
.get(j);
|
||||
|
||||
String title = hii.item.getName();
|
||||
emailText.append(" ").append(labels.getString("org.dspace.eperson.Subscribe.title"))
|
||||
.append(" ");
|
||||
|
||||
if (StringUtils.isNotBlank(title)) {
|
||||
emailText.append(title);
|
||||
} else {
|
||||
emailText.append(labels.getString("org.dspace.eperson.Subscribe.untitled"));
|
||||
}
|
||||
|
||||
List<MetadataValue> authors = itemService
|
||||
.getMetadata(hii.item, MetadataSchemaEnum.DC.getName(), "contributor", Item.ANY, Item.ANY);
|
||||
|
||||
if (authors.size() > 0) {
|
||||
emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.authors"))
|
||||
.append(" ").append(
|
||||
authors.get(0).getValue());
|
||||
|
||||
for (int k = 1; k < authors.size(); k++) {
|
||||
emailText.append("\n ").append(
|
||||
authors.get(k).getValue());
|
||||
}
|
||||
}
|
||||
|
||||
emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.id"))
|
||||
.append(" ").append(
|
||||
handleService.getCanonicalForm(hii.handle)).append(
|
||||
"\n\n");
|
||||
}
|
||||
}
|
||||
} catch (ParseException pe) {
|
||||
// This should never get thrown as the Dates are auto-generated
|
||||
}
|
||||
}
|
||||
|
||||
// Send an e-mail if there were any new items
|
||||
if (emailText.length() > 0) {
|
||||
|
||||
if (test) {
|
||||
log.info(LogHelper.getHeader(context, "subscription:", "eperson=" + eperson.getEmail()));
|
||||
log.info(LogHelper.getHeader(context, "subscription:", "text=" + emailText.toString()));
|
||||
|
||||
} else {
|
||||
|
||||
Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "subscription"));
|
||||
email.addRecipient(eperson.getEmail());
|
||||
email.addArgument(emailText.toString());
|
||||
email.send();
|
||||
|
||||
log.info(LogHelper.getHeader(context, "sent_subscription", "eperson_id=" + eperson.getID()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for invoking subscriptions via the command line
|
||||
*
|
||||
* @param argv the command line arguments given
|
||||
*/
|
||||
public static void main(String[] argv) {
|
||||
String usage = "org.dspace.eperson.Subscribe [-t] or nothing to send out subscriptions.";
|
||||
|
||||
Options options = new Options();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
CommandLine line = null;
|
||||
|
||||
{
|
||||
Option opt = new Option("t", "test", false, "Run test session");
|
||||
opt.setRequired(false);
|
||||
options.addOption(opt);
|
||||
}
|
||||
|
||||
{
|
||||
Option opt = new Option("h", "help", false, "Print this help message");
|
||||
opt.setRequired(false);
|
||||
options.addOption(opt);
|
||||
}
|
||||
|
||||
try {
|
||||
line = new DefaultParser().parse(options, argv);
|
||||
} catch (org.apache.commons.cli.ParseException e) {
|
||||
// automatically generate the help statement
|
||||
formatter.printHelp(usage, e.getMessage(), options, "");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (line.hasOption("h")) {
|
||||
// automatically generate the help statement
|
||||
formatter.printHelp(usage, options);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
boolean test = line.hasOption("t");
|
||||
|
||||
Context context = null;
|
||||
|
||||
try {
|
||||
context = new Context(Context.Mode.READ_ONLY);
|
||||
processDaily(context, test);
|
||||
context.complete();
|
||||
} catch (IOException | SQLException e) {
|
||||
log.fatal(e);
|
||||
} finally {
|
||||
if (context != null && context.isValid()) {
|
||||
// Nothing is actually written
|
||||
context.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<HarvestedItemInfo> filterOutToday(List<HarvestedItemInfo> completeList) {
|
||||
log.debug("Filtering out all today item to leave new items list size="
|
||||
+ completeList.size());
|
||||
List<HarvestedItemInfo> filteredList = new ArrayList<>();
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String today = sdf.format(new Date());
|
||||
// Get the start and end dates for yesterday
|
||||
Date thisTimeYesterday = new Date(System.currentTimeMillis()
|
||||
- (24 * 60 * 60 * 1000));
|
||||
String yesterday = sdf.format(thisTimeYesterday);
|
||||
|
||||
for (HarvestedItemInfo infoObject : completeList) {
|
||||
Date lastUpdate = infoObject.item.getLastModified();
|
||||
String lastUpdateStr = sdf.format(lastUpdate);
|
||||
|
||||
// has the item modified today?
|
||||
if (lastUpdateStr.equals(today)) {
|
||||
List<MetadataValue> dateAccArr = itemService.getMetadata(infoObject.item, "dc",
|
||||
"date", "accessioned", Item.ANY);
|
||||
// we need only the item archived yesterday
|
||||
if (dateAccArr != null && dateAccArr.size() > 0) {
|
||||
for (MetadataValue date : dateAccArr) {
|
||||
if (date != null && date.getValue() != null) {
|
||||
// if it hasn't been archived today
|
||||
if (date.getValue().startsWith(yesterday)) {
|
||||
filteredList.add(infoObject);
|
||||
log.debug("adding : " + dateAccArr.get(0).getValue()
|
||||
+ " : " + today + " : "
|
||||
+ infoObject.handle);
|
||||
break;
|
||||
} else {
|
||||
log.debug("ignoring : " + dateAccArr.get(0).getValue()
|
||||
+ " : " + today + " : "
|
||||
+ infoObject.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.debug("no date accessioned, adding : "
|
||||
+ infoObject.handle);
|
||||
filteredList.add(infoObject);
|
||||
}
|
||||
} else {
|
||||
// the item has been modified yesterday...
|
||||
filteredList.add(infoObject);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredList;
|
||||
}
|
||||
|
||||
private static List<HarvestedItemInfo> filterOutModified(List<HarvestedItemInfo> completeList) {
|
||||
log.debug("Filtering out all modified to leave new items list size=" + completeList.size());
|
||||
List<HarvestedItemInfo> filteredList = new ArrayList<>();
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
// Get the start and end dates for yesterday
|
||||
Date thisTimeYesterday = new Date(System.currentTimeMillis()
|
||||
- (24 * 60 * 60 * 1000));
|
||||
String yesterday = sdf.format(thisTimeYesterday);
|
||||
|
||||
for (HarvestedItemInfo infoObject : completeList) {
|
||||
List<MetadataValue> dateAccArr = itemService
|
||||
.getMetadata(infoObject.item, "dc", "date", "accessioned", Item.ANY);
|
||||
|
||||
if (dateAccArr != null && dateAccArr.size() > 0) {
|
||||
for (MetadataValue date : dateAccArr) {
|
||||
if (date != null && date.getValue() != null) {
|
||||
// if it has been archived yesterday
|
||||
if (date.getValue().startsWith(yesterday)) {
|
||||
filteredList.add(infoObject);
|
||||
log.debug("adding : " + dateAccArr.get(0)
|
||||
.getValue() + " : " + yesterday + " : " + infoObject
|
||||
.handle);
|
||||
break;
|
||||
} else {
|
||||
log.debug("ignoring : " + dateAccArr.get(0)
|
||||
.getValue() + " : " + yesterday + " : " + infoObject
|
||||
.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
log.debug("no date accessioned, adding : " + infoObject.handle);
|
||||
filteredList.add(infoObject);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredList;
|
||||
}
|
||||
}
|
@@ -9,11 +9,16 @@ package org.dspace.eperson;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
@@ -29,106 +34,177 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class SubscribeServiceImpl implements SubscribeService {
|
||||
/**
|
||||
* log4j logger
|
||||
*/
|
||||
private Logger log = org.apache.logging.log4j.LogManager.getLogger(SubscribeServiceImpl.class);
|
||||
|
||||
private Logger log = LogManager.getLogger(SubscribeServiceImpl.class);
|
||||
|
||||
@Autowired(required = true)
|
||||
protected SubscriptionDAO subscriptionDAO;
|
||||
|
||||
private SubscriptionDAO subscriptionDAO;
|
||||
@Autowired(required = true)
|
||||
protected AuthorizeService authorizeService;
|
||||
private AuthorizeService authorizeService;
|
||||
@Autowired(required = true)
|
||||
protected CollectionService collectionService;
|
||||
|
||||
protected SubscribeServiceImpl() {
|
||||
|
||||
}
|
||||
private CollectionService collectionService;
|
||||
|
||||
@Override
|
||||
public List<Subscription> findAll(Context context) throws SQLException {
|
||||
return subscriptionDAO.findAllOrderedByEPerson(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Context context, EPerson eperson,
|
||||
Collection collection) throws SQLException, AuthorizeException {
|
||||
// Check authorisation. Must be administrator, or the eperson.
|
||||
if (authorizeService.isAdmin(context)
|
||||
|| ((context.getCurrentUser() != null) && (context
|
||||
.getCurrentUser().getID().equals(eperson.getID())))) {
|
||||
if (!isSubscribed(context, eperson, collection)) {
|
||||
Subscription subscription = subscriptionDAO.create(context, new Subscription());
|
||||
subscription.setCollection(collection);
|
||||
subscription.setePerson(eperson);
|
||||
}
|
||||
public List<Subscription> findAll(Context context, String resourceType, Integer limit, Integer offset)
|
||||
throws Exception {
|
||||
if (StringUtils.isBlank(resourceType)) {
|
||||
return subscriptionDAO.findAllOrderedByDSO(context, limit, offset);
|
||||
} else {
|
||||
throw new AuthorizeException(
|
||||
"Only admin or e-person themselves can subscribe");
|
||||
if (resourceType.equals(Collection.class.getSimpleName()) ||
|
||||
resourceType.equals(Community.class.getSimpleName())) {
|
||||
return subscriptionDAO.findAllOrderedByIDAndResourceType(context, resourceType, limit, offset);
|
||||
} else {
|
||||
log.error("Resource type must be Collection or Community");
|
||||
throw new Exception("Resource type must be Collection or Community");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(Context context, EPerson eperson,
|
||||
Collection collection) throws SQLException, AuthorizeException {
|
||||
public Subscription subscribe(Context context, EPerson eperson,
|
||||
DSpaceObject dSpaceObject,
|
||||
List<SubscriptionParameter> subscriptionParameterList,
|
||||
String type) throws SQLException, AuthorizeException {
|
||||
// Check authorisation. Must be administrator, or the eperson.
|
||||
if (authorizeService.isAdmin(context)
|
||||
|| ((context.getCurrentUser() != null) && (context
|
||||
.getCurrentUser().getID().equals(eperson.getID())))) {
|
||||
if (collection == null) {
|
||||
|| ((context.getCurrentUser() != null) && (context
|
||||
.getCurrentUser().getID().equals(eperson.getID())))) {
|
||||
Subscription newSubscription = subscriptionDAO.create(context, new Subscription());
|
||||
subscriptionParameterList.forEach(subscriptionParameter ->
|
||||
newSubscription.addParameter(subscriptionParameter));
|
||||
newSubscription.setEPerson(eperson);
|
||||
newSubscription.setDSpaceObject(dSpaceObject);
|
||||
newSubscription.setSubscriptionType(type);
|
||||
return newSubscription;
|
||||
} else {
|
||||
throw new AuthorizeException("Only admin or e-person themselves can subscribe");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(Context context, EPerson eperson, DSpaceObject dSpaceObject)
|
||||
throws SQLException, AuthorizeException {
|
||||
// Check authorisation. Must be administrator, or the eperson.
|
||||
if (authorizeService.isAdmin(context)
|
||||
|| ((context.getCurrentUser() != null) && (context
|
||||
.getCurrentUser().getID().equals(eperson.getID())))) {
|
||||
if (dSpaceObject == null) {
|
||||
// Unsubscribe from all
|
||||
subscriptionDAO.deleteByEPerson(context, eperson);
|
||||
} else {
|
||||
subscriptionDAO.deleteByCollectionAndEPerson(context, collection, eperson);
|
||||
subscriptionDAO.deleteByDSOAndEPerson(context, dSpaceObject, eperson);
|
||||
|
||||
log.info(LogHelper.getHeader(context, "unsubscribe",
|
||||
"eperson_id=" + eperson.getID() + ",collection_id="
|
||||
+ collection.getID()));
|
||||
+ dSpaceObject.getID()));
|
||||
}
|
||||
} else {
|
||||
throw new AuthorizeException(
|
||||
"Only admin or e-person themselves can unsubscribe");
|
||||
throw new AuthorizeException("Only admin or e-person themselves can unsubscribe");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> getSubscriptions(Context context, EPerson eperson)
|
||||
throws SQLException {
|
||||
return subscriptionDAO.findByEPerson(context, eperson);
|
||||
public List<Subscription> findSubscriptionsByEPerson(Context context, EPerson eperson, Integer limit,Integer offset)
|
||||
throws SQLException {
|
||||
return subscriptionDAO.findByEPerson(context, eperson, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Collection> getAvailableSubscriptions(Context context)
|
||||
throws SQLException {
|
||||
return getAvailableSubscriptions(context, null);
|
||||
public List<Subscription> findSubscriptionsByEPersonAndDso(Context context, EPerson eperson,
|
||||
DSpaceObject dSpaceObject,
|
||||
Integer limit, Integer offset) throws SQLException {
|
||||
return subscriptionDAO.findByEPersonAndDso(context, eperson, dSpaceObject, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Collection> getAvailableSubscriptions(Context context, EPerson eperson)
|
||||
throws SQLException {
|
||||
List<Collection> collections;
|
||||
if (eperson != null) {
|
||||
public List<Collection> findAvailableSubscriptions(Context context) throws SQLException {
|
||||
return findAvailableSubscriptions(context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Collection> findAvailableSubscriptions(Context context, EPerson eperson) throws SQLException {
|
||||
if (Objects.nonNull(eperson)) {
|
||||
context.setCurrentUser(eperson);
|
||||
}
|
||||
collections = collectionService.findAuthorized(context, null, Constants.ADD);
|
||||
|
||||
return collections;
|
||||
return collectionService.findAuthorized(context, null, Constants.ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubscribed(Context context, EPerson eperson,
|
||||
Collection collection) throws SQLException {
|
||||
return subscriptionDAO.findByCollectionAndEPerson(context, eperson, collection) != null;
|
||||
public boolean isSubscribed(Context context, EPerson eperson, DSpaceObject dSpaceObject) throws SQLException {
|
||||
return subscriptionDAO.findByEPersonAndDso(context, eperson, dSpaceObject, -1, -1) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByCollection(Context context, Collection collection) throws SQLException {
|
||||
subscriptionDAO.deleteByCollection(context, collection);
|
||||
public void deleteByDspaceObject(Context context, DSpaceObject dSpaceObject) throws SQLException {
|
||||
subscriptionDAO.deleteByDspaceObject(context, dSpaceObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByEPerson(Context context, EPerson ePerson) throws SQLException {
|
||||
subscriptionDAO.deleteByEPerson(context, ePerson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subscription findById(Context context, int id) throws SQLException {
|
||||
return subscriptionDAO.findByID(context, Subscription.class, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subscription updateSubscription(Context context, Integer id, String subscriptionType,
|
||||
List<SubscriptionParameter> subscriptionParameterList)
|
||||
throws SQLException {
|
||||
Subscription subscriptionDB = subscriptionDAO.findByID(context, Subscription.class, id);
|
||||
subscriptionDB.removeParameterList();
|
||||
subscriptionDB.setSubscriptionType(subscriptionType);
|
||||
subscriptionParameterList.forEach(x -> subscriptionDB.addParameter(x));
|
||||
subscriptionDAO.save(context, subscriptionDB);
|
||||
return subscriptionDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subscription addSubscriptionParameter(Context context, Integer id, SubscriptionParameter subscriptionParam)
|
||||
throws SQLException {
|
||||
Subscription subscriptionDB = subscriptionDAO.findByID(context, Subscription.class, id);
|
||||
subscriptionDB.addParameter(subscriptionParam);
|
||||
subscriptionDAO.save(context, subscriptionDB);
|
||||
return subscriptionDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subscription removeSubscriptionParameter(Context context,Integer id, SubscriptionParameter subscriptionParam)
|
||||
throws SQLException {
|
||||
Subscription subscriptionDB = subscriptionDAO.findByID(context, Subscription.class, id);
|
||||
subscriptionDB.removeParameter(subscriptionParam);
|
||||
subscriptionDAO.save(context, subscriptionDB);
|
||||
return subscriptionDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSubscription(Context context, Subscription subscription) throws SQLException {
|
||||
subscriptionDAO.delete(context, subscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> findAllSubscriptionsBySubscriptionTypeAndFrequency(Context context,
|
||||
String subscriptionType, String frequencyValue) throws SQLException {
|
||||
return subscriptionDAO.findAllSubscriptionsBySubscriptionTypeAndFrequency(context, subscriptionType,
|
||||
frequencyValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countAll(Context context) throws SQLException {
|
||||
return subscriptionDAO.countAll(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countSubscriptionsByEPerson(Context context, EPerson ePerson) throws SQLException {
|
||||
return subscriptionDAO.countAllByEPerson(context, ePerson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countByEPersonAndDSO(Context context, EPerson ePerson, DSpaceObject dSpaceObject)
|
||||
throws SQLException {
|
||||
return subscriptionDAO.countAllByEPersonAndDso(context, ePerson, dSpaceObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,6 +7,9 @@
|
||||
*/
|
||||
package org.dspace.eperson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
@@ -15,10 +18,11 @@ import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
|
||||
@@ -37,40 +41,78 @@ public class Subscription implements ReloadableEntity<Integer> {
|
||||
@SequenceGenerator(name = "subscription_seq", sequenceName = "subscription_seq", allocationSize = 1)
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "collection_id")
|
||||
private Collection collection;
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "dspace_object_id")
|
||||
private DSpaceObject dSpaceObject;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "eperson_id")
|
||||
private EPerson ePerson;
|
||||
|
||||
/**
|
||||
* Protected constructor, create object using:
|
||||
* {@link org.dspace.eperson.service.SubscribeService#subscribe(Context, EPerson, Collection)}
|
||||
* Represent subscription type, for example, "content" or "statistics".
|
||||
*
|
||||
* NOTE: Currently, in DSpace we use only one "content"
|
||||
*/
|
||||
protected Subscription() {
|
||||
@Column(name = "type")
|
||||
private String subscriptionType;
|
||||
|
||||
}
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "subscription", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<SubscriptionParameter> subscriptionParameterList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Protected constructor, create object using:
|
||||
* {@link org.dspace.eperson.service.SubscribeService#subscribe(Context, EPerson, DSpaceObject, List, String)}
|
||||
*/
|
||||
protected Subscription() {}
|
||||
|
||||
@Override
|
||||
public Integer getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Collection getCollection() {
|
||||
return collection;
|
||||
public DSpaceObject getDSpaceObject() {
|
||||
return this.dSpaceObject;
|
||||
}
|
||||
|
||||
void setCollection(Collection collection) {
|
||||
this.collection = collection;
|
||||
void setDSpaceObject(DSpaceObject dSpaceObject) {
|
||||
this.dSpaceObject = dSpaceObject;
|
||||
}
|
||||
|
||||
public EPerson getePerson() {
|
||||
public EPerson getEPerson() {
|
||||
return ePerson;
|
||||
}
|
||||
|
||||
void setePerson(EPerson ePerson) {
|
||||
public void setEPerson(EPerson ePerson) {
|
||||
this.ePerson = ePerson;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSubscriptionType() {
|
||||
return subscriptionType;
|
||||
}
|
||||
|
||||
public void setSubscriptionType(String subscriptionType) {
|
||||
this.subscriptionType = subscriptionType;
|
||||
}
|
||||
|
||||
public List<SubscriptionParameter> getSubscriptionParameterList() {
|
||||
return subscriptionParameterList;
|
||||
}
|
||||
|
||||
public void setSubscriptionParameterList(List<SubscriptionParameter> subscriptionList) {
|
||||
this.subscriptionParameterList = subscriptionList;
|
||||
}
|
||||
|
||||
public void addParameter(SubscriptionParameter subscriptionParameter) {
|
||||
subscriptionParameterList.add(subscriptionParameter);
|
||||
subscriptionParameter.setSubscription(this);
|
||||
}
|
||||
|
||||
public void removeParameterList() {
|
||||
subscriptionParameterList.clear();
|
||||
}
|
||||
|
||||
public void removeParameter(SubscriptionParameter subscriptionParameter) {
|
||||
subscriptionParameterList.remove(subscriptionParameter);
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.eperson;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
|
||||
/**
|
||||
* Database entity representation of the subscription_parameter table
|
||||
* SubscriptionParameter represents a frequency with which an user wants to be notified.
|
||||
*
|
||||
* @author Alba Aliu at atis.al
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "subscription_parameter")
|
||||
public class SubscriptionParameter implements ReloadableEntity<Integer> {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subscription_parameter_seq")
|
||||
@SequenceGenerator(name = "subscription_parameter_seq", sequenceName = "subscription_parameter_seq",
|
||||
allocationSize = 1)
|
||||
@Column(name = "subscription_parameter_id", unique = true)
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "subscription_id", nullable = false)
|
||||
private Subscription subscription;
|
||||
|
||||
/*
|
||||
* Currently, we have only one use case for this attribute: "frequency"
|
||||
*/
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
/*
|
||||
* Currently, we use this attribute only with following values: "D", "W", "M".
|
||||
* Where D stand for Day, W stand for Week and M stand for Month
|
||||
*/
|
||||
@Column
|
||||
private String value;
|
||||
|
||||
public SubscriptionParameter() {}
|
||||
|
||||
public SubscriptionParameter(Integer id, Subscription subscription, String name, String value) {
|
||||
this.id = id;
|
||||
this.subscription = subscription;
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Subscription getSubscription() {
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public void setSubscription(Subscription subscription) {
|
||||
this.subscription = subscription;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
@@ -10,7 +10,7 @@ package org.dspace.eperson.dao;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.GenericDAO;
|
||||
import org.dspace.eperson.EPerson;
|
||||
@@ -26,17 +26,125 @@ import org.dspace.eperson.Subscription;
|
||||
*/
|
||||
public interface SubscriptionDAO extends GenericDAO<Subscription> {
|
||||
|
||||
public void deleteByCollection(Context context, Collection collection) throws SQLException;
|
||||
/**
|
||||
* Delete all subscription of provided dSpaceObject
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param dSpaceObject DSpace resource
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public void deleteByDspaceObject(Context context, DSpaceObject dSpaceObject) throws SQLException;
|
||||
|
||||
public List<Subscription> findByEPerson(Context context, EPerson eperson) throws SQLException;
|
||||
/**
|
||||
* Return a paginated list of all subscriptions of the eperson
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param eperson ePerson whose subscriptions want to find
|
||||
* @param limit Paging limit
|
||||
* @param offset The position of the first result to return
|
||||
* @return
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public List<Subscription> findByEPerson(Context context, EPerson eperson, Integer limit, Integer offset)
|
||||
throws SQLException;
|
||||
|
||||
public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection)
|
||||
throws SQLException;
|
||||
/**
|
||||
* Return a paginated list of subscriptions related to a DSpaceObject belong to an ePerson
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param eperson ePerson whose subscriptions want to find
|
||||
* @param dSpaceObject DSpaceObject of whom subscriptions want to find
|
||||
* @param limit Paging limit
|
||||
* @param offset The position of the first result to return
|
||||
* @return
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public List<Subscription> findByEPersonAndDso(Context context, EPerson eperson, DSpaceObject dSpaceObject,
|
||||
Integer limit, Integer offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Delete all subscription of provided ePerson
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param eperson ePerson whose subscriptions want to delete
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public void deleteByEPerson(Context context, EPerson eperson) throws SQLException;
|
||||
|
||||
public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson)
|
||||
throws SQLException;
|
||||
/**
|
||||
* Delete all subscriptions related to a DSpaceObject belong to an ePerson
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param dSpaceObject DSpaceObject of whom subscriptions want to delete
|
||||
* @param eperson ePerson whose subscriptions want to delete
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public void deleteByDSOAndEPerson(Context context, DSpaceObject dSpaceObject, EPerson eperson) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return a paginated list of all subscriptions ordered by ID and resourceType
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param resourceType Could be Collection or Community
|
||||
* @param limit Paging limit
|
||||
* @param offset The position of the first result to return
|
||||
* @return
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public List<Subscription> findAllOrderedByIDAndResourceType(Context context, String resourceType,
|
||||
Integer limit, Integer offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return a paginated list of subscriptions ordered by DSpaceObject
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param limit Paging limit
|
||||
* @param offset The position of the first result to return
|
||||
* @return
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public List<Subscription> findAllOrderedByDSO(Context context, Integer limit, Integer offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return a list of all subscriptions by subscriptionType and frequency
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param subscriptionType Could be "content" or "statistics". NOTE: in DSpace we have only "content"
|
||||
* @param frequencyValue Could be "D" stand for Day, "W" stand for Week, and "M" stand for Month
|
||||
* @return
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public List<Subscription> findAllSubscriptionsBySubscriptionTypeAndFrequency(Context context,
|
||||
String subscriptionType, String frequencyValue) throws SQLException;
|
||||
|
||||
/**
|
||||
* Count all subscriptions
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @return Total of all subscriptions
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public Long countAll(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Count all subscriptions belong to an ePerson
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param ePerson ePerson whose subscriptions want count
|
||||
* @return Total of all subscriptions belong to an ePerson
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public Long countAllByEPerson(Context context, EPerson ePerson) throws SQLException;
|
||||
|
||||
/**
|
||||
* Count all subscriptions related to a DSpaceObject belong to an ePerson
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param ePerson ePerson whose subscriptions want count
|
||||
* @param dSpaceObject DSpaceObject of whom subscriptions want count
|
||||
* @return
|
||||
* @throws SQLException If database error
|
||||
*/
|
||||
public Long countAllByEPersonAndDso(Context context, EPerson ePerson,DSpaceObject dSpaceObject) throws SQLException;
|
||||
|
||||
public List<Subscription> findAllOrderedByEPerson(Context context) throws SQLException;
|
||||
}
|
||||
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.eperson.dao;
|
||||
import org.dspace.core.GenericDAO;
|
||||
import org.dspace.eperson.SubscriptionParameter;
|
||||
|
||||
|
||||
/**
|
||||
* Database Access Object interface class for the SubscriptionParamter object.
|
||||
* The implementation of this class is responsible for all database calls for the SubscriptionParameter object and is
|
||||
* autowired by spring
|
||||
* This class should only be accessed from a single service and should never be exposed outside of the API
|
||||
*
|
||||
* @author Alba Aliu at atis.al
|
||||
*/
|
||||
public interface SubscriptionParameterDAO extends GenericDAO<SubscriptionParameter> {
|
||||
}
|
@@ -9,17 +9,21 @@ package org.dspace.eperson.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.AbstractHibernateDAO;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Subscription;
|
||||
import org.dspace.eperson.SubscriptionParameter;
|
||||
import org.dspace.eperson.SubscriptionParameter_;
|
||||
import org.dspace.eperson.Subscription_;
|
||||
import org.dspace.eperson.dao.SubscriptionDAO;
|
||||
|
||||
@@ -31,42 +35,50 @@ import org.dspace.eperson.dao.SubscriptionDAO;
|
||||
* @author kevinvandevelde at atmire.com
|
||||
*/
|
||||
public class SubscriptionDAOImpl extends AbstractHibernateDAO<Subscription> implements SubscriptionDAO {
|
||||
|
||||
protected SubscriptionDAOImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> findByEPerson(Context context, EPerson eperson) throws SQLException {
|
||||
public List<Subscription> findByEPerson(Context context, EPerson eperson, Integer limit, Integer offset)
|
||||
throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class);
|
||||
Root<Subscription> subscriptionRoot = criteriaQuery.from(Subscription.class);
|
||||
criteriaQuery.select(subscriptionRoot);
|
||||
criteriaQuery.where(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson));
|
||||
return list(context, criteriaQuery, false, Subscription.class, -1, -1);
|
||||
|
||||
List<javax.persistence.criteria.Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.dSpaceObject)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
return list(context, criteriaQuery, false, Subscription.class, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection)
|
||||
throws SQLException {
|
||||
public List<Subscription> findByEPersonAndDso(Context context, EPerson eperson,
|
||||
DSpaceObject dSpaceObject,
|
||||
Integer limit, Integer offset) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class);
|
||||
javax.persistence.criteria.CriteriaQuery criteriaQuery =
|
||||
getCriteriaQuery(criteriaBuilder, Subscription.class);
|
||||
Root<Subscription> subscriptionRoot = criteriaQuery.from(Subscription.class);
|
||||
criteriaQuery.select(subscriptionRoot);
|
||||
criteriaQuery
|
||||
.where(criteriaBuilder.and(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson),
|
||||
criteriaBuilder.equal(subscriptionRoot.get(Subscription_.collection), collection)
|
||||
)
|
||||
);
|
||||
return singleResult(context, criteriaQuery);
|
||||
criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.equal(
|
||||
subscriptionRoot.get(Subscription_.ePerson), eperson),
|
||||
criteriaBuilder.equal(subscriptionRoot.get(Subscription_.dSpaceObject), dSpaceObject)
|
||||
));
|
||||
List<javax.persistence.criteria.Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.dSpaceObject)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
return list(context, criteriaQuery, false, Subscription.class, limit, offset);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void deleteByCollection(Context context, Collection collection) throws SQLException {
|
||||
String hqlQuery = "delete from Subscription where collection=:collection";
|
||||
public void deleteByDspaceObject(Context context, DSpaceObject dSpaceObject) throws SQLException {
|
||||
String hqlQuery = "delete from Subscription where dSpaceObject=:dSpaceObject";
|
||||
Query query = createQuery(context, hqlQuery);
|
||||
query.setParameter("collection", collection);
|
||||
query.setParameter("dSpaceObject", dSpaceObject);
|
||||
query.executeUpdate();
|
||||
}
|
||||
|
||||
@@ -79,28 +91,98 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO<Subscription> impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson)
|
||||
throws SQLException {
|
||||
String hqlQuery = "delete from Subscription where collection=:collection AND ePerson=:ePerson";
|
||||
public void deleteByDSOAndEPerson(Context context, DSpaceObject dSpaceObject, EPerson eperson)
|
||||
throws SQLException {
|
||||
String hqlQuery = "delete from Subscription where dSpaceObject=:dSpaceObject AND ePerson=:ePerson";
|
||||
Query query = createQuery(context, hqlQuery);
|
||||
query.setParameter("collection", collection);
|
||||
query.setParameter("dSpaceObject", dSpaceObject);
|
||||
query.setParameter("ePerson", eperson);
|
||||
query.executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> findAllOrderedByEPerson(Context context) throws SQLException {
|
||||
|
||||
public List<Subscription> findAllOrderedByIDAndResourceType(Context context, String resourceType,
|
||||
Integer limit, Integer offset) throws SQLException {
|
||||
String hqlQuery = "select s from Subscription s join %s dso " +
|
||||
"ON dso.id = s.dSpaceObject ORDER BY subscription_id";
|
||||
if (resourceType != null) {
|
||||
hqlQuery = String.format(hqlQuery, resourceType);
|
||||
}
|
||||
Query query = createQuery(context, hqlQuery);
|
||||
if (limit != -1) {
|
||||
query.setMaxResults(limit);
|
||||
}
|
||||
if (offset != -1) {
|
||||
query.setFirstResult(offset);
|
||||
}
|
||||
query.setHint("org.hibernate.cacheable", false);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> findAllOrderedByDSO(Context context, Integer limit, Integer offset) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class);
|
||||
Root<Subscription> subscriptionRoot = criteriaQuery.from(Subscription.class);
|
||||
criteriaQuery.select(subscriptionRoot);
|
||||
List<javax.persistence.criteria.Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.dSpaceObject)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
return list(context, criteriaQuery, false, Subscription.class, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> findAllSubscriptionsBySubscriptionTypeAndFrequency(Context context,
|
||||
String subscriptionType, String frequencyValue) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class);
|
||||
Root<Subscription> subscriptionRoot = criteriaQuery.from(Subscription.class);
|
||||
criteriaQuery.select(subscriptionRoot);
|
||||
Join<Subscription, SubscriptionParameter> childJoin = subscriptionRoot.join("subscriptionParameterList");
|
||||
criteriaQuery.where(
|
||||
criteriaBuilder.and(
|
||||
criteriaBuilder.equal(subscriptionRoot.get(Subscription_.SUBSCRIPTION_TYPE), subscriptionType),
|
||||
criteriaBuilder.equal(childJoin.get(SubscriptionParameter_.name), "frequency"),
|
||||
criteriaBuilder.equal(childJoin.get(SubscriptionParameter_.value), frequencyValue)
|
||||
));
|
||||
List<javax.persistence.criteria.Order> orderList = new ArrayList<>(1);
|
||||
orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.ePerson)));
|
||||
orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.id)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
|
||||
return list(context, criteriaQuery, false, Subscription.class, -1, -1);
|
||||
return list(context, criteriaQuery, false, Subscription.class, 10000, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countAll(Context context) throws SQLException {
|
||||
CriteriaBuilder qb = getCriteriaBuilder(context);
|
||||
CriteriaQuery<Long> cq = qb.createQuery(Long.class);
|
||||
cq.select(qb.count(cq.from(Subscription.class)));
|
||||
Query query = this.getHibernateSession(context).createQuery(cq);
|
||||
return (Long) query.getSingleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countAllByEPerson(Context context, EPerson ePerson) throws SQLException {
|
||||
CriteriaBuilder qb = getCriteriaBuilder(context);
|
||||
CriteriaQuery<Long> cq = qb.createQuery(Long.class);
|
||||
Root<Subscription> subscriptionRoot = cq.from(Subscription.class);
|
||||
cq.select(qb.count(subscriptionRoot));
|
||||
cq.where(qb.equal(subscriptionRoot.get(Subscription_.ePerson), ePerson));
|
||||
Query query = this.getHibernateSession(context).createQuery(cq);
|
||||
return (Long) query.getSingleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countAllByEPersonAndDso(Context context,
|
||||
EPerson ePerson, DSpaceObject dSpaceObject) throws SQLException {
|
||||
CriteriaBuilder qb = getCriteriaBuilder(context);
|
||||
CriteriaQuery<Long> cq = qb.createQuery(Long.class);
|
||||
Root<Subscription> subscriptionRoot = cq.from(Subscription.class);
|
||||
cq.select(qb.count(subscriptionRoot));
|
||||
cq.where(qb.and(qb.equal(subscriptionRoot.get(Subscription_.ePerson)
|
||||
, ePerson), qb.equal(subscriptionRoot.get(Subscription_.dSpaceObject), dSpaceObject)));
|
||||
Query query = this.getHibernateSession(context).createQuery(cq);
|
||||
return (Long) query.getSingleResult();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.eperson.dao.impl;
|
||||
|
||||
import org.dspace.core.AbstractHibernateDAO;
|
||||
import org.dspace.eperson.SubscriptionParameter;
|
||||
import org.dspace.eperson.dao.SubscriptionParameterDAO;
|
||||
|
||||
/**
|
||||
* Hibernate implementation of the Database Access Object interface class for the SubscriptionParameter object.
|
||||
* This class is responsible for all database calls for the SubscriptionParameter object and is autowired by spring
|
||||
* This class should never be accessed directly.
|
||||
*
|
||||
* @author Alba Aliu at atis.al
|
||||
*/
|
||||
public class SubscriptionParameterDAOImpl extends AbstractHibernateDAO<SubscriptionParameter>
|
||||
implements SubscriptionParameterDAO {
|
||||
|
||||
protected SubscriptionParameterDAOImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
@@ -12,9 +12,11 @@ import java.util.List;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Subscription;
|
||||
import org.dspace.eperson.SubscriptionParameter;
|
||||
|
||||
/**
|
||||
* Service interface class for the Subscription object.
|
||||
@@ -31,49 +33,74 @@ public interface SubscribeService {
|
||||
* new item appears in the collection.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param limit Number of subscriptions to return
|
||||
* @param offset Offset number
|
||||
* @return list of Subscription objects
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public List<Subscription> findAll(Context context) throws SQLException;
|
||||
public List<Subscription> findAll(Context context, String resourceType, Integer limit, Integer offset)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Subscribe an e-person to a collection. An e-mail will be sent every day a
|
||||
* new item appears in the collection.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param eperson EPerson to subscribe
|
||||
* @param collection Collection to subscribe to
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
* Subscribe an EPerson to a dSpaceObject (Collection or Community). An e-mail will be sent every day a
|
||||
* new item appears in the Collection or Community.
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param eperson EPerson to subscribe
|
||||
* @param dSpaceObject DSpaceObject to subscribe
|
||||
* @param subscriptionParameters list of @SubscriptionParameter
|
||||
* @param subscriptionType Currently supported only "content"
|
||||
* @return
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
*/
|
||||
public void subscribe(Context context, EPerson eperson,
|
||||
Collection collection) throws SQLException, AuthorizeException;
|
||||
public Subscription subscribe(Context context, EPerson eperson, DSpaceObject dSpaceObject,
|
||||
List<SubscriptionParameter> subscriptionParameters,
|
||||
String subscriptionType) throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Unsubscribe an e-person to a collection. Passing in <code>null</code>
|
||||
* for the collection unsubscribes the e-person from all collections they
|
||||
* are subscribed to.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param eperson EPerson to unsubscribe
|
||||
* @param collection Collection to unsubscribe from
|
||||
* @param context DSpace context
|
||||
* @param eperson EPerson to unsubscribe
|
||||
* @param dSpaceObject DSpaceObject to unsubscribe from
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
*/
|
||||
public void unsubscribe(Context context, EPerson eperson,
|
||||
Collection collection) throws SQLException, AuthorizeException;
|
||||
public void unsubscribe(Context context, EPerson eperson, DSpaceObject dSpaceObject)
|
||||
throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Find out which collections an e-person is subscribed to
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param eperson EPerson
|
||||
* @param limit Number of subscriptions to return
|
||||
* @param offset Offset number
|
||||
* @return array of collections e-person is subscribed to
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public List<Subscription> getSubscriptions(Context context, EPerson eperson) throws SQLException;
|
||||
public List<Subscription> findSubscriptionsByEPerson(Context context, EPerson eperson, Integer limit,Integer offset)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Find out which collections an e-person is subscribed to and related with dso
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param eperson EPerson
|
||||
* @param dSpaceObject DSpaceObject
|
||||
* @param limit Number of subscriptions to return
|
||||
* @param offset Offset number
|
||||
* @return array of collections e-person is subscribed to and related with dso
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public List<Subscription> findSubscriptionsByEPersonAndDso(Context context, EPerson eperson,
|
||||
DSpaceObject dSpaceObject,
|
||||
Integer limit, Integer offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Find out which collections the currently logged in e-person can subscribe to
|
||||
@@ -82,8 +109,7 @@ public interface SubscribeService {
|
||||
* @return array of collections the currently logged in e-person can subscribe to
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public List<Collection> getAvailableSubscriptions(Context context)
|
||||
throws SQLException;
|
||||
public List<Collection> findAvailableSubscriptions(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Find out which collections an e-person can subscribe to
|
||||
@@ -93,29 +119,27 @@ public interface SubscribeService {
|
||||
* @return array of collections e-person can subscribe to
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public List<Collection> getAvailableSubscriptions(Context context, EPerson eperson)
|
||||
throws SQLException;
|
||||
public List<Collection> findAvailableSubscriptions(Context context, EPerson eperson) throws SQLException;
|
||||
|
||||
/**
|
||||
* Is that e-person subscribed to that collection?
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param eperson find out if this e-person is subscribed
|
||||
* @param collection find out if subscribed to this collection
|
||||
* @param context DSpace context
|
||||
* @param eperson find out if this e-person is subscribed
|
||||
* @param dSpaceObject find out if subscribed to this dSpaceObject
|
||||
* @return <code>true</code> if they are subscribed
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public boolean isSubscribed(Context context, EPerson eperson,
|
||||
Collection collection) throws SQLException;
|
||||
public boolean isSubscribed(Context context, EPerson eperson, DSpaceObject dSpaceObject) throws SQLException;
|
||||
|
||||
/**
|
||||
* Delete subscription by collection.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param collection find out if subscribed to this collection
|
||||
* @param context DSpace context
|
||||
* @param dSpaceObject find out if subscribed to this dSpaceObject
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public void deleteByCollection(Context context, Collection collection) throws SQLException;
|
||||
public void deleteByDspaceObject(Context context, DSpaceObject dSpaceObject) throws SQLException;
|
||||
|
||||
/**
|
||||
* Delete subscription by eperson (subscriber).
|
||||
@@ -125,4 +149,92 @@ public interface SubscribeService {
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public void deleteByEPerson(Context context, EPerson ePerson) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a subscription by id
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param id the id of subscription to be searched
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public Subscription findById(Context context, int id) throws SQLException;
|
||||
|
||||
/**
|
||||
* Updates a subscription by id
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param id Integer id
|
||||
* @param subscriptionParameterList List<SubscriptionParameter> subscriptionParameterList
|
||||
* @param subscriptionType type
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public Subscription updateSubscription(Context context, Integer id, String subscriptionType,
|
||||
List<SubscriptionParameter> subscriptionParameterList) throws SQLException;
|
||||
|
||||
/**
|
||||
* Adds a parameter to a subscription
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param id Integer id
|
||||
* @param subscriptionParameter SubscriptionParameter subscriptionParameter
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public Subscription addSubscriptionParameter(Context context,Integer id,
|
||||
SubscriptionParameter subscriptionParameter) throws SQLException;
|
||||
|
||||
/**
|
||||
* Deletes a parameter from subscription
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param id Integer id
|
||||
* @param subscriptionParam SubscriptionParameter subscriptionParameter
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public Subscription removeSubscriptionParameter(Context context, Integer id,
|
||||
SubscriptionParameter subscriptionParam) throws SQLException;
|
||||
|
||||
/**
|
||||
* Deletes a subscription
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param subscription The subscription to delete
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public void deleteSubscription(Context context, Subscription subscription) throws SQLException;
|
||||
|
||||
/**
|
||||
* Finds all subscriptions by subscriptionType and frequency
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param subscriptionType Could be "content" or "statistics". NOTE: in DSpace we have only "content"
|
||||
* @param frequencyValue Could be "D" stand for Day, "W" stand for Week, and "M" stand for Month
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public List<Subscription> findAllSubscriptionsBySubscriptionTypeAndFrequency(Context context,
|
||||
String subscriptionType, String frequencyValue) throws SQLException;
|
||||
|
||||
/**
|
||||
* Counts all subscriptions
|
||||
*
|
||||
* @param context DSpace context
|
||||
*/
|
||||
public Long countAll(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Counts all subscriptions by ePerson
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param ePerson EPerson ePerson
|
||||
*/
|
||||
public Long countSubscriptionsByEPerson(Context context, EPerson ePerson) throws SQLException;
|
||||
|
||||
/**
|
||||
* Counts all subscriptions by ePerson and DSO
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param ePerson EPerson ePerson
|
||||
* @param dSpaceObject DSpaceObject dSpaceObject
|
||||
*/
|
||||
public Long countByEPersonAndDSO(Context context, EPerson ePerson, DSpaceObject dSpaceObject) throws SQLException;
|
||||
|
||||
}
|
@@ -21,6 +21,7 @@ import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.content.logic.TrueFilter;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
@@ -28,6 +29,7 @@ import org.dspace.identifier.doi.DOIConnector;
|
||||
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||
import org.dspace.identifier.doi.DOIIdentifierNotApplicableException;
|
||||
import org.dspace.identifier.service.DOIService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -44,6 +46,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
* <p>Any identifier a method of this class returns is a string in the following format: doi:10.123/456.</p>
|
||||
*
|
||||
* @author Pascal-Nicolas Becker
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class);
|
||||
@@ -71,16 +74,44 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
public static final String MD_SCHEMA = "dc";
|
||||
public static final String DOI_ELEMENT = "identifier";
|
||||
public static final String DOI_QUALIFIER = "uri";
|
||||
|
||||
// The DOI is queued for registered with the service provider
|
||||
public static final Integer TO_BE_REGISTERED = 1;
|
||||
// The DOI is queued for reservation with the service provider
|
||||
public static final Integer TO_BE_RESERVED = 2;
|
||||
// The DOI has been registered online
|
||||
public static final Integer IS_REGISTERED = 3;
|
||||
// The DOI has been reserved online
|
||||
public static final Integer IS_RESERVED = 4;
|
||||
// The DOI is reserved and requires an updated metadata record to be sent to the service provider
|
||||
public static final Integer UPDATE_RESERVED = 5;
|
||||
// The DOI is registered and requires an updated metadata record to be sent to the service provider
|
||||
public static final Integer UPDATE_REGISTERED = 6;
|
||||
// The DOI metadata record should be updated before performing online registration
|
||||
public static final Integer UPDATE_BEFORE_REGISTRATION = 7;
|
||||
// The DOI will be deleted locally and marked as deleted in the DOI service provider
|
||||
public static final Integer TO_BE_DELETED = 8;
|
||||
// The DOI has been deleted and is no longer associated with an item
|
||||
public static final Integer DELETED = 9;
|
||||
// The DOI is created in the database and is waiting for either successful filter check on item install or
|
||||
// manual intervention by an administrator to proceed to reservation or registration
|
||||
public static final Integer PENDING = 10;
|
||||
// The DOI is created in the database, but no more context is known
|
||||
public static final Integer MINTED = 11;
|
||||
|
||||
public static final String[] statusText = {
|
||||
"UNKNOWN", // 0
|
||||
"TO_BE_REGISTERED", // 1
|
||||
"TO_BE_RESERVED", // 2
|
||||
"IS_REGISTERED", // 3
|
||||
"IS_RESERVED", // 4
|
||||
"UPDATE_RESERVED", // 5
|
||||
"UPDATE_REGISTERED", // 6
|
||||
"UPDATE_BEFORE_REGISTRATION", // 7
|
||||
"TO_BE_DELETED", // 8
|
||||
"DELETED", // 9
|
||||
"PENDING", // 10
|
||||
"MINTED", // 11
|
||||
};
|
||||
|
||||
@Autowired(required = true)
|
||||
protected DOIService doiService;
|
||||
@@ -89,8 +120,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
@Autowired(required = true)
|
||||
protected ItemService itemService;
|
||||
|
||||
protected Filter filterService;
|
||||
|
||||
/**
|
||||
* Empty / default constructor for Spring
|
||||
*/
|
||||
@@ -153,16 +182,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Filter to use when testing items to see if a DOI should be registered
|
||||
* Spring will use this setter to set the filter from the configured property in identifier-services.xml
|
||||
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface
|
||||
*/
|
||||
@Override
|
||||
public void setFilterService(Filter filterService) {
|
||||
this.filterService = filterService;
|
||||
}
|
||||
|
||||
/**
|
||||
* This identifier provider supports identifiers of type
|
||||
* {@link org.dspace.identifier.DOI}.
|
||||
@@ -206,7 +225,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
@Override
|
||||
public String register(Context context, DSpaceObject dso)
|
||||
throws IdentifierException {
|
||||
return register(context, dso, false);
|
||||
return register(context, dso, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,29 +238,29 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException {
|
||||
register(context, dso, identifier, false);
|
||||
register(context, dso, identifier, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new DOI for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new DOI
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public String register(Context context, DSpaceObject dso, boolean skipFilter)
|
||||
public String register(Context context, DSpaceObject dso, Filter filter)
|
||||
throws IdentifierException {
|
||||
if (!(dso instanceof Item)) {
|
||||
// DOI are currently assigned only to Item
|
||||
return null;
|
||||
}
|
||||
|
||||
String doi = mint(context, dso, skipFilter);
|
||||
String doi = mint(context, dso, filter);
|
||||
|
||||
// register tries to reserve doi if it's not already.
|
||||
// So we don't have to reserve it here.
|
||||
register(context, dso, doi, skipFilter);
|
||||
register(context, dso, doi, filter);
|
||||
return doi;
|
||||
}
|
||||
|
||||
@@ -250,11 +269,11 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new DOI
|
||||
* @param identifier - String containing the DOI to register
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
public void register(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException {
|
||||
if (!(dso instanceof Item)) {
|
||||
// DOI are currently assigned only to Item
|
||||
@@ -265,7 +284,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
|
||||
// search DOI in our db
|
||||
try {
|
||||
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
doiRow = loadOrCreateDOI(context, dso, doi, filter);
|
||||
} catch (SQLException ex) {
|
||||
log.error("Error in databse connection: " + ex.getMessage());
|
||||
throw new RuntimeException("Error in database conncetion.", ex);
|
||||
@@ -277,7 +296,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||
}
|
||||
|
||||
// Check status of DOI
|
||||
if (IS_REGISTERED.equals(doiRow.getStatus())) {
|
||||
return;
|
||||
}
|
||||
@@ -290,6 +308,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
log.warn("SQLException while changing status of DOI {} to be registered.", doi);
|
||||
throw new RuntimeException(sqle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,7 +328,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
@Override
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException {
|
||||
reserve(context, dso, identifier, false);
|
||||
reserve(context, dso, identifier, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,20 +336,18 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
|
||||
* @param filter - Logical item filter to determine whether this identifier should be reserved
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
@Override
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException, IllegalArgumentException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
DOI doiRow = null;
|
||||
|
||||
try {
|
||||
// if the doi is in our db already loadOrCreateDOI just returns.
|
||||
// if it is not loadOrCreateDOI safes the doi.
|
||||
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
doiRow = loadOrCreateDOI(context, dso, doi, filter);
|
||||
} catch (SQLException sqle) {
|
||||
throw new RuntimeException(sqle);
|
||||
}
|
||||
@@ -359,7 +376,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
*/
|
||||
public void reserveOnline(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
reserveOnline(context, dso, identifier, false);
|
||||
reserveOnline(context, dso, identifier, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,16 +384,16 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @param skipFilter - skip the filters for {@link checkMintable(Context, DSpaceObject)}
|
||||
* @param filter - Logical item filter to determine whether this identifier should be reserved online
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void reserveOnline(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
public void reserveOnline(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
// get TableRow and ensure DOI belongs to dso regarding our db
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, filter);
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to reserve a DOI that "
|
||||
@@ -402,7 +419,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
public void registerOnline(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
|
||||
registerOnline(context, dso, identifier, false);
|
||||
registerOnline(context, dso, identifier, this.filter);
|
||||
|
||||
}
|
||||
|
||||
@@ -411,18 +428,17 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to register
|
||||
* @param skipFilter - skip filters for {@link checkMintable(Context, DSpaceObject)}
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered online
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void registerOnline(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
public void registerOnline(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
log.debug("registerOnline: skipFilter is " + skipFilter);
|
||||
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
// get TableRow and ensure DOI belongs to dso regarding our db
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, filter);
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||
@@ -435,7 +451,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
} catch (DOIIdentifierException die) {
|
||||
// do we have to reserve DOI before we can register it?
|
||||
if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) {
|
||||
this.reserveOnline(context, dso, identifier, skipFilter);
|
||||
this.reserveOnline(context, dso, identifier, filter);
|
||||
connector.registerDOI(context, dso, doi);
|
||||
} else {
|
||||
throw die;
|
||||
@@ -471,17 +487,23 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
|
||||
boolean skipFilter = false;
|
||||
// Use the default filter unless we find the object
|
||||
Filter updateFilter = this.filter;
|
||||
|
||||
if (doiService.findDOIByDSpaceObject(context, dso) != null) {
|
||||
// We can skip the filter here since we know the DOI already exists for the item
|
||||
log.debug("updateMetadata: found DOIByDSpaceObject: " +
|
||||
doiService.findDOIByDSpaceObject(context, dso).getDoi());
|
||||
skipFilter = true;
|
||||
updateFilter = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(
|
||||
"always_true_filter", TrueFilter.class);
|
||||
}
|
||||
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, updateFilter);
|
||||
|
||||
if (PENDING.equals(doiRow.getStatus()) || MINTED.equals(doiRow.getStatus())) {
|
||||
log.info("Not updating metadata for PENDING or MINTED doi: " + doi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||
@@ -571,19 +593,19 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
@Override
|
||||
public String mint(Context context, DSpaceObject dso)
|
||||
throws IdentifierException {
|
||||
return mint(context, dso, false);
|
||||
return mint(context, dso, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mint a new DOI in DSpace - this is usually the first step of registration
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting.
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @return a String containing the new identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public String mint(Context context, DSpaceObject dso, boolean skipFilter) throws IdentifierException {
|
||||
public String mint(Context context, DSpaceObject dso, Filter filter) throws IdentifierException {
|
||||
|
||||
String doi = null;
|
||||
try {
|
||||
@@ -597,7 +619,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
}
|
||||
if (null == doi) {
|
||||
try {
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, null, skipFilter);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, null, filter);
|
||||
doi = DOI.SCHEME + doiRow.getDoi();
|
||||
|
||||
} catch (SQLException e) {
|
||||
@@ -895,7 +917,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
*/
|
||||
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier)
|
||||
throws SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
return loadOrCreateDOI(context, dso, doiIdentifier, false);
|
||||
return loadOrCreateDOI(context, dso, doiIdentifier, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -910,13 +932,13 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to identify
|
||||
* @param doiIdentifier - DOI to load or create (null to mint a new one)
|
||||
* @param skipFilter - Whether or not to skip the filters for the checkMintable() check
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @return
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
* @throws org.dspace.identifier.IdentifierNotApplicableException passed through.
|
||||
*/
|
||||
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier, boolean skipFilter)
|
||||
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier, Filter filter)
|
||||
throws SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
|
||||
DOI doi = null;
|
||||
@@ -954,6 +976,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
// doi is assigned to a DSO; is it assigned to our specific dso?
|
||||
// check if DOI already belongs to dso
|
||||
if (dso.getID().equals(doi.getDSpaceObject().getID())) {
|
||||
// Before we return this, check the filter
|
||||
checkMintable(context, filter, dso);
|
||||
return doi;
|
||||
} else {
|
||||
throw new DOIIdentifierException("Trying to create a DOI " +
|
||||
@@ -963,15 +987,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// we did not find the doi in the database or shall reassign it. Before doing so, we should check if a
|
||||
// filter is in place to prevent the creation of new DOIs for certain items.
|
||||
if (skipFilter) {
|
||||
log.warn("loadOrCreateDOI: Skipping default item filter");
|
||||
} else {
|
||||
// Find out if we're allowed to create a DOI
|
||||
// throws an exception if creation of a new DOI is prohibited by a filter
|
||||
checkMintable(context, dso);
|
||||
}
|
||||
// Check if this item is eligible for minting. An IdentifierNotApplicableException will be thrown if not.
|
||||
checkMintable(context, filter, dso);
|
||||
|
||||
// check prefix
|
||||
if (!doiIdentifier.startsWith(this.getPrefix() + "/")) {
|
||||
@@ -984,15 +1001,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
doi = doiService.create(context);
|
||||
}
|
||||
} else {
|
||||
// We need to generate a new DOI. Before doing so, we should check if a
|
||||
// filter is in place to prevent the creation of new DOIs for certain items.
|
||||
if (skipFilter) {
|
||||
log.warn("loadOrCreateDOI: Skipping default item filter");
|
||||
} else {
|
||||
// Find out if we're allowed to create a DOI
|
||||
// throws an exception if creation of a new DOI is prohibited by a filter
|
||||
checkMintable(context, dso);
|
||||
}
|
||||
// Check if this item is eligible for minting. An IdentifierNotApplicableException will be thrown if not.
|
||||
checkMintable(context, filter, dso);
|
||||
|
||||
doi = doiService.create(context);
|
||||
doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
|
||||
@@ -1002,7 +1012,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
// prepare new doiRow
|
||||
doi.setDoi(doiIdentifier);
|
||||
doi.setDSpaceObject(dso);
|
||||
doi.setStatus(null);
|
||||
doi.setStatus(MINTED);
|
||||
try {
|
||||
doiService.update(context, doi);
|
||||
} catch (SQLException e) {
|
||||
@@ -1102,20 +1112,32 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
/**
|
||||
* Checks to see if an item can have a DOI minted, using the configured logical filter
|
||||
* @param context
|
||||
* @param filter Logical item filter to apply
|
||||
* @param dso The item to be evaluated
|
||||
* @throws DOIIdentifierNotApplicableException
|
||||
*/
|
||||
@Override
|
||||
public void checkMintable(Context context, DSpaceObject dso) throws DOIIdentifierNotApplicableException {
|
||||
public void checkMintable(Context context, Filter filter, DSpaceObject dso)
|
||||
throws DOIIdentifierNotApplicableException {
|
||||
if (filter == null) {
|
||||
Filter trueFilter = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(
|
||||
"always_true_filter", TrueFilter.class);
|
||||
// If a null filter was passed, and we have a good default filter to apply, apply it.
|
||||
// Otherwise, set to TrueFilter which means "no filtering"
|
||||
if (this.filter != null) {
|
||||
filter = this.filter;
|
||||
} else {
|
||||
filter = trueFilter;
|
||||
}
|
||||
}
|
||||
// If the check fails, an exception will be thrown to be caught by the calling method
|
||||
if (this.filterService != null && contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
|
||||
if (contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
|
||||
try {
|
||||
boolean result = filterService.getResult(context, (Item) dso);
|
||||
boolean result = filter.getResult(context, (Item) dso);
|
||||
log.debug("Result of filter for " + dso.getHandle() + " is " + result);
|
||||
if (!result) {
|
||||
throw new DOIIdentifierNotApplicableException("Item " + dso.getHandle() +
|
||||
" was evaluated as 'false' by the item filter, not minting");
|
||||
" was evaluated as 'false' by the item filter, not minting");
|
||||
}
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error("Error evaluating item with logical filter: " + e.getLocalizedMessage());
|
||||
@@ -1125,4 +1147,16 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
log.debug("DOI Identifier Provider: filterService is null (ie. don't prevent DOI minting)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if an item can have a DOI minted, using the configured logical filter
|
||||
* @param context
|
||||
* @param dso The item to be evaluated
|
||||
* @throws DOIIdentifierNotApplicableException
|
||||
*/
|
||||
@Override
|
||||
public void checkMintable(Context context, DSpaceObject dso) throws DOIIdentifierNotApplicableException {
|
||||
checkMintable(context, this.filter, dso);
|
||||
}
|
||||
|
||||
}
|
@@ -12,8 +12,9 @@ import java.sql.SQLException;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.TrueFilter;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
/**
|
||||
* This abstract class adds extra method signatures so that implementing IdentifierProviders can
|
||||
@@ -24,26 +25,28 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
*/
|
||||
public abstract class FilteredIdentifierProvider extends IdentifierProvider {
|
||||
|
||||
protected Filter filterService;
|
||||
protected Filter filter = DSpaceServicesFactory.getInstance()
|
||||
.getServiceManager().getServiceByName("always_true_filter", TrueFilter.class);
|
||||
|
||||
/**
|
||||
* Setter for spring to set the filter service from the property in configuration XML
|
||||
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface
|
||||
* Setter for spring to set the default filter from the property in configuration XML
|
||||
* @param filter - an object implementing the org.dspace.content.logic.Filter interface
|
||||
*/
|
||||
@Autowired
|
||||
public void setFilterService(Filter filterService) {
|
||||
this.filterService = filterService;
|
||||
public void setFilter(Filter filter) {
|
||||
if (filter != null) {
|
||||
this.filter = filter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new identifier for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to use for identifier registration
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @return identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract String register(Context context, DSpaceObject dso, boolean skipFilter)
|
||||
public abstract String register(Context context, DSpaceObject dso, Filter filter)
|
||||
throws IdentifierException;
|
||||
|
||||
/**
|
||||
@@ -51,10 +54,10 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @param identifier - String containing the identifier to register
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract void register(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
public abstract void register(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException;
|
||||
|
||||
/**
|
||||
@@ -62,23 +65,23 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this identifier
|
||||
* @param identifier - String containing the identifier to reserve
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
|
||||
* @param filter - Logical item filter to determine whether this identifier should be reserved
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public abstract void reserve(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
public abstract void reserve(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException;
|
||||
|
||||
/**
|
||||
* Mint a new identifier in DSpace - this is usually the first step of registration
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting.
|
||||
* @param filter - Logical item filter to determine whether this identifier should be registered
|
||||
* @return a String containing the new identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract String mint(Context context, DSpaceObject dso, boolean skipFilter) throws IdentifierException;
|
||||
public abstract String mint(Context context, DSpaceObject dso, Filter filter) throws IdentifierException;
|
||||
|
||||
/**
|
||||
* Check configured item filters to see if this identifier is allowed to be minted
|
||||
@@ -88,5 +91,13 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
|
||||
*/
|
||||
public abstract void checkMintable(Context context, DSpaceObject dso) throws IdentifierException;
|
||||
|
||||
/**
|
||||
* Check configured item filters to see if this identifier is allowed to be minted
|
||||
* @param context - DSpace context
|
||||
* @param filter - Logical item filter
|
||||
* @param dso - DSpaceObject to be inspected
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract void checkMintable(Context context, Filter filter, DSpaceObject dso) throws IdentifierException;
|
||||
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ package org.dspace.identifier;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -17,6 +18,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.handle.service.HandleService;
|
||||
import org.dspace.identifier.service.IdentifierService;
|
||||
@@ -44,7 +46,6 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
protected HandleService handleService;
|
||||
|
||||
protected IdentifierServiceImpl() {
|
||||
|
||||
}
|
||||
|
||||
@Autowired(required = true)
|
||||
@@ -98,7 +99,7 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
//We need to commit our context because one of the providers might require the handle created above
|
||||
// Next resolve all other services
|
||||
for (IdentifierProvider service : providers) {
|
||||
@@ -112,11 +113,99 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, Class<? extends Identifier> type, Filter filter)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
boolean registered = false;
|
||||
// Iterate all services and register identifiers as appropriate
|
||||
for (IdentifierProvider service : providers) {
|
||||
if (service.supports(type)) {
|
||||
try {
|
||||
if (service instanceof FilteredIdentifierProvider) {
|
||||
FilteredIdentifierProvider filteredService = (FilteredIdentifierProvider)service;
|
||||
filteredService.register(context, dso, filter);
|
||||
} else {
|
||||
service.register(context, dso);
|
||||
}
|
||||
registered = true;
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!registered) {
|
||||
throw new IdentifierException("Cannot register identifier: Didn't "
|
||||
+ "find a provider that supports this identifier.");
|
||||
}
|
||||
// Update our item / collection / community
|
||||
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, Class<? extends Identifier> type)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
boolean registered = false;
|
||||
// Iterate all services and register identifiers as appropriate
|
||||
for (IdentifierProvider service : providers) {
|
||||
if (service.supports(type)) {
|
||||
try {
|
||||
service.register(context, dso);
|
||||
registered = true;
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!registered) {
|
||||
throw new IdentifierException("Cannot register identifier: Didn't "
|
||||
+ "find a provider that supports this identifier.");
|
||||
}
|
||||
// Update our item / collection / community
|
||||
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, Map<Class<? extends Identifier>, Filter> typeFilters)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
// Iterate all services and register identifiers as appropriate
|
||||
for (IdentifierProvider service : providers) {
|
||||
try {
|
||||
// If the service supports filtering, look through the map and the first supported class
|
||||
// we find, set the filter and break. If no filter was seen for this type, just let the provider
|
||||
// use its own implementation.
|
||||
if (service instanceof FilteredIdentifierProvider) {
|
||||
FilteredIdentifierProvider filteredService = (FilteredIdentifierProvider)service;
|
||||
Filter filter = null;
|
||||
for (Class<? extends Identifier> type : typeFilters.keySet()) {
|
||||
if (filteredService.supports(type)) {
|
||||
filter = typeFilters.get(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filter != null) {
|
||||
// Pass the found filter to the provider
|
||||
filteredService.register(context, dso, filter);
|
||||
} else {
|
||||
// Let the provider use the default filter / behaviour
|
||||
filteredService.register(context, dso);
|
||||
}
|
||||
} else {
|
||||
service.register(context, dso);
|
||||
}
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
// Update our item / collection / community
|
||||
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject object, String identifier)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
//We need to commit our context because one of the providers might require the handle created above
|
||||
// Next resolve all other services
|
||||
// Iterate all services and register identifiers as appropriate
|
||||
boolean registered = false;
|
||||
for (IdentifierProvider service : providers) {
|
||||
if (service.supports(identifier)) {
|
||||
@@ -132,7 +221,7 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
throw new IdentifierException("Cannot register identifier: Didn't "
|
||||
+ "find a provider that supports this identifier.");
|
||||
}
|
||||
//Update our item / collection / community
|
||||
// pdate our item / collection / community
|
||||
contentServiceFactory.getDSpaceObjectService(object).update(context, object);
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@ import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.identifier.doi.DOIConnector;
|
||||
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||
@@ -49,7 +50,12 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
protected VersionHistoryService versionHistoryService;
|
||||
|
||||
@Override
|
||||
public String mint(Context context, DSpaceObject dso)
|
||||
public String mint(Context context, DSpaceObject dso) throws IdentifierException {
|
||||
return mint(context, dso, this.filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mint(Context context, DSpaceObject dso, Filter filter)
|
||||
throws IdentifierException {
|
||||
if (!(dso instanceof Item)) {
|
||||
throw new IdentifierException("Currently only Items are supported for DOIs.");
|
||||
@@ -79,6 +85,9 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
+ " with ID " + dso.getID() + ".", ex);
|
||||
}
|
||||
|
||||
// Make a call to the filter here to throw an exception instead of carrying on with removal + creation
|
||||
checkMintable(context, filter, dso);
|
||||
|
||||
// check whether we have a DOI in the metadata and if we have to remove it
|
||||
String metadataDOI = getDOIOutOfObject(dso);
|
||||
if (metadataDOI != null) {
|
||||
@@ -111,7 +120,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
// ensure DOI exists in our database as well and return.
|
||||
// this also checks that the doi is not assigned to another dso already.
|
||||
try {
|
||||
loadOrCreateDOI(context, dso, versionedDOI);
|
||||
loadOrCreateDOI(context, dso, versionedDOI, filter);
|
||||
} catch (SQLException ex) {
|
||||
log.error(
|
||||
"A problem with the database connection occurd while processing DOI " + versionedDOI + ".", ex);
|
||||
@@ -127,7 +136,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
// if we have a history, we have a item
|
||||
doi = makeIdentifierBasedOnHistory(context, dso, history);
|
||||
} else {
|
||||
doi = loadOrCreateDOI(context, dso, null).getDoi();
|
||||
doi = loadOrCreateDOI(context, dso, null, filter).getDoi();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
log.error("SQLException while creating a new DOI: ", ex);
|
||||
@@ -140,7 +149,12 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, String identifier)
|
||||
public void register(Context context, DSpaceObject dso, String identifier) throws IdentifierException {
|
||||
register(context, dso, identifier, this.filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, String identifier, Filter filter)
|
||||
throws IdentifierException {
|
||||
if (!(dso instanceof Item)) {
|
||||
throw new IdentifierException("Currently only Items are supported for DOIs.");
|
||||
@@ -220,8 +234,14 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
return doiPostfix;
|
||||
}
|
||||
|
||||
// Should never return null!
|
||||
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history)
|
||||
throws AuthorizeException, SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
return makeIdentifierBasedOnHistory(context, dso, history, this.filter);
|
||||
}
|
||||
|
||||
// Should never return null!
|
||||
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history,
|
||||
Filter filter)
|
||||
throws AuthorizeException, SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
// Mint foreach new version an identifier like: 12345/100.versionNumber
|
||||
// use the bare handle (g.e. 12345/100) for the first version.
|
||||
@@ -244,6 +264,9 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
}
|
||||
|
||||
if (previousVersionDOI == null) {
|
||||
// Before continuing with any new DOI creation, apply the filter
|
||||
checkMintable(context, filter, dso);
|
||||
|
||||
// We need to generate a new DOI.
|
||||
DOI doi = doiService.create(context);
|
||||
|
||||
@@ -269,7 +292,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber()));
|
||||
}
|
||||
|
||||
loadOrCreateDOI(context, dso, identifier);
|
||||
loadOrCreateDOI(context, dso, identifier, filter);
|
||||
return identifier;
|
||||
}
|
||||
|
||||
|
@@ -7,22 +7,32 @@
|
||||
*/
|
||||
package org.dspace.identifier.doi;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.FilterUtils;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.event.Consumer;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.identifier.DOI;
|
||||
import org.dspace.identifier.DOIIdentifierProvider;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.IdentifierNotFoundException;
|
||||
import org.dspace.identifier.IdentifierNotApplicableException;
|
||||
import org.dspace.identifier.factory.IdentifierServiceFactory;
|
||||
import org.dspace.identifier.service.DOIService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.workflow.factory.WorkflowServiceFactory;
|
||||
|
||||
/**
|
||||
* @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de)
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class DOIConsumer implements Consumer {
|
||||
/**
|
||||
@@ -30,12 +40,15 @@ public class DOIConsumer implements Consumer {
|
||||
*/
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DOIConsumer.class);
|
||||
|
||||
ConfigurationService configurationService;
|
||||
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
// nothing to do
|
||||
// we can ask spring to give as a properly setuped instance of
|
||||
// DOIIdentifierProvider. Doing so we don't have to configure it and
|
||||
// can load it in consume method as this is not very expensive.
|
||||
configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
}
|
||||
|
||||
@@ -62,36 +75,73 @@ public class DOIConsumer implements Consumer {
|
||||
return;
|
||||
}
|
||||
Item item = (Item) dso;
|
||||
|
||||
if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null
|
||||
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) {
|
||||
// ignore workflow and workspace items, DOI will be minted when item is installed
|
||||
return;
|
||||
DOIIdentifierProvider provider = new DSpace().getSingletonService(DOIIdentifierProvider.class);
|
||||
boolean inProgress = (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item)
|
||||
!= null || WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null);
|
||||
boolean identifiersInSubmission = configurationService.getBooleanProperty("identifiers.submission.register",
|
||||
false);
|
||||
DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();
|
||||
Filter workspaceFilter = null;
|
||||
if (identifiersInSubmission) {
|
||||
workspaceFilter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter.workspace");
|
||||
}
|
||||
|
||||
DOIIdentifierProvider provider = new DSpace().getSingletonService(
|
||||
DOIIdentifierProvider.class);
|
||||
|
||||
String doi = null;
|
||||
if (inProgress && !identifiersInSubmission) {
|
||||
// ignore workflow and workspace items, DOI will be minted and updated when item is installed
|
||||
// UNLESS special pending filter is set
|
||||
return;
|
||||
}
|
||||
DOI doi = null;
|
||||
try {
|
||||
doi = provider.lookup(ctx, dso);
|
||||
} catch (IdentifierNotFoundException ex) {
|
||||
doi = doiService.findDOIByDSpaceObject(ctx, dso);
|
||||
} catch (SQLException ex) {
|
||||
// nothing to do here, next if clause will stop us from processing
|
||||
// items without dois.
|
||||
}
|
||||
if (doi == null) {
|
||||
log.debug("DOIConsumer cannot handles items without DOIs, skipping: "
|
||||
+ event.toString());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
provider.updateMetadata(ctx, dso, doi);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// should not happen, as we got the DOI from the DOIProvider
|
||||
log.warn("DOIConsumer caught an IdentifierException.", ex);
|
||||
} catch (IdentifierException ex) {
|
||||
log.warn("DOIConsumer cannot update metadata for Item with ID "
|
||||
+ item.getID() + " and DOI " + doi + ".", ex);
|
||||
// No DOI. The only time something should be minted is if we have enabled submission reg'n and
|
||||
// it passes the workspace filter. We also need to update status to PENDING straight after.
|
||||
if (inProgress) {
|
||||
provider.mint(ctx, dso, workspaceFilter);
|
||||
DOI newDoi = doiService.findDOIByDSpaceObject(ctx, dso);
|
||||
if (newDoi != null) {
|
||||
newDoi.setStatus(DOIIdentifierProvider.PENDING);
|
||||
doiService.update(ctx, newDoi);
|
||||
}
|
||||
} else {
|
||||
log.debug("DOIConsumer cannot handles items without DOIs, skipping: " + event.toString());
|
||||
}
|
||||
} else {
|
||||
// If in progress, we can also switch PENDING and MINTED status depending on the latest filter
|
||||
// evaluation
|
||||
if (inProgress) {
|
||||
try {
|
||||
// Check the filter
|
||||
provider.checkMintable(ctx, workspaceFilter, dso);
|
||||
// If we made it here, the existing doi should be back to PENDING
|
||||
if (DOIIdentifierProvider.MINTED.equals(doi.getStatus())) {
|
||||
doi.setStatus(DOIIdentifierProvider.PENDING);
|
||||
}
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
// Set status to MINTED if configured to downgrade existing DOIs
|
||||
if (configurationService
|
||||
.getBooleanProperty("identifiers.submission.strip_pending_during_submission", true)) {
|
||||
doi.setStatus(DOIIdentifierProvider.MINTED);
|
||||
}
|
||||
}
|
||||
doiService.update(ctx, doi);
|
||||
} else {
|
||||
try {
|
||||
provider.updateMetadata(ctx, dso, doi.getDoi());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// should not happen, as we got the DOI from the DOIProvider
|
||||
log.warn("DOIConsumer caught an IdentifierException.", ex);
|
||||
} catch (IdentifierException ex) {
|
||||
log.warn("DOIConsumer cannot update metadata for Item with ID "
|
||||
+ item.getID() + " and DOI " + doi + ".", ex);
|
||||
}
|
||||
}
|
||||
ctx.commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,9 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.FilterUtils;
|
||||
import org.dspace.content.logic.TrueFilter;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
@@ -61,7 +64,8 @@ public class DOIOrganiser {
|
||||
protected ItemService itemService;
|
||||
protected DOIService doiService;
|
||||
protected ConfigurationService configurationService;
|
||||
protected boolean skipFilter;
|
||||
// This filter will override the default provider filter / behaviour
|
||||
protected Filter filter;
|
||||
|
||||
/**
|
||||
* Constructor to be called within the main() method
|
||||
@@ -76,7 +80,8 @@ public class DOIOrganiser {
|
||||
this.itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
this.doiService = IdentifierServiceFactory.getInstance().getDOIService();
|
||||
this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
this.skipFilter = false;
|
||||
this.filter = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(
|
||||
"always_true_filter", TrueFilter.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,12 +126,13 @@ public class DOIOrganiser {
|
||||
"Perform online metadata update for all identifiers queued for metadata update.");
|
||||
options.addOption("d", "delete-all", false,
|
||||
"Perform online deletion for all identifiers queued for deletion.");
|
||||
|
||||
options.addOption("q", "quiet", false,
|
||||
"Turn the command line output off.");
|
||||
|
||||
options.addOption(null, "skip-filter", false,
|
||||
"Skip the configured item filter when registering or reserving.");
|
||||
Option filterDoi = Option.builder().optionalArg(true).longOpt("filter").hasArg().argName("filterName")
|
||||
.desc("Use the specified filter name instead of the provider's filter. Defaults to a special " +
|
||||
"'always true' filter to force operations").build();
|
||||
options.addOption(filterDoi);
|
||||
|
||||
Option registerDoi = Option.builder()
|
||||
.longOpt("register-doi")
|
||||
@@ -203,10 +209,12 @@ public class DOIOrganiser {
|
||||
}
|
||||
|
||||
DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();
|
||||
// Should we skip the filter?
|
||||
if (line.hasOption("skip-filter")) {
|
||||
System.out.println("Skipping the item filter");
|
||||
organiser.skipFilter = true;
|
||||
// Do we get a filter?
|
||||
if (line.hasOption("filter")) {
|
||||
String filter = line.getOptionValue("filter");
|
||||
if (null != filter) {
|
||||
organiser.filter = FilterUtils.getFilterFromConfiguration(filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (line.hasOption('s')) {
|
||||
@@ -394,19 +402,18 @@ public class DOIOrganiser {
|
||||
/**
|
||||
* Register DOI with the provider
|
||||
* @param doiRow - doi to register
|
||||
* @param skipFilter - whether filters should be skipped before registration
|
||||
* @param filter - logical item filter to override
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void register(DOI doiRow, boolean skipFilter) throws SQLException, DOIIdentifierException {
|
||||
public void register(DOI doiRow, Filter filter) throws SQLException, DOIIdentifierException {
|
||||
DSpaceObject dso = doiRow.getDSpaceObject();
|
||||
if (Constants.ITEM != dso.getType()) {
|
||||
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
|
||||
}
|
||||
|
||||
try {
|
||||
provider.registerOnline(context, dso,
|
||||
DOI.SCHEME + doiRow.getDoi());
|
||||
provider.registerOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), filter);
|
||||
|
||||
if (!quiet) {
|
||||
System.out.println("This identifier: "
|
||||
@@ -466,29 +473,23 @@ public class DOIOrganiser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register DOI with the provider, always applying (ie. never skipping) any configured filters
|
||||
* Register DOI with the provider
|
||||
* @param doiRow - doi to register
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void register(DOI doiRow) throws SQLException, DOIIdentifierException {
|
||||
if (this.skipFilter) {
|
||||
System.out.println("Skipping the filter for " + doiRow.getDoi());
|
||||
}
|
||||
register(doiRow, this.skipFilter);
|
||||
register(doiRow, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve DOI with the provider, always applying (ie. never skipping) any configured filters
|
||||
* Reserve DOI with the provider,
|
||||
* @param doiRow - doi to reserve
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void reserve(DOI doiRow) {
|
||||
if (this.skipFilter) {
|
||||
System.out.println("Skipping the filter for " + doiRow.getDoi());
|
||||
}
|
||||
reserve(doiRow, this.skipFilter);
|
||||
reserve(doiRow, this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,14 +498,14 @@ public class DOIOrganiser {
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void reserve(DOI doiRow, boolean skipFilter) {
|
||||
public void reserve(DOI doiRow, Filter filter) {
|
||||
DSpaceObject dso = doiRow.getDSpaceObject();
|
||||
if (Constants.ITEM != dso.getType()) {
|
||||
throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only.");
|
||||
}
|
||||
|
||||
try {
|
||||
provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), skipFilter);
|
||||
provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), filter);
|
||||
|
||||
if (!quiet) {
|
||||
System.out.println("This identifier : " + DOI.SCHEME + doiRow.getDoi() + " is successfully reserved.");
|
||||
@@ -699,7 +700,7 @@ public class DOIOrganiser {
|
||||
|
||||
//Check if this Item has an Identifier, mint one if it doesn't
|
||||
if (null == doiRow) {
|
||||
doi = provider.mint(context, dso, this.skipFilter);
|
||||
doi = provider.mint(context, dso, this.filter);
|
||||
doiRow = doiService.findByDoi(context,
|
||||
doi.substring(DOI.SCHEME.length()));
|
||||
return doiRow;
|
||||
@@ -723,7 +724,7 @@ public class DOIOrganiser {
|
||||
doiRow = doiService.findDOIByDSpaceObject(context, dso);
|
||||
|
||||
if (null == doiRow) {
|
||||
doi = provider.mint(context, dso, this.skipFilter);
|
||||
doi = provider.mint(context, dso, this.filter);
|
||||
doiRow = doiService.findByDoi(context,
|
||||
doi.substring(DOI.SCHEME.length()));
|
||||
}
|
||||
|
@@ -9,9 +9,11 @@ package org.dspace.identifier.service;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.identifier.Identifier;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
@@ -103,6 +105,52 @@ public interface IdentifierService {
|
||||
*/
|
||||
void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Register identifiers for a DSO, with a map of logical filters for each Identifier class to apply
|
||||
* at the time of local registration.
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param dso DSpace object to be registered
|
||||
* @param typeFilters If a service supports a given Identifier implementation, apply the associated filter
|
||||
* @throws AuthorizeException if authorization error
|
||||
* @throws SQLException if database error
|
||||
* @throws IdentifierException if identifier error
|
||||
*/
|
||||
void register(Context context, DSpaceObject dso, Map<Class<? extends Identifier>, Filter> typeFilters)
|
||||
throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Register identifier(s) for the given DSO just with providers that support that Identifier class, and
|
||||
* apply the given filter if that provider extends FilteredIdentifierProvider
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param dso DSpace object to be registered
|
||||
* @param type Type of identifier to register
|
||||
* @param filter If a service supports a given Identifier implementation, apply this specific filter
|
||||
* @throws AuthorizeException if authorization error
|
||||
* @throws SQLException if database error
|
||||
* @throws IdentifierException if identifier error
|
||||
*/
|
||||
void register(Context context, DSpaceObject dso, Class<? extends Identifier> type, Filter filter)
|
||||
throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Register identifier(s) for the given DSO just with providers that support that Identifier class, and
|
||||
* apply the given filter if that provider extends FilteredIdentifierProvider
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param dso DSpace object to be registered
|
||||
* @param type Type of identifier to register
|
||||
* @throws AuthorizeException if authorization error
|
||||
* @throws SQLException if database error
|
||||
* @throws IdentifierException if identifier error
|
||||
*/
|
||||
void register(Context context, DSpaceObject dso, Class<? extends Identifier> type)
|
||||
throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
* Used to Register a specific Identifier (for example a Handle, hdl:1234.5/6).
|
||||
* The provider is responsible for detecting and processing the appropriate
|
||||
|
@@ -8,6 +8,7 @@
|
||||
package org.dspace.scripts;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -36,7 +37,9 @@ public class ScriptServiceImpl implements ScriptService {
|
||||
@Override
|
||||
public List<ScriptConfiguration> getScriptConfigurations(Context context) {
|
||||
return serviceManager.getServicesByType(ScriptConfiguration.class).stream().filter(
|
||||
scriptConfiguration -> scriptConfiguration.isAllowedToExecute(context)).collect(Collectors.toList());
|
||||
scriptConfiguration -> scriptConfiguration.isAllowedToExecute(context))
|
||||
.sorted(Comparator.comparing(ScriptConfiguration::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -303,6 +303,10 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini
|
||||
commitCounter++;
|
||||
if (commitCounter % 100 == 0) {
|
||||
context.dispatchEvents();
|
||||
// Commit actual changes to DB after dispatch events
|
||||
System.out.print("Performing incremental commit to the database...");
|
||||
context.commit();
|
||||
System.out.println(" Incremental commit done!");
|
||||
}
|
||||
|
||||
context.uncacheEntity(bitstream);
|
||||
|
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.subscriptions;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.apache.commons.lang.StringUtils.EMPTY;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.crosswalk.StreamDisseminationCrosswalk;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.Email;
|
||||
import org.dspace.core.I18nUtil;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.subscriptions.service.SubscriptionGenerator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Implementation class of SubscriptionGenerator
|
||||
* which will handle the logic of sending the emails
|
||||
* in case of 'content' subscriptionType
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ContentGenerator implements SubscriptionGenerator<IndexableObject> {
|
||||
|
||||
private final Logger log = LogManager.getLogger(ContentGenerator.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, StreamDisseminationCrosswalk> entityType2Disseminator = new HashMap();
|
||||
|
||||
@Autowired
|
||||
private ItemService itemService;
|
||||
|
||||
@Override
|
||||
public void notifyForSubscriptions(Context context, EPerson ePerson,
|
||||
List<IndexableObject> indexableComm,
|
||||
List<IndexableObject> indexableColl) {
|
||||
try {
|
||||
if (Objects.nonNull(ePerson)) {
|
||||
Locale supportedLocale = I18nUtil.getEPersonLocale(ePerson);
|
||||
Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "subscriptions_content"));
|
||||
email.addRecipient(ePerson.getEmail());
|
||||
email.addArgument(generateBodyMail(context, indexableComm));
|
||||
email.addArgument(generateBodyMail(context, indexableColl));
|
||||
email.send();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
log.warn("Cannot email user eperson_id: {} eperson_email: {}", ePerson::getID, ePerson::getEmail);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateBodyMail(Context context, List<IndexableObject> indexableObjects) {
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write("\n".getBytes(UTF_8));
|
||||
if (indexableObjects.size() > 0) {
|
||||
for (IndexableObject indexableObject : indexableObjects) {
|
||||
out.write("\n".getBytes(UTF_8));
|
||||
Item item = (Item) indexableObject.getIndexedObject();
|
||||
String entityType = itemService.getEntityTypeLabel(item);
|
||||
Optional.ofNullable(entityType2Disseminator.get(entityType))
|
||||
.orElseGet(() -> entityType2Disseminator.get("Item"))
|
||||
.disseminate(context, item, out);
|
||||
}
|
||||
return out.toString();
|
||||
} else {
|
||||
out.write("No items".getBytes(UTF_8));
|
||||
}
|
||||
return out.toString();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
public void setEntityType2Disseminator(Map<String, StreamDisseminationCrosswalk> entityType2Disseminator) {
|
||||
this.entityType2Disseminator = entityType2Disseminator;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* 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.subscriptions;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.FrequencyType;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* Implementation of {@link DSpaceRunnable} to find subscribed objects and send notification mails about them
|
||||
*
|
||||
* @author alba aliu
|
||||
*/
|
||||
public class SubscriptionEmailNotification
|
||||
extends DSpaceRunnable<SubscriptionEmailNotificationConfiguration<SubscriptionEmailNotification>> {
|
||||
|
||||
private Context context;
|
||||
private SubscriptionEmailNotificationService subscriptionEmailNotificationService;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public SubscriptionEmailNotificationConfiguration<SubscriptionEmailNotification> getScriptConfiguration() {
|
||||
return new DSpace().getServiceManager().getServiceByName("subscription-send",
|
||||
SubscriptionEmailNotificationConfiguration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() throws ParseException {
|
||||
this.subscriptionEmailNotificationService = new DSpace().getServiceManager().getServiceByName(
|
||||
SubscriptionEmailNotificationServiceImpl.class.getName(), SubscriptionEmailNotificationServiceImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalRun() throws Exception {
|
||||
assignCurrentUserInContext();
|
||||
assignSpecialGroupsInContext();
|
||||
String frequencyOption = commandLine.getOptionValue("f");
|
||||
if (StringUtils.isBlank(frequencyOption)) {
|
||||
throw new IllegalArgumentException("Option --frequency (-f) must be set");
|
||||
}
|
||||
|
||||
if (!FrequencyType.isSupportedFrequencyType(frequencyOption)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Option f must be one of following values D(Day), W(Week) or M(Month)");
|
||||
}
|
||||
subscriptionEmailNotificationService.perform(getContext(), handler, "content", frequencyOption);
|
||||
}
|
||||
|
||||
private void assignCurrentUserInContext() throws SQLException {
|
||||
context = new Context();
|
||||
UUID uuid = getEpersonIdentifier();
|
||||
if (Objects.nonNull(uuid)) {
|
||||
EPerson ePerson = EPersonServiceFactory.getInstance().getEPersonService().find(context, uuid);
|
||||
context.setCurrentUser(ePerson);
|
||||
}
|
||||
}
|
||||
|
||||
private void assignSpecialGroupsInContext() throws SQLException {
|
||||
for (UUID uuid : handler.getSpecialGroups()) {
|
||||
context.setSpecialGroup(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public SubscriptionEmailNotificationService getSubscriptionEmailNotificationService() {
|
||||
return subscriptionEmailNotificationService;
|
||||
}
|
||||
|
||||
public void setSubscriptionEmailNotificationService(SubscriptionEmailNotificationService notificationService) {
|
||||
this.subscriptionEmailNotificationService = notificationService;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void setContext(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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.subscriptions;
|
||||
|
||||
/**
|
||||
* Extension of {@link SubscriptionEmailNotification} for CLI.
|
||||
*/
|
||||
public class SubscriptionEmailNotificationCli extends SubscriptionEmailNotification {
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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.subscriptions;
|
||||
|
||||
/**
|
||||
* Extension of {@link SubscriptionEmailNotificationCli} for CLI.
|
||||
*/
|
||||
public class SubscriptionEmailNotificationCliScriptConfiguration<T extends SubscriptionEmailNotificationCli>
|
||||
extends SubscriptionEmailNotificationConfiguration<T> {
|
||||
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.subscriptions;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.dspace.authorize.AuthorizeServiceImpl;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Implementation of {@link DSpaceRunnable} to find subscribed objects and send notification mails about them
|
||||
*/
|
||||
public class SubscriptionEmailNotificationConfiguration<T
|
||||
extends SubscriptionEmailNotification> extends ScriptConfiguration<T> {
|
||||
|
||||
private Class<T> dspaceRunnableClass;
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceImpl authorizeService;
|
||||
|
||||
@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 (Objects.isNull(options)) {
|
||||
Options options = new Options();
|
||||
options.addOption("f", "frequency", true,
|
||||
"Subscription frequency. Valid values include: D (Day), W (Week) and M (Month)");
|
||||
options.getOption("f").setRequired(true);
|
||||
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,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.subscriptions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.scripts.handler.DSpaceRunnableHandler;
|
||||
|
||||
/**
|
||||
* Service interface class for the subscription e-mail notification services
|
||||
*
|
||||
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
|
||||
*/
|
||||
public interface SubscriptionEmailNotificationService {
|
||||
|
||||
/**
|
||||
* Performs sending of e-mails to subscribers by frequency value and SubscriptionType
|
||||
*
|
||||
* @param context DSpace context object
|
||||
* @param handler Applicable DSpaceRunnableHandler
|
||||
* @param subscriptionType Currently supported only "content"
|
||||
* @param frequency Valid values include: D (Day), W (Week) and M (Month)
|
||||
*/
|
||||
public void perform(Context context, DSpaceRunnableHandler handler, String subscriptionType, String frequency);
|
||||
|
||||
/**
|
||||
* returns a set of supported SubscriptionTypes
|
||||
*/
|
||||
public Set<String> getSupportedSubscriptionTypes();
|
||||
|
||||
}
|
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* 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.subscriptions;
|
||||
|
||||
import static org.dspace.core.Constants.COLLECTION;
|
||||
import static org.dspace.core.Constants.COMMUNITY;
|
||||
import static org.dspace.core.Constants.READ;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Subscription;
|
||||
import org.dspace.eperson.service.SubscribeService;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.scripts.handler.DSpaceRunnableHandler;
|
||||
import org.dspace.subscriptions.service.DSpaceObjectUpdates;
|
||||
import org.dspace.subscriptions.service.SubscriptionGenerator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Implementation of {@link DSpaceRunnable} to find subscribed objects and send notification mails about them
|
||||
*
|
||||
* @author alba aliu
|
||||
*/
|
||||
public class SubscriptionEmailNotificationServiceImpl implements SubscriptionEmailNotificationService {
|
||||
|
||||
private static final Logger log = LogManager.getLogger(SubscriptionEmailNotificationServiceImpl.class);
|
||||
|
||||
private Map<String, DSpaceObjectUpdates> contentUpdates = new HashMap<>();
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Map<String, SubscriptionGenerator> subscriptionType2generators = new HashMap<>();
|
||||
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
@Autowired
|
||||
private SubscribeService subscribeService;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public SubscriptionEmailNotificationServiceImpl(Map<String, DSpaceObjectUpdates> contentUpdates,
|
||||
Map<String, SubscriptionGenerator> subscriptionType2generators) {
|
||||
this.contentUpdates = contentUpdates;
|
||||
this.subscriptionType2generators = subscriptionType2generators;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void perform(Context context, DSpaceRunnableHandler handler, String subscriptionType, String frequency) {
|
||||
List<IndexableObject> communityItems = new ArrayList<>();
|
||||
List<IndexableObject> collectionsItems = new ArrayList<>();
|
||||
try {
|
||||
List<Subscription> subscriptions =
|
||||
findAllSubscriptionsBySubscriptionTypeAndFrequency(context, subscriptionType, frequency);
|
||||
// Here is verified if SubscriptionType is "content" Or "statistics" as them are configured
|
||||
if (subscriptionType2generators.keySet().contains(subscriptionType)) {
|
||||
// the list of the person who has subscribed
|
||||
int iterator = 0;
|
||||
for (Subscription subscription : subscriptions) {
|
||||
DSpaceObject dSpaceObject = subscription.getDSpaceObject();
|
||||
EPerson ePerson = subscription.getEPerson();
|
||||
|
||||
if (!authorizeService.authorizeActionBoolean(context, ePerson, dSpaceObject, READ, true)) {
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dSpaceObject.getType() == COMMUNITY) {
|
||||
List<IndexableObject> indexableCommunityItems = contentUpdates
|
||||
.get(Community.class.getSimpleName().toLowerCase())
|
||||
.findUpdates(context, dSpaceObject, frequency);
|
||||
communityItems.addAll(getItems(context, ePerson, indexableCommunityItems));
|
||||
} else if (dSpaceObject.getType() == COLLECTION) {
|
||||
List<IndexableObject> indexableCollectionItems = contentUpdates
|
||||
.get(Collection.class.getSimpleName().toLowerCase())
|
||||
.findUpdates(context, dSpaceObject, frequency);
|
||||
collectionsItems.addAll(getItems(context, ePerson, indexableCollectionItems));
|
||||
} else {
|
||||
log.warn("found an invalid DSpace Object type ({}) among subscriptions to send",
|
||||
dSpaceObject.getType());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iterator < subscriptions.size() - 1) {
|
||||
// as the subscriptions are ordered by eperson id, so we send them by ePerson
|
||||
if (ePerson.equals(subscriptions.get(iterator + 1).getEPerson())) {
|
||||
iterator++;
|
||||
continue;
|
||||
} else {
|
||||
subscriptionType2generators.get(subscriptionType)
|
||||
.notifyForSubscriptions(context, ePerson, communityItems, collectionsItems);
|
||||
communityItems.clear();
|
||||
collectionsItems.clear();
|
||||
}
|
||||
} else {
|
||||
//in the end of the iteration
|
||||
subscriptionType2generators.get(subscriptionType)
|
||||
.notifyForSubscriptions(context, ePerson, communityItems, collectionsItems);
|
||||
}
|
||||
iterator++;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Currently this SubscriptionType:" + subscriptionType +
|
||||
" is not supported!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
handler.handleException(e);
|
||||
context.abort();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private List<IndexableObject> getItems(Context context, EPerson ePerson, List<IndexableObject> indexableItems)
|
||||
throws SQLException {
|
||||
List<IndexableObject> items = new ArrayList<IndexableObject>();
|
||||
for (IndexableObject indexableitem : indexableItems) {
|
||||
Item item = (Item) indexableitem.getIndexedObject();
|
||||
if (authorizeService.authorizeActionBoolean(context, ePerson, item, READ, true)) {
|
||||
items.add(indexableitem);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all Subscriptions by subscriptionType and frequency ordered by ePerson ID
|
||||
* if there are none it returns an empty list
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param subscriptionType Could be "content" or "statistics". NOTE: in DSpace we have only "content"
|
||||
* @param frequency Could be "D" stand for Day, "W" stand for Week, and "M" stand for Month
|
||||
* @return
|
||||
*/
|
||||
private List<Subscription> findAllSubscriptionsBySubscriptionTypeAndFrequency(Context context,
|
||||
String subscriptionType, String frequency) {
|
||||
try {
|
||||
return subscribeService.findAllSubscriptionsBySubscriptionTypeAndFrequency(context, subscriptionType,
|
||||
frequency)
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(s -> s.getEPerson().getID()))
|
||||
.collect(Collectors.toList());
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return new ArrayList<Subscription>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedSubscriptionTypes() {
|
||||
return subscriptionType2generators.keySet();
|
||||
}
|
||||
|
||||
}
|
@@ -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.subscriptions.objectupdates;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverResult;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.discovery.SearchService;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.eperson.FrequencyType;
|
||||
import org.dspace.subscriptions.service.DSpaceObjectUpdates;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Class which will be used to find
|
||||
* all collection objects updated related with subscribed DSO
|
||||
*
|
||||
* @author Alba Aliu
|
||||
*/
|
||||
public class CollectionUpdates implements DSpaceObjectUpdates {
|
||||
|
||||
@Autowired
|
||||
private SearchService searchService;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<IndexableObject> findUpdates(Context context, DSpaceObject dSpaceObject, String frequency)
|
||||
throws SearchServiceException {
|
||||
DiscoverQuery discoverQuery = new DiscoverQuery();
|
||||
getDefaultFilterQueries().stream().forEach(fq -> discoverQuery.addFilterQueries(fq));
|
||||
discoverQuery.addFilterQueries("location.coll:(" + dSpaceObject.getID() + ")");
|
||||
discoverQuery.addFilterQueries("lastModified:" + FrequencyType.findLastFrequency(frequency));
|
||||
DiscoverResult discoverResult = searchService.search(context, discoverQuery);
|
||||
return discoverResult.getIndexableObjects();
|
||||
}
|
||||
|
||||
}
|
@@ -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.subscriptions.objectupdates;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverResult;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.discovery.SearchService;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.eperson.FrequencyType;
|
||||
import org.dspace.subscriptions.service.DSpaceObjectUpdates;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Class which will be used to find
|
||||
* all community objects updated related with subscribed DSO
|
||||
*
|
||||
* @author Alba Aliu
|
||||
*/
|
||||
public class CommunityUpdates implements DSpaceObjectUpdates {
|
||||
|
||||
@Autowired
|
||||
private SearchService searchService;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<IndexableObject> findUpdates(Context context, DSpaceObject dSpaceObject, String frequency)
|
||||
throws SearchServiceException {
|
||||
DiscoverQuery discoverQuery = new DiscoverQuery();
|
||||
getDefaultFilterQueries().stream().forEach(fq -> discoverQuery.addFilterQueries(fq));
|
||||
discoverQuery.addFilterQueries("location.comm:(" + dSpaceObject.getID() + ")");
|
||||
discoverQuery.addFilterQueries("lastModified:" + FrequencyType.findLastFrequency(frequency));
|
||||
DiscoverResult discoverResult = searchService.search(context, discoverQuery);
|
||||
return discoverResult.getIndexableObjects();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.subscriptions.service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
|
||||
/**
|
||||
* Interface class which will be used to find all objects updated related with subscribed DSO
|
||||
*
|
||||
* @author Alba Aliu
|
||||
*/
|
||||
public interface DSpaceObjectUpdates {
|
||||
|
||||
/**
|
||||
* Send an email to some addresses, concerning a Subscription, using a given dso.
|
||||
*
|
||||
* @param context current DSpace session.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<IndexableObject> findUpdates(Context context, DSpaceObject dSpaceObject, String frequency)
|
||||
throws SearchServiceException;
|
||||
|
||||
default List<String> getDefaultFilterQueries() {
|
||||
return Arrays.asList("search.resourcetype:" + Item.class.getSimpleName(),
|
||||
"-discoverable:" + false,
|
||||
"-withdrawn:" + true);
|
||||
}
|
||||
|
||||
}
|
@@ -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.subscriptions.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
|
||||
/**
|
||||
* Interface Class which will be used to send email notifications to ePerson
|
||||
* containing information for all list of objects.
|
||||
*
|
||||
* @author Alba Aliu
|
||||
*/
|
||||
public interface SubscriptionGenerator<T> {
|
||||
|
||||
public void notifyForSubscriptions(Context c, EPerson ePerson, List<T> comm, List<T> coll);
|
||||
|
||||
}
|
@@ -18,6 +18,7 @@ import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
|
||||
/**
|
||||
* Service interface class for the WorkflowService framework.
|
||||
@@ -100,6 +101,9 @@ public interface WorkflowService<T extends WorkflowItem> {
|
||||
String rejection_message)
|
||||
throws SQLException, AuthorizeException, IOException;
|
||||
|
||||
public void restartWorkflow(Context context, XmlWorkflowItem wi, EPerson decliner, String provenance)
|
||||
throws SQLException, AuthorizeException, IOException, WorkflowException;
|
||||
|
||||
public String getMyDSpaceLink();
|
||||
|
||||
public void deleteCollection(Context context, Collection collection)
|
||||
|
@@ -41,6 +41,9 @@ public class Role implements BeanNameAware {
|
||||
@Autowired
|
||||
private WorkflowItemRoleService workflowItemRoleService;
|
||||
|
||||
// Whether or not to delete temporary group made attached to the WorkflowItemRole for this role in AutoAssignAction
|
||||
private boolean deleteTemporaryGroup = false;
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
@@ -153,4 +156,17 @@ public class Role implements BeanNameAware {
|
||||
public void setInternal(boolean internal) {
|
||||
isInternal = internal;
|
||||
}
|
||||
|
||||
public boolean isDeleteTemporaryGroup() {
|
||||
return deleteTemporaryGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for config that indicated whether or not to delete temporary group made attached to the
|
||||
* WorkflowItemRole for this role in AutoAssignAction
|
||||
* @param deleteTemporaryGroup
|
||||
*/
|
||||
public void setDeleteTemporaryGroup(boolean deleteTemporaryGroup) {
|
||||
this.deleteTemporaryGroup = deleteTemporaryGroup;
|
||||
}
|
||||
}
|
||||
|
@@ -1076,6 +1076,53 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService {
|
||||
return wsi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restartWorkflow(Context context, XmlWorkflowItem wi, EPerson decliner, String provenance)
|
||||
throws SQLException, AuthorizeException, IOException, WorkflowException {
|
||||
if (!authorizeService.isAdmin(context)) {
|
||||
throw new AuthorizeException("You must be an admin to restart a workflow");
|
||||
}
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
// rejection provenance
|
||||
Item myitem = wi.getItem();
|
||||
|
||||
// Here's what happened
|
||||
String provDescription =
|
||||
provenance + " Declined by " + getEPersonName(decliner) + " on " + DCDate.getCurrent().toString() +
|
||||
" (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
itemService
|
||||
.addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(),
|
||||
"description", "provenance", "en", provDescription);
|
||||
|
||||
//Clear any workflow schema related metadata
|
||||
itemService
|
||||
.clearMetadata(context, myitem, WorkflowRequirementsService.WORKFLOW_SCHEMA, Item.ANY, Item.ANY, Item.ANY);
|
||||
|
||||
itemService.update(context, myitem);
|
||||
|
||||
// remove policy for controller
|
||||
removeUserItemPolicies(context, myitem, decliner);
|
||||
revokeReviewerPolicies(context, myitem);
|
||||
|
||||
// convert into personal workspace
|
||||
WorkspaceItem wsi = returnToWorkspace(context, wi);
|
||||
|
||||
// Because of issue of xmlWorkflowItemService not realising wfi wrapper has been deleted
|
||||
context.commit();
|
||||
wsi = context.reloadEntity(wsi);
|
||||
|
||||
log.info(LogHelper.getHeader(context, "decline_workflow", "workflow_item_id="
|
||||
+ wi.getID() + "item_id=" + wi.getItem().getID() + "collection_id=" + wi.getCollection().getID() +
|
||||
"eperson_id=" + decliner.getID()));
|
||||
|
||||
// Restart workflow
|
||||
this.startWithoutNotify(context, wsi);
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the workflow item to the workspace of the submitter. The workflow
|
||||
* item is removed, and a workspace item created.
|
||||
|
@@ -14,10 +14,15 @@ import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.workflow.WorkflowException;
|
||||
import org.dspace.xmlworkflow.RoleMembers;
|
||||
import org.dspace.xmlworkflow.WorkflowConfigurationException;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
|
||||
@@ -37,6 +42,8 @@ public abstract class Action {
|
||||
|
||||
private WorkflowActionConfig parent;
|
||||
private static final String ERROR_FIELDS_ATTRIBUTE = "dspace.workflow.error_fields";
|
||||
private List<String> advancedOptions = new ArrayList<>();
|
||||
private List<ActionAdvancedInfo> advancedInfo = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Called when a workflow item becomes eligible for this Action.
|
||||
@@ -192,4 +199,58 @@ public abstract class Action {
|
||||
//save updated list
|
||||
setErrorFields(request, errorFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of advanced options that the user can select at this action
|
||||
* @return A list of advanced options of this action, resulting in the next step of the workflow
|
||||
*/
|
||||
protected List<String> getAdvancedOptions() {
|
||||
return advancedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Action has advanced options, false if it doesn't
|
||||
* @return true if there are advanced options, false otherwise
|
||||
*/
|
||||
protected boolean isAdvanced() {
|
||||
return !getAdvancedOptions().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of advanced info required by the advanced options
|
||||
* @return A list of advanced info required by the advanced options
|
||||
*/
|
||||
protected List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||
return advancedInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds info in the metadata field dc.description.provenance about item being approved containing in which step
|
||||
* it was approved, which user approved it and the time
|
||||
*
|
||||
* @param c DSpace contect
|
||||
* @param wfi Workflow item we're adding workflow accept provenance on
|
||||
*/
|
||||
public void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
|
||||
//Add the provenance for the accept
|
||||
String now = DCDate.getCurrent().toString();
|
||||
|
||||
// Get user's name + email address
|
||||
String usersName =
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().getEPersonName(c.getCurrentUser());
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by " + usersName + " on "
|
||||
+ now + " (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
c.turnOffAuthorisationSystem();
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||
provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
c.restoreAuthSystemState();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.xmlworkflow.state.actions;
|
||||
|
||||
/**
|
||||
* Interface for the shared properties of an 'advancedInfo' section of an advanced workflow {@link Action}
|
||||
* Implementations of this class will define the specific fields per action that will need to be defined/configured
|
||||
* to pass along this info to REST endpoint
|
||||
*/
|
||||
public abstract class ActionAdvancedInfo {
|
||||
|
||||
protected String type;
|
||||
protected String id;
|
||||
|
||||
protected final static String TYPE_PREFIX = "action_info_";
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = TYPE_PREFIX + type;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the Action id to be set.
|
||||
* This is an MD5 hash of the type and the stringified properties of the advanced info
|
||||
*
|
||||
* @param type The type of this Action to be included in the MD5 hash
|
||||
*/
|
||||
protected abstract void generateId(String type);
|
||||
|
||||
}
|
@@ -69,4 +69,28 @@ public class WorkflowActionConfig {
|
||||
return this.processingAction.getOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of advanced options this user has on this action, resulting in the next step of the workflow
|
||||
* @return A list of advanced options of this action, resulting in the next step of the workflow
|
||||
*/
|
||||
public List<String> getAdvancedOptions() {
|
||||
return this.processingAction.getAdvancedOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean depending on whether this action has advanced options
|
||||
* @return The boolean indicating whether this action has advanced options
|
||||
*/
|
||||
public boolean isAdvanced() {
|
||||
return this.processingAction.isAdvanced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of info for the advanced options this user has on this action
|
||||
* @return a Map of info for the advanced options this user has on this action
|
||||
*/
|
||||
public List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||
return this.processingAction.getAdvancedInfo();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -15,8 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
@@ -34,8 +32,6 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
*/
|
||||
public class AcceptEditRejectAction extends ProcessingAction {
|
||||
|
||||
private static final String SUBMIT_APPROVE = "submit_approve";
|
||||
private static final String SUBMIT_REJECT = "submit_reject";
|
||||
private static final String SUBMITTER_IS_DELETED_PAGE = "submitter_deleted";
|
||||
|
||||
//TODO: rename to AcceptAndEditMetadataAction
|
||||
@@ -53,7 +49,7 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
||||
case SUBMIT_APPROVE:
|
||||
return processAccept(c, wfi);
|
||||
case SUBMIT_REJECT:
|
||||
return processRejectPage(c, wfi, request);
|
||||
return super.processRejectPage(c, wfi, request);
|
||||
case SUBMITTER_IS_DELETED_PAGE:
|
||||
return processSubmitterIsDeletedPage(c, wfi, request);
|
||||
default:
|
||||
@@ -69,33 +65,18 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
||||
options.add(SUBMIT_APPROVE);
|
||||
options.add(SUBMIT_REJECT);
|
||||
options.add(ProcessingAction.SUBMIT_EDIT_METADATA);
|
||||
options.add(RETURN_TO_POOL);
|
||||
return options;
|
||||
}
|
||||
|
||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi)
|
||||
throws SQLException, AuthorizeException {
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
super.addApprovedProvenance(c, wfi);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
}
|
||||
|
||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
String reason = request.getParameter("reason");
|
||||
if (reason == null || 0 == reason.trim().length()) {
|
||||
addErrorField(request, "reason");
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
|
||||
// We have pressed reject, so remove the task the user has & put it back
|
||||
// to a workspace item
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().sendWorkflowItemBackSubmission(c, wfi,
|
||||
c.getCurrentUser(), this.getProvenanceStartId(), reason);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
|
||||
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
if (request.getParameter("submit_delete") != null) {
|
||||
@@ -111,21 +92,4 @@ public class AcceptEditRejectAction extends ProcessingAction {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
//Add the provenance for the accept
|
||||
String now = DCDate.getCurrent().toString();
|
||||
|
||||
// Get user's name + email address
|
||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.getEPersonName(c.getCurrentUser());
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
||||
+ usersName + " on " + now + " (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||
provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
}
|
||||
}
|
||||
|
@@ -14,10 +14,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
@@ -52,7 +49,7 @@ public class FinalEditAction extends ProcessingAction {
|
||||
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||
case SUBMIT_APPROVE:
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
super.addApprovedProvenance(c, wfi);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
default:
|
||||
//We pressed the leave button so return to our submissions page
|
||||
@@ -67,25 +64,8 @@ public class FinalEditAction extends ProcessingAction {
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add(SUBMIT_APPROVE);
|
||||
options.add(ProcessingAction.SUBMIT_EDIT_METADATA);
|
||||
options.add(RETURN_TO_POOL);
|
||||
return options;
|
||||
}
|
||||
|
||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
//Add the provenance for the accept
|
||||
String now = DCDate.getCurrent().toString();
|
||||
|
||||
// Get user's name + email address
|
||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.getEPersonName(c.getCurrentUser());
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
||||
+ usersName + " on " + now + " (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||
provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -7,12 +7,16 @@
|
||||
*/
|
||||
package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.xmlworkflow.service.XmlWorkflowService;
|
||||
import org.dspace.xmlworkflow.state.actions.Action;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
|
||||
@@ -32,9 +36,15 @@ public abstract class ProcessingAction extends Action {
|
||||
protected ClaimedTaskService claimedTaskService;
|
||||
@Autowired(required = true)
|
||||
protected ItemService itemService;
|
||||
@Autowired
|
||||
protected XmlWorkflowService xmlWorkflowService;
|
||||
|
||||
public static final String SUBMIT_EDIT_METADATA = "submit_edit_metadata";
|
||||
public static final String SUBMIT_CANCEL = "submit_cancel";
|
||||
protected static final String SUBMIT_APPROVE = "submit_approve";
|
||||
protected static final String SUBMIT_REJECT = "submit_reject";
|
||||
protected static final String RETURN_TO_POOL = "return_to_pool";
|
||||
protected static final String REJECT_REASON = "reason";
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException {
|
||||
@@ -48,4 +58,31 @@ public abstract class ProcessingAction extends Action {
|
||||
task.getStepID().equals(getParent().getStep().getId()) &&
|
||||
task.getActionID().equals(getParent().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Process result when option {@link this#SUBMIT_REJECT} is selected.
|
||||
* - Sets the reason and workflow step responsible on item in dc.description.provenance
|
||||
* - Send workflow back to the submission
|
||||
* If reason is not given => error
|
||||
*/
|
||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
String reason = request.getParameter(REJECT_REASON);
|
||||
if (reason == null || 0 == reason.trim().length()) {
|
||||
addErrorField(request, REJECT_REASON);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
|
||||
// We have pressed reject, so remove the task the user has & put it back
|
||||
// to a workspace item
|
||||
xmlWorkflowService.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(),
|
||||
reason);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAdvanced() {
|
||||
return !getAdvancedOptions().isEmpty();
|
||||
}
|
||||
}
|
||||
|
@@ -15,8 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
@@ -36,11 +34,8 @@ public class ReviewAction extends ProcessingAction {
|
||||
public static final int MAIN_PAGE = 0;
|
||||
public static final int REJECT_PAGE = 1;
|
||||
|
||||
private static final String SUBMIT_APPROVE = "submit_approve";
|
||||
private static final String SUBMIT_REJECT = "submit_reject";
|
||||
private static final String SUBMITTER_IS_DELETED_PAGE = "submitter_deleted";
|
||||
|
||||
|
||||
@Override
|
||||
public void activate(Context c, XmlWorkflowItem wfItem) {
|
||||
|
||||
@@ -54,7 +49,7 @@ public class ReviewAction extends ProcessingAction {
|
||||
case SUBMIT_APPROVE:
|
||||
return processAccept(c, wfi);
|
||||
case SUBMIT_REJECT:
|
||||
return processRejectPage(c, wfi, step, request);
|
||||
return super.processRejectPage(c, wfi, request);
|
||||
case SUBMITTER_IS_DELETED_PAGE:
|
||||
return processSubmitterIsDeletedPage(c, wfi, request);
|
||||
default:
|
||||
@@ -69,50 +64,15 @@ public class ReviewAction extends ProcessingAction {
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add(SUBMIT_APPROVE);
|
||||
options.add(SUBMIT_REJECT);
|
||||
options.add(RETURN_TO_POOL);
|
||||
return options;
|
||||
}
|
||||
|
||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
super.addApprovedProvenance(c, wfi);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
}
|
||||
|
||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
//Add the provenance for the accept
|
||||
String now = DCDate.getCurrent().toString();
|
||||
|
||||
// Get user's name + email address
|
||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.getEPersonName(c.getCurrentUser());
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
||||
+ usersName + " on " + now + " (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||
provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
}
|
||||
|
||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
String reason = request.getParameter("reason");
|
||||
if (reason == null || 0 == reason.trim().length()) {
|
||||
request.setAttribute("page", REJECT_PAGE);
|
||||
addErrorField(request, "reason");
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
|
||||
//We have pressed reject, so remove the task the user has & put it back to a workspace item
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
||||
this.getProvenanceStartId(), reason);
|
||||
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
|
||||
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
if (request.getParameter("submit_delete") != null) {
|
||||
|
@@ -7,6 +7,9 @@
|
||||
*/
|
||||
package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||
|
||||
import static org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction.REVIEW_FIELD;
|
||||
import static org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction.SCORE_FIELD;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
@@ -19,7 +22,6 @@ import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.service.WorkflowRequirementsService;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
@@ -37,6 +39,7 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
*/
|
||||
public class ScoreEvaluationAction extends ProcessingAction {
|
||||
|
||||
// Minimum aggregate of scores
|
||||
private int minimumAcceptanceScore;
|
||||
|
||||
@Override
|
||||
@@ -47,43 +50,64 @@ public class ScoreEvaluationAction extends ProcessingAction {
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
boolean hasPassed = false;
|
||||
//Retrieve all our scores from the metadata & add em up
|
||||
// Retrieve all our scores from the metadata & add em up
|
||||
int scoreMean = getMeanScore(wfi);
|
||||
//We have passed if we have at least gained our minimum score
|
||||
boolean hasPassed = getMinimumAcceptanceScore() <= scoreMean;
|
||||
//Whether or not we have passed, clear our score information
|
||||
itemService.clearMetadata(c, wfi.getItem(), SCORE_FIELD.schema, SCORE_FIELD.element, SCORE_FIELD.qualifier,
|
||||
Item.ANY);
|
||||
if (hasPassed) {
|
||||
this.addRatingInfoToProv(c, wfi, scoreMean);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
} else {
|
||||
//We haven't passed, reject our item
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(),
|
||||
"The item was reject due to a bad review score.");
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private int getMeanScore(XmlWorkflowItem wfi) {
|
||||
List<MetadataValue> scores = itemService
|
||||
.getMetadata(wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY);
|
||||
.getMetadata(wfi.getItem(), SCORE_FIELD.schema, SCORE_FIELD.element, SCORE_FIELD.qualifier, Item.ANY);
|
||||
int scoreMean = 0;
|
||||
if (0 < scores.size()) {
|
||||
int totalScoreCount = 0;
|
||||
for (MetadataValue score : scores) {
|
||||
totalScoreCount += Integer.parseInt(score.getValue());
|
||||
}
|
||||
int scoreMean = totalScoreCount / scores.size();
|
||||
//We have passed if we have at least gained our minimum score
|
||||
hasPassed = getMinimumAcceptanceScore() <= scoreMean;
|
||||
//Wether or not we have passed, clear our score information
|
||||
itemService
|
||||
.clearMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY);
|
||||
scoreMean = totalScoreCount / scores.size();
|
||||
}
|
||||
return scoreMean;
|
||||
}
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive with a score of: " +
|
||||
scoreMean;
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(),
|
||||
"description", "provenance", "en", provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
private void addRatingInfoToProv(Context c, XmlWorkflowItem wfi, int scoreMean)
|
||||
throws SQLException, AuthorizeException {
|
||||
StringBuilder provDescription = new StringBuilder();
|
||||
provDescription.append(String.format("%s Approved for entry into archive with a score of: %s",
|
||||
getProvenanceStartId(), scoreMean));
|
||||
List<MetadataValue> reviews = itemService
|
||||
.getMetadata(wfi.getItem(), REVIEW_FIELD.schema, REVIEW_FIELD.element, REVIEW_FIELD.qualifier, Item.ANY);
|
||||
if (!reviews.isEmpty()) {
|
||||
provDescription.append(" | Reviews: ");
|
||||
}
|
||||
if (hasPassed) {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
} else {
|
||||
//We haven't passed, reject our item
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
||||
this.getProvenanceStartId(),
|
||||
"The item was reject due to a bad review score.");
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
for (MetadataValue review : reviews) {
|
||||
provDescription.append(String.format("; %s", review.getValue()));
|
||||
}
|
||||
c.turnOffAuthorisationSystem();
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(),
|
||||
"description", "provenance", "en", provDescription.toString());
|
||||
itemService.update(c, wfi.getItem());
|
||||
c.restoreAuthSystemState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOptions() {
|
||||
return new ArrayList<>();
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add(RETURN_TO_POOL);
|
||||
return options;
|
||||
}
|
||||
|
||||
public int getMinimumAcceptanceScore() {
|
||||
|
@@ -9,14 +9,20 @@ package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.MetadataFieldName;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.xmlworkflow.service.WorkflowRequirementsService;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
|
||||
@@ -24,40 +30,121 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
* This action will allow multiple users to rate a certain item
|
||||
* if the mean of this score is higher then the minimum score the
|
||||
* item will be sent to the next action/step else it will be rejected
|
||||
*
|
||||
* @author Bram De Schouwer (bram.deschouwer at dot com)
|
||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
*/
|
||||
public class ScoreReviewAction extends ProcessingAction {
|
||||
private static final Logger log = LogManager.getLogger(ScoreReviewAction.class);
|
||||
|
||||
private static final String SUBMIT_SCORE = "submit_score";
|
||||
// Option(s)
|
||||
public static final String SUBMIT_SCORE = "submit_score";
|
||||
|
||||
// Response param(s)
|
||||
private static final String SCORE = "score";
|
||||
private static final String REVIEW = "review";
|
||||
|
||||
// Metadata fields to save params in
|
||||
public static final MetadataFieldName SCORE_FIELD =
|
||||
new MetadataFieldName(WorkflowRequirementsService.WORKFLOW_SCHEMA, SCORE, null);
|
||||
public static final MetadataFieldName REVIEW_FIELD =
|
||||
new MetadataFieldName(WorkflowRequirementsService.WORKFLOW_SCHEMA, REVIEW, null);
|
||||
|
||||
// Whether or not it is required that a text review is added to the rating
|
||||
private boolean descriptionRequired;
|
||||
// Maximum value rating is allowed to be
|
||||
private int maxValue;
|
||||
|
||||
@Override
|
||||
public void activate(Context c, XmlWorkflowItem wf) {
|
||||
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
if (request.getParameter(SUBMIT_SCORE) != null) {
|
||||
int score = Util.getIntParameter(request, "score");
|
||||
//Add our score to the metadata
|
||||
itemService.addMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, null,
|
||||
String.valueOf(score));
|
||||
itemService.update(c, wfi.getItem());
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
} else {
|
||||
//We have pressed the leave button so return to our submission page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
throws SQLException, AuthorizeException {
|
||||
if (super.isOptionInParam(request) &&
|
||||
StringUtils.equalsIgnoreCase(Util.getSubmitButton(request, SUBMIT_CANCEL), SUBMIT_SCORE)) {
|
||||
return processSetRating(c, wfi, request);
|
||||
}
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
|
||||
private ActionResult processSetRating(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
int score = Util.getIntParameter(request, SCORE);
|
||||
String review = request.getParameter(REVIEW);
|
||||
if (!this.checkRequestValid(score, review)) {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
//Add our rating and review to the metadata
|
||||
itemService.addMetadata(c, wfi.getItem(), SCORE_FIELD.schema, SCORE_FIELD.element, SCORE_FIELD.qualifier, null,
|
||||
String.valueOf(score));
|
||||
if (StringUtils.isNotBlank(review)) {
|
||||
itemService.addMetadata(c, wfi.getItem(), REVIEW_FIELD.schema, REVIEW_FIELD.element,
|
||||
REVIEW_FIELD.qualifier, null, String.format("%s - %s", score, review));
|
||||
}
|
||||
itemService.update(c, wfi.getItem());
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request is not valid if:
|
||||
* - Given score is higher than configured maxValue
|
||||
* - There is no review given and description is configured to be required
|
||||
* Config in workflow-actions.xml
|
||||
*
|
||||
* @param score Given score rating from request
|
||||
* @param review Given review/description from request
|
||||
* @return True if valid request params with config, otherwise false
|
||||
*/
|
||||
private boolean checkRequestValid(int score, String review) {
|
||||
if (score > this.maxValue) {
|
||||
log.error("{} only allows max rating {} (config workflow-actions.xml), given rating of " +
|
||||
"{} not allowed.", this.getClass().toString(), this.maxValue, score);
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isBlank(review) && this.descriptionRequired) {
|
||||
log.error("{} has config descriptionRequired=true (workflow-actions.xml), so rating " +
|
||||
"requests without 'review' query param containing description are not allowed",
|
||||
this.getClass().toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOptions() {
|
||||
return List.of(SUBMIT_SCORE, RETURN_TO_POOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getAdvancedOptions() {
|
||||
return Arrays.asList(SUBMIT_SCORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||
ScoreReviewActionAdvancedInfo scoreReviewActionAdvancedInfo = new ScoreReviewActionAdvancedInfo();
|
||||
scoreReviewActionAdvancedInfo.setDescriptionRequired(descriptionRequired);
|
||||
scoreReviewActionAdvancedInfo.setMaxValue(maxValue);
|
||||
scoreReviewActionAdvancedInfo.setType(SUBMIT_SCORE);
|
||||
scoreReviewActionAdvancedInfo.generateId(SUBMIT_SCORE);
|
||||
return Collections.singletonList(scoreReviewActionAdvancedInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter that sets the descriptionRequired property from workflow-actions.xml
|
||||
* @param descriptionRequired boolean whether a description is required
|
||||
*/
|
||||
public void setDescriptionRequired(boolean descriptionRequired) {
|
||||
this.descriptionRequired = descriptionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter that sets the maxValue property from workflow-actions.xml
|
||||
* @param maxValue integer of the maximum allowed value
|
||||
*/
|
||||
public void setMaxValue(int maxValue) {
|
||||
this.maxValue = maxValue;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.xmlworkflow.state.actions.processingaction;
|
||||
|
||||
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
/**
|
||||
* Class that holds the advanced information needed for the
|
||||
* {@link org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction}
|
||||
* See config {@code workflow-actions.cfg}
|
||||
*/
|
||||
public class ScoreReviewActionAdvancedInfo extends ActionAdvancedInfo {
|
||||
private boolean descriptionRequired;
|
||||
private int maxValue;
|
||||
|
||||
public boolean isDescriptionRequired() {
|
||||
return descriptionRequired;
|
||||
}
|
||||
|
||||
public void setDescriptionRequired(boolean descriptionRequired) {
|
||||
this.descriptionRequired = descriptionRequired;
|
||||
}
|
||||
|
||||
public int getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
public void setMaxValue(int maxValue) {
|
||||
this.maxValue = maxValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateId(String type) {
|
||||
String idString = type
|
||||
+ ";descriptionRequired," + descriptionRequired
|
||||
+ ";maxValue," + maxValue;
|
||||
super.id = DigestUtils.md5DigestAsHex(idString.getBytes());
|
||||
}
|
||||
}
|
@@ -9,17 +9,27 @@ package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.xmlworkflow.Role;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||
import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
@@ -37,13 +47,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
*/
|
||||
public class SelectReviewerAction extends ProcessingAction {
|
||||
|
||||
public static final int SEARCH_RESULTS_PAGE = 1;
|
||||
|
||||
public static final int RESULTS_PER_PAGE = 5;
|
||||
private static final Logger log = LogManager.getLogger(SelectReviewerAction.class);
|
||||
|
||||
private static final String SUBMIT_CANCEL = "submit_cancel";
|
||||
private static final String SUBMIT_SEARCH = "submit_search";
|
||||
private static final String SUBMIT_SELECT_REVIEWER = "submit_select_reviewer_";
|
||||
private static final String SUBMIT_SELECT_REVIEWER = "submit_select_reviewer";
|
||||
private static final String PARAM_REVIEWER = "eperson";
|
||||
|
||||
private static final String CONFIG_REVIEWER_GROUP = "action.selectrevieweraction.group";
|
||||
|
||||
private Role role;
|
||||
|
||||
@@ -53,6 +63,15 @@ public class SelectReviewerAction extends ProcessingAction {
|
||||
@Autowired(required = true)
|
||||
private WorkflowItemRoleService workflowItemRoleService;
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
private GroupService groupService;
|
||||
|
||||
private static Group selectFromReviewsGroup;
|
||||
private static boolean selectFromReviewsGroupInitialised = false;
|
||||
|
||||
@Override
|
||||
public void activate(Context c, XmlWorkflowItem wf) {
|
||||
|
||||
@@ -60,56 +79,128 @@ public class SelectReviewerAction extends ProcessingAction {
|
||||
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
throws SQLException, AuthorizeException {
|
||||
String submitButton = Util.getSubmitButton(request, SUBMIT_CANCEL);
|
||||
|
||||
//Check if our user has pressed cancel
|
||||
if (submitButton.equals(SUBMIT_CANCEL)) {
|
||||
//Send us back to the submissions page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
|
||||
} else if (submitButton.equals(SUBMIT_SEARCH)) {
|
||||
//Perform the search
|
||||
String query = request.getParameter("query");
|
||||
int page = Util.getIntParameter(request, "result-page");
|
||||
if (page == -1) {
|
||||
page = 0;
|
||||
}
|
||||
|
||||
int resultCount = ePersonService.searchResultCount(c, query);
|
||||
List<EPerson> epeople = ePersonService.search(c, query, page * RESULTS_PER_PAGE, RESULTS_PER_PAGE);
|
||||
|
||||
|
||||
request.setAttribute("eperson-result-count", resultCount);
|
||||
request.setAttribute("eperson-results", epeople);
|
||||
request.setAttribute("result-page", page);
|
||||
request.setAttribute("page", SEARCH_RESULTS_PAGE);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE, SEARCH_RESULTS_PAGE);
|
||||
} else if (submitButton.startsWith(SUBMIT_SELECT_REVIEWER)) {
|
||||
//Retrieve the identifier of the eperson which will do the reviewing
|
||||
UUID reviewerId = UUID.fromString(submitButton.substring(submitButton.lastIndexOf("_") + 1));
|
||||
EPerson reviewer = ePersonService.find(c, reviewerId);
|
||||
//Assign the reviewer. The workflowitemrole will be translated into a task in the autoassign
|
||||
WorkflowItemRole workflowItemRole = workflowItemRoleService.create(c);
|
||||
workflowItemRole.setEPerson(reviewer);
|
||||
workflowItemRole.setRoleId(getRole().getId());
|
||||
workflowItemRole.setWorkflowItem(wfi);
|
||||
workflowItemRoleService.update(c, workflowItemRole);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
return processSelectReviewers(c, wfi, request);
|
||||
}
|
||||
|
||||
//There are only 2 active buttons on this page, so if anything else happens just return an error
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle the {@link this#SUBMIT_SELECT_REVIEWER} action:
|
||||
* - will retrieve the reviewer(s) uuid from request (param {@link this#PARAM_REVIEWER})
|
||||
* - assign them to a {@link WorkflowItemRole}
|
||||
* - In {@link org.dspace.xmlworkflow.state.actions.userassignment.AutoAssignAction} these reviewer(s) will get
|
||||
* claimed task for this {@link XmlWorkflowItem}
|
||||
* Will result in error if:
|
||||
* - No reviewer(s) uuid in request (param {@link this#PARAM_REVIEWER})
|
||||
* - If none of the reviewer(s) uuid passed along result in valid EPerson
|
||||
* - If the reviewer(s) passed along are not in {@link this#selectFromReviewsGroup} when it is set
|
||||
*
|
||||
* @param c current DSpace session
|
||||
* @param wfi the item on which the action is to be performed
|
||||
* @param request the current client request
|
||||
* @return the result of performing the action
|
||||
*/
|
||||
private ActionResult processSelectReviewers(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
//Retrieve the identifier of the eperson which will do the reviewing
|
||||
String[] reviewerIds = request.getParameterValues(PARAM_REVIEWER);
|
||||
if (ArrayUtils.isEmpty(reviewerIds)) {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
List<EPerson> reviewers = new ArrayList<>();
|
||||
for (String reviewerId : reviewerIds) {
|
||||
EPerson reviewer = ePersonService.find(c, UUID.fromString(reviewerId));
|
||||
if (reviewer == null) {
|
||||
log.warn("No EPerson found with uuid {}", reviewerId);
|
||||
} else {
|
||||
reviewers.add(reviewer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.checkReviewersValid(c, reviewers)) {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
|
||||
createWorkflowItemRole(c, wfi, reviewers);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
}
|
||||
|
||||
private boolean checkReviewersValid(Context c, List<EPerson> reviewers) throws SQLException {
|
||||
if (reviewers.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
Group group = this.getGroup(c);
|
||||
if (group != null) {
|
||||
for (EPerson reviewer: reviewers) {
|
||||
if (!groupService.isMember(c, reviewer, group)) {
|
||||
log.error("Reviewers selected must be member of group {}", group.getID());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private WorkflowItemRole createWorkflowItemRole(Context c, XmlWorkflowItem wfi, List<EPerson> reviewers)
|
||||
throws SQLException, AuthorizeException {
|
||||
WorkflowItemRole workflowItemRole = workflowItemRoleService.create(c);
|
||||
workflowItemRole.setRoleId(getRole().getId());
|
||||
workflowItemRole.setWorkflowItem(wfi);
|
||||
if (reviewers.size() == 1) {
|
||||
// 1 reviewer in workflowitemrole => will be translated into a claimed task in the autoassign
|
||||
workflowItemRole.setEPerson(reviewers.get(0));
|
||||
} else {
|
||||
// multiple reviewers, create a temporary group and assign this group, the workflowitemrole will be
|
||||
// translated into a claimed task for reviewers in the autoassign, where group will be deleted
|
||||
c.turnOffAuthorisationSystem();
|
||||
Group selectedReviewsGroup = groupService.create(c);
|
||||
groupService.setName(selectedReviewsGroup, "selectedReviewsGroup_" + wfi.getID());
|
||||
for (EPerson reviewer : reviewers) {
|
||||
groupService.addMember(c, selectedReviewsGroup, reviewer);
|
||||
}
|
||||
workflowItemRole.setGroup(selectedReviewsGroup);
|
||||
c.restoreAuthSystemState();
|
||||
}
|
||||
workflowItemRoleService.update(c, workflowItemRole);
|
||||
return workflowItemRole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOptions() {
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add(SUBMIT_SEARCH);
|
||||
options.add(SUBMIT_SELECT_REVIEWER);
|
||||
options.add(RETURN_TO_POOL);
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getAdvancedOptions() {
|
||||
return Arrays.asList(SUBMIT_SELECT_REVIEWER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ActionAdvancedInfo> getAdvancedInfo() {
|
||||
List<ActionAdvancedInfo> advancedInfo = new ArrayList<>();
|
||||
SelectReviewerActionAdvancedInfo selectReviewerActionAdvancedInfo = new SelectReviewerActionAdvancedInfo();
|
||||
if (getGroup(null) != null) {
|
||||
selectReviewerActionAdvancedInfo.setGroup(getGroup(null).getID().toString());
|
||||
}
|
||||
selectReviewerActionAdvancedInfo.setType(SUBMIT_SELECT_REVIEWER);
|
||||
selectReviewerActionAdvancedInfo.generateId(SUBMIT_SELECT_REVIEWER);
|
||||
advancedInfo.add(selectReviewerActionAdvancedInfo);
|
||||
return advancedInfo;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
@@ -118,4 +209,49 @@ public class SelectReviewerAction extends ProcessingAction {
|
||||
public void setRole(Role role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Reviewer group from the "action.selectrevieweraction.group" property in actions.cfg by its UUID or name
|
||||
* Returns null if no (valid) group configured
|
||||
*
|
||||
* @return configured reviewers Group from property or null if none
|
||||
*/
|
||||
private Group getGroup(@Nullable Context context) {
|
||||
if (selectFromReviewsGroupInitialised) {
|
||||
return this.selectFromReviewsGroup;
|
||||
}
|
||||
if (context == null) {
|
||||
context = new Context();
|
||||
}
|
||||
String groupIdOrName = configurationService.getProperty(CONFIG_REVIEWER_GROUP);
|
||||
|
||||
if (StringUtils.isNotBlank(groupIdOrName)) {
|
||||
Group group = null;
|
||||
try {
|
||||
// try to get group by name
|
||||
group = groupService.findByName(context, groupIdOrName);
|
||||
if (group == null) {
|
||||
// try to get group by uuid if not a name
|
||||
group = groupService.find(context, UUID.fromString(groupIdOrName));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// There is an issue with the reviewer group that is set; if it is not set then can be chosen
|
||||
// from all epeople
|
||||
log.error("Issue with determining matching group for config {}={} for reviewer group of " +
|
||||
"select reviewers workflow", CONFIG_REVIEWER_GROUP, groupIdOrName);
|
||||
}
|
||||
|
||||
this.selectFromReviewsGroup = group;
|
||||
}
|
||||
selectFromReviewsGroupInitialised = true;
|
||||
return this.selectFromReviewsGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be used by IT, e.g. {@code XmlWorkflowServiceIT}, when defining new 'Reviewers' group
|
||||
*/
|
||||
static public void resetGroup() {
|
||||
selectFromReviewsGroup = null;
|
||||
selectFromReviewsGroupInitialised = false;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.xmlworkflow.state.actions.processingaction;
|
||||
|
||||
import org.dspace.xmlworkflow.state.actions.ActionAdvancedInfo;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
/**
|
||||
* Class that holds the advanced information needed for the
|
||||
* {@link org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction}
|
||||
* See config {@code workflow-actions.cfg}
|
||||
*/
|
||||
public class SelectReviewerActionAdvancedInfo extends ActionAdvancedInfo {
|
||||
private String group;
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateId(String type) {
|
||||
String idString = type
|
||||
+ ";group," + group;
|
||||
super.id = DigestUtils.md5DigestAsHex(idString.getBytes());
|
||||
}
|
||||
}
|
||||
|
@@ -13,11 +13,15 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.workflow.WorkflowException;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.state.Step;
|
||||
import org.dspace.xmlworkflow.state.actions.ActionResult;
|
||||
@@ -34,39 +38,59 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
*/
|
||||
public class SingleUserReviewAction extends ProcessingAction {
|
||||
|
||||
public static final int MAIN_PAGE = 0;
|
||||
public static final int REJECT_PAGE = 1;
|
||||
public static final int SUBMITTER_IS_DELETED_PAGE = 2;
|
||||
private static final Logger log = LogManager.getLogger(SingleUserReviewAction.class);
|
||||
|
||||
public static final int OUTCOME_REJECT = 1;
|
||||
|
||||
protected static final String SUBMIT_APPROVE = "submit_approve";
|
||||
protected static final String SUBMIT_REJECT = "submit_reject";
|
||||
protected static final String SUBMIT_DECLINE_TASK = "submit_decline_task";
|
||||
|
||||
@Override
|
||||
public void activate(Context c, XmlWorkflowItem wfItem) {
|
||||
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
int page = Util.getIntParameter(request, "page");
|
||||
|
||||
switch (page) {
|
||||
case MAIN_PAGE:
|
||||
return processMainPage(c, wfi, step, request);
|
||||
case REJECT_PAGE:
|
||||
return processRejectPage(c, wfi, step, request);
|
||||
case SUBMITTER_IS_DELETED_PAGE:
|
||||
return processSubmitterIsDeletedPage(c, wfi, request);
|
||||
throws SQLException, AuthorizeException, IOException, WorkflowException {
|
||||
if (!super.isOptionInParam(request)) {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
switch (Util.getSubmitButton(request, SUBMIT_CANCEL)) {
|
||||
case SUBMIT_APPROVE:
|
||||
return processAccept(c, wfi);
|
||||
case SUBMIT_REJECT:
|
||||
return processReject(c, wfi, request);
|
||||
case SUBMIT_DECLINE_TASK:
|
||||
return processDecline(c, wfi);
|
||||
default:
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {@link super#SUBMIT_REJECT} on this action, will either:
|
||||
* - If submitter of item no longer exists => Permanently delete corresponding item (no wfi/wsi remaining)
|
||||
* - Otherwise: reject item back to submission => becomes wsi of submitter again
|
||||
*/
|
||||
private ActionResult processReject(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
if (wfi.getSubmitter() == null) {
|
||||
// If the original submitter is no longer there, delete the task
|
||||
return processDelete(c, wfi);
|
||||
} else {
|
||||
return super.processRejectPage(c, wfi, request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept the workflow item => last step in workflow so will be archived
|
||||
* Info on step & reviewer will be added on metadata dc.description.provenance of resulting item
|
||||
*/
|
||||
public ActionResult processAccept(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
super.addApprovedProvenance(c, wfi);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOptions() {
|
||||
List<String> options = new ArrayList<>();
|
||||
@@ -76,87 +100,29 @@ public class SingleUserReviewAction extends ProcessingAction {
|
||||
return options;
|
||||
}
|
||||
|
||||
public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException {
|
||||
if (request.getParameter(SUBMIT_APPROVE) != null) {
|
||||
//Delete the tasks
|
||||
addApprovedProvenance(c, wfi);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE);
|
||||
} else if (request.getParameter(SUBMIT_REJECT) != null) {
|
||||
// Make sure we indicate which page we want to process
|
||||
if (wfi.getSubmitter() == null) {
|
||||
request.setAttribute("page", SUBMITTER_IS_DELETED_PAGE);
|
||||
} else {
|
||||
request.setAttribute("page", REJECT_PAGE);
|
||||
}
|
||||
// We have pressed reject item, so take the user to a page where they can reject
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
||||
} else if (request.getParameter(SUBMIT_DECLINE_TASK) != null) {
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, OUTCOME_REJECT);
|
||||
|
||||
} else {
|
||||
//We pressed the leave button so return to our submissions page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private void addApprovedProvenance(Context c, XmlWorkflowItem wfi) throws SQLException, AuthorizeException {
|
||||
//Add the provenance for the accept
|
||||
String now = DCDate.getCurrent().toString();
|
||||
|
||||
// Get user's name + email address
|
||||
String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.getEPersonName(c.getCurrentUser());
|
||||
|
||||
String provDescription = getProvenanceStartId() + " Approved for entry into archive by "
|
||||
+ usersName + " on " + now + " (GMT) ";
|
||||
|
||||
// Add to item as a DC field
|
||||
itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en",
|
||||
provDescription);
|
||||
itemService.update(c, wfi.getItem());
|
||||
}
|
||||
|
||||
public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request)
|
||||
/**
|
||||
* Since original submitter no longer exists, workflow item is permanently deleted
|
||||
*/
|
||||
private ActionResult processDelete(Context c, XmlWorkflowItem wfi)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
if (request.getParameter("submit_reject") != null) {
|
||||
String reason = request.getParameter("reason");
|
||||
if (reason == null || 0 == reason.trim().length()) {
|
||||
request.setAttribute("page", REJECT_PAGE);
|
||||
addErrorField(request, "reason");
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_ERROR);
|
||||
}
|
||||
|
||||
//We have pressed reject, so remove the task the user has & put it back to a workspace item
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(),
|
||||
this.getProvenanceStartId(), reason);
|
||||
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
} else {
|
||||
//Cancel, go back to the main task page
|
||||
request.setAttribute("page", MAIN_PAGE);
|
||||
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
||||
}
|
||||
EPerson user = c.getCurrentUser();
|
||||
c.turnOffAuthorisationSystem();
|
||||
WorkspaceItem workspaceItem = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.abort(c, wfi, user);
|
||||
ContentServiceFactory.getInstance().getWorkspaceItemService().deleteAll(c, workspaceItem);
|
||||
c.restoreAuthSystemState();
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
|
||||
public ActionResult processSubmitterIsDeletedPage(Context c, XmlWorkflowItem wfi, HttpServletRequest request)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
if (request.getParameter("submit_delete") != null) {
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.deleteWorkflowByWorkflowItem(c, wfi, c.getCurrentUser());
|
||||
// Delete and send user back to myDspace page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
} else if (request.getParameter("submit_keep_it") != null) {
|
||||
// Do nothing, just send it back to myDspace page
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
} else {
|
||||
//Cancel, go back to the main task page
|
||||
request.setAttribute("page", MAIN_PAGE);
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_PAGE);
|
||||
}
|
||||
/**
|
||||
* Selected reviewer declines to review task, then the workflow is aborted and restarted
|
||||
*/
|
||||
private ActionResult processDecline(Context c, XmlWorkflowItem wfi)
|
||||
throws SQLException, IOException, AuthorizeException, WorkflowException {
|
||||
c.turnOffAuthorisationSystem();
|
||||
xmlWorkflowService.restartWorkflow(c, wfi, c.getCurrentUser(), this.getProvenanceStartId());
|
||||
c.restoreAuthSystemState();
|
||||
return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -80,6 +80,10 @@ public class AutoAssignAction extends UserSelectionAction {
|
||||
}
|
||||
//Delete our workflow item role since the users have been assigned
|
||||
workflowItemRoleService.delete(c, workflowItemRole);
|
||||
if (role.isDeleteTemporaryGroup() && workflowItemRole.getGroup() != null) {
|
||||
// Delete temporary groups created after members have workflow task assigned
|
||||
groupService.delete(c, workflowItemRole.getGroup());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn(LogHelper.getHeader(c, "Error while executing auto assign action",
|
||||
@@ -127,7 +131,7 @@ public class AutoAssignAction extends UserSelectionAction {
|
||||
protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig,
|
||||
EPerson user) throws SQLException, AuthorizeException, IOException {
|
||||
if (claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null) {
|
||||
workflowRequirementsService.addClaimedUser(c, wfi, step, c.getCurrentUser());
|
||||
workflowRequirementsService.addClaimedUser(c, wfi, step, user);
|
||||
XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService()
|
||||
.createOwnedTask(c, wfi, step, actionConfig, user);
|
||||
}
|
||||
|
@@ -138,6 +138,10 @@ public class ClaimAction extends UserSelectionAction {
|
||||
RoleMembers roleMembers = role.getMembers(context, wfi);
|
||||
|
||||
ArrayList<EPerson> epersons = roleMembers.getAllUniqueMembers(context);
|
||||
if (epersons.isEmpty() || step.getRequiredUsers() > epersons.size()) {
|
||||
log.warn(String.format("There must be at least %s ePerson(s) in the group",
|
||||
step.getRequiredUsers()));
|
||||
}
|
||||
return !(epersons.isEmpty() || step.getRequiredUsers() > epersons.size());
|
||||
} else {
|
||||
// We don't have a role and do have a UI so throw a workflow exception
|
||||
|
@@ -0,0 +1,44 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- ADD table subscription_parameter
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
CREATE SEQUENCE if NOT EXISTS subscription_parameter_seq;
|
||||
-------------------------------------------------------
|
||||
-- Create the subscription_parameter table
|
||||
-------------------------------------------------------
|
||||
|
||||
CREATE TABLE if NOT EXISTS subscription_parameter
|
||||
(
|
||||
subscription_parameter_id INTEGER NOT NULL,
|
||||
name CHARACTER VARYING(255),
|
||||
value CHARACTER VARYING(255),
|
||||
subscription_id INTEGER NOT NULL,
|
||||
CONSTRAINT subscription_parameter_pkey PRIMARY KEY (subscription_parameter_id),
|
||||
CONSTRAINT subscription_parameter_subscription_fkey FOREIGN KEY (subscription_id) REFERENCES subscription (subscription_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
--
|
||||
ALTER TABLE subscription ADD COLUMN if NOT EXISTS dspace_object_id UUID;
|
||||
--
|
||||
ALTER TABLE subscription ADD COLUMN if NOT EXISTS type CHARACTER VARYING(255);
|
||||
--
|
||||
ALTER TABLE subscription DROP CONSTRAINT IF EXISTS subscription_dspaceobject_fkey;
|
||||
ALTER TABLE subscription ADD CONSTRAINT subscription_dspaceobject_fkey FOREIGN KEY (dspace_object_id) REFERENCES dspaceobject (uuid);
|
||||
-- --
|
||||
UPDATE subscription set dspace_object_id = collection_id , type = 'content';
|
||||
--
|
||||
ALTER TABLE subscription DROP CONSTRAINT IF EXISTS Subscription_collection_id_fk;
|
||||
--
|
||||
ALTER TABLE subscription DROP COLUMN IF EXISTS collection_id;
|
||||
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Create table for System wide alerts
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
CREATE SEQUENCE alert_id_seq;
|
||||
|
||||
CREATE TABLE systemwidealert
|
||||
(
|
||||
alert_id INTEGER NOT NULL PRIMARY KEY,
|
||||
message VARCHAR(512),
|
||||
allow_sessions VARCHAR(64),
|
||||
countdown_to TIMESTAMP,
|
||||
active BOOLEAN
|
||||
);
|
@@ -0,0 +1,45 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- ADD table subscription_parameter
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
CREATE SEQUENCE if NOT EXISTS subscription_parameter_seq;
|
||||
-----------------------------------------------------------------------------------
|
||||
-- ADD table subscription_parameter
|
||||
-----------------------------------------------------------------------------------
|
||||
CREATE TABLE if NOT EXISTS subscription_parameter
|
||||
(
|
||||
subscription_parameter_id INTEGER NOT NULL,
|
||||
name VARCHAR(255),
|
||||
value VARCHAR(255),
|
||||
subscription_id INTEGER NOT NULL,
|
||||
CONSTRAINT subscription_parameter_pkey PRIMARY KEY (subscription_parameter_id),
|
||||
CONSTRAINT subscription_parameter_subscription_fkey FOREIGN KEY (subscription_id)
|
||||
REFERENCES subscription (subscription_id) ON DELETE CASCADE
|
||||
);
|
||||
-- --
|
||||
|
||||
ALTER TABLE subscription ADD COLUMN if NOT EXISTS dspace_object_id UUID;
|
||||
---- --
|
||||
ALTER TABLE subscription ADD COLUMN if NOT EXISTS type CHARACTER VARYING(255);
|
||||
--
|
||||
UPDATE subscription SET dspace_object_id = collection_id , type = 'content';
|
||||
--
|
||||
ALTER TABLE subscription DROP CONSTRAINT IF EXISTS subscription_dspaceobject_fkey;
|
||||
ALTER TABLE subscription ADD CONSTRAINT subscription_dspaceobject_fkey FOREIGN KEY (dspace_object_id) REFERENCES dspaceobject (uuid);
|
||||
--
|
||||
ALTER TABLE subscription DROP CONSTRAINT IF EXISTS subscription_collection_id_fkey;
|
||||
---- --
|
||||
ALTER TABLE subscription DROP COLUMN IF EXISTS collection_id;
|
||||
-- --
|
||||
INSERT INTO subscription_parameter (subscription_parameter_id, name, value, subscription_id)
|
||||
SELECT getnextid('subscription_parameter'), 'frequency', 'D', subscription_id from "subscription" ;
|
||||
|
@@ -0,0 +1,22 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Create table for System wide alerts
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
CREATE SEQUENCE alert_id_seq;
|
||||
|
||||
CREATE TABLE systemwidealert
|
||||
(
|
||||
alert_id INTEGER NOT NULL PRIMARY KEY,
|
||||
message VARCHAR(512),
|
||||
allow_sessions VARCHAR(64),
|
||||
countdown_to TIMESTAMP,
|
||||
active BOOLEAN
|
||||
);
|
@@ -0,0 +1,43 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- ADD table subscription_parameter
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
CREATE SEQUENCE if NOT EXISTS subscription_parameter_seq;
|
||||
-----------------------------------------------------------------------------------
|
||||
-- ADD table subscription_parameter
|
||||
-----------------------------------------------------------------------------------
|
||||
CREATE TABLE if NOT EXISTS subscription_parameter
|
||||
(
|
||||
subscription_parameter_id INTEGER NOT NULL,
|
||||
name CHARACTER VARYING(255),
|
||||
value CHARACTER VARYING(255),
|
||||
subscription_id INTEGER NOT NULL,
|
||||
CONSTRAINT subscription_parameter_pkey PRIMARY KEY (subscription_parameter_id),
|
||||
CONSTRAINT subscription_parameter_subscription_fkey FOREIGN KEY (subscription_id) REFERENCES subscription (subscription_id) ON DELETE CASCADE
|
||||
);
|
||||
--
|
||||
ALTER TABLE subscription ADD COLUMN if NOT EXISTS dspace_object_id UUID;
|
||||
-- --
|
||||
ALTER TABLE subscription ADD COLUMN if NOT EXISTS type CHARACTER VARYING(255);
|
||||
---- --
|
||||
ALTER TABLE subscription DROP CONSTRAINT IF EXISTS subscription_dspaceobject_fkey;
|
||||
ALTER TABLE subscription ADD CONSTRAINT subscription_dspaceobject_fkey FOREIGN KEY (dspace_object_id) REFERENCES dspaceobject (uuid);
|
||||
--
|
||||
UPDATE subscription SET dspace_object_id = collection_id , type = 'content';
|
||||
--
|
||||
ALTER TABLE subscription DROP CONSTRAINT IF EXISTS subscription_collection_id_fkey;
|
||||
-- --
|
||||
ALTER TABLE subscription DROP COLUMN IF EXISTS collection_id;
|
||||
-- --
|
||||
INSERT INTO subscription_parameter (subscription_parameter_id, name, value, subscription_id)
|
||||
SELECT getnextid('subscription_parameter'), 'frequency', 'D', subscription_id from "subscription" ;
|
||||
|
@@ -0,0 +1,22 @@
|
||||
--
|
||||
-- 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/
|
||||
--
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Create table for System wide alerts
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
CREATE SEQUENCE alert_id_seq;
|
||||
|
||||
CREATE TABLE systemwidealert
|
||||
(
|
||||
alert_id INTEGER NOT NULL PRIMARY KEY,
|
||||
message VARCHAR(512),
|
||||
allow_sessions VARCHAR(64),
|
||||
countdown_to TIMESTAMP,
|
||||
active BOOLEAN
|
||||
);
|
@@ -143,6 +143,12 @@
|
||||
<processing-class>org.dspace.app.rest.submit.step.SherpaPolicyStep</processing-class>
|
||||
<type>sherpaPolicy</type>
|
||||
</step-definition>
|
||||
|
||||
<step-definition id="identifiers">
|
||||
<heading>submit.progressbar.identifiers</heading>
|
||||
<processing-class>org.dspace.app.rest.submit.step.ShowIdentifiersStep</processing-class>
|
||||
<type>identifiers</type>
|
||||
</step-definition>
|
||||
</step-definitions>
|
||||
|
||||
<!-- The submission-definitions map lays out the detailed definition of -->
|
||||
@@ -169,6 +175,8 @@
|
||||
|
||||
<step id="collection"/>
|
||||
|
||||
<step id="identifiers"/>
|
||||
|
||||
<!--Step will be to Describe the item. -->
|
||||
<step id="traditionalpageone"/>
|
||||
<step id="traditionalpagetwo"/>
|
||||
|
@@ -43,7 +43,7 @@ dspace.server.url = http://localhost
|
||||
db.driver = org.h2.Driver
|
||||
db.dialect=org.hibernate.dialect.H2Dialect
|
||||
# Use a 10 second database lock timeout to avoid occasional JDBC lock timeout errors
|
||||
db.url = jdbc:h2:mem:test;LOCK_TIMEOUT=10000;
|
||||
db.url = jdbc:h2:mem:test;LOCK_TIMEOUT=10000;NON_KEYWORDS=VALUE
|
||||
db.username = sa
|
||||
db.password =
|
||||
# H2's default schema is PUBLIC
|
||||
|
@@ -0,0 +1,49 @@
|
||||
#----------------------------------------------------------------------#
|
||||
#---------------------IDENTIFIER CONFIGURATIONS------------------------#
|
||||
#----------------------------------------------------------------------#
|
||||
# These configs are used for additional identifier configuration such #
|
||||
# as the Show Identifiers step which can "pre-mint" DOIs and Handles #
|
||||
#----------------------------------------------------------------------#
|
||||
|
||||
# Should configured identifiers (eg handle and DOI) be minted for (future) registration at workspace item creation?
|
||||
# A handle created at this stage will act just like a regular handle created at archive time.
|
||||
# A DOI created at this stage will be in a 'PENDING' status while in workspace and workflow.
|
||||
# At the time of item install, the DOI filter (if any) will be applied and if the item matches the filter, the DOI
|
||||
# status will be updated to TO_BE_REGISTERED. An administrator can also manually progress the DOI status, overriding
|
||||
# any filters, in the item status page.
|
||||
# This option doesn't require the Show Identifiers submission step to be visible.
|
||||
# Default: false
|
||||
identifiers.submission.register = false
|
||||
|
||||
# This configuration property can be set to a filter name to determine if a PENDING DOI for an item
|
||||
# should be queued for registration. If the filter doesn't match, the DOI will stay in PENDING or MINTED status
|
||||
# so that the identifier itself persists in case it is considered for registration in the future.
|
||||
# See doi-filter and other example filters in item-filters.xml.
|
||||
# Default (always_true_filter)
|
||||
identifiers.submission.filter.install = doi_filter
|
||||
|
||||
# This optional configuration property can be set to a filter name, in case there are some initial rules to apply
|
||||
# when first deciding whether a DOI should be be created for a new workspace item with a PENDING status.
|
||||
# This filter is only applied if identifiers.submission.register is true.
|
||||
# This filter is updated as submission data is saved.
|
||||
# Default: (always_true_filter)
|
||||
identifiers.submission.filter.workspace = doi_filter
|
||||
|
||||
# If true, the workspace filter will be applied as submission data is saved. If the filter no longer
|
||||
# matches the item, the DOI will be shifted into a MINTED status and not displayed in the submission section.
|
||||
# If false, then once a DOI has been created with PENDING status it will remain that way until final item install
|
||||
# Default: true
|
||||
#identifiers.submission.strip_pending_during_submission = true
|
||||
|
||||
# This configuration property can be set to a filter name to determine if an item processed by RegisterDOI curation
|
||||
# task should be eligible for a DOI
|
||||
identifiers.submission.filter.curation = always_true_filter
|
||||
|
||||
# Show Register DOI button in item status page?
|
||||
# Default: false
|
||||
identifiers.item-status.register-doi = true
|
||||
|
||||
# Which identifier types to show in submission step?
|
||||
# Default: handle, doi (currently the only supported identifier 'types')
|
||||
identifiers.submission.display = handle
|
||||
identifiers.submission.display = doi
|
@@ -0,0 +1,370 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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/
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||||
>
|
||||
<!-- default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> -->
|
||||
|
||||
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
|
||||
<bean id="always_true_filter" scope="singleton" class="org.dspace.content.logic.TrueFilter"/>
|
||||
|
||||
<!-- DEFINE CONDITIONS
|
||||
Define condition beans below for use as sub-statements in operator and filter beans
|
||||
-->
|
||||
|
||||
<!--
|
||||
The MetadataValueMatchCondition takes a regular expression, not an exact value.
|
||||
For an exact value match (rather than 'contains'), make sure to anchor the string
|
||||
like "^Exact Match$".
|
||||
Special characters used in Java regular expressions will need escaping.
|
||||
The below condition returns true if dc.title contains "demo" (case insensitive)
|
||||
-->
|
||||
<bean id="title-contains-demo_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value="(?i)demo" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="item-is-public_condition"
|
||||
class="org.dspace.content.logic.condition.ReadableByGroupCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="group" value="Anonymous" />
|
||||
<entry key="action" value="READ" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.title starts with Pattern -->
|
||||
<bean id="title-starts-with-pattern_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value="^Pattern" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.type is exactly Journal Article -->
|
||||
<bean id="type-equals-journal-article_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.type" />
|
||||
<entry key="pattern" value="^Journal Article$" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.type is exactly Dataset -->
|
||||
<bean id="type-equals-dataset_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.type" />
|
||||
<entry key="pattern" value="^Dataset$" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
A filter that checks if any value of dc.identifier.uri contains "10.12345/".
|
||||
-->
|
||||
<bean id="dc-identifier-uri-contains-doi_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.identifier.uri" />
|
||||
<entry key="pattern" value="10.12345/" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.type ends with any of the listed values, as per XOAI "driverDocumentTypeCondition" -->
|
||||
<bean id="driver-document-type_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValuesMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.type" />
|
||||
<entry key="patterns">
|
||||
<list>
|
||||
<value>article$</value>
|
||||
<value>bachelorThesis$</value>
|
||||
<value>masterThesis$</value>
|
||||
<value>doctoralThesis$</value>
|
||||
<value>book$</value>
|
||||
<value>bookPart$</value>
|
||||
<value>review$</value>
|
||||
<value>conferenceObject$</value>
|
||||
<value>lecture$</value>
|
||||
<value>workingPaper$</value>
|
||||
<value>preprint$</value>
|
||||
<value>report$</value>
|
||||
<value>annotation$</value>
|
||||
<value>contributionToPeriodical$</value>
|
||||
<value>patent$</value>
|
||||
<value>dataset$</value>
|
||||
<value>other$</value>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- is in collection 123456789/20 (note, list parameter map means multiple collections can be passed) -->
|
||||
<bean id="in-outfit-collection_condition"
|
||||
class="org.dspace.content.logic.condition.InCollectionCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="collections">
|
||||
<list>
|
||||
<value>123456789/20</value>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- has exactly one bitstream in ORIGINAL bundle -->
|
||||
<bean id="has-one-bitstream_condition"
|
||||
class="org.dspace.content.logic.condition.BitstreamCountCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="bundle" value="ORIGINAL"/>
|
||||
<entry key="min" value="1"/>
|
||||
<entry key="max" value="1"/>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- has at least one bitstream in ORIGINAL bundle -->
|
||||
<bean id="has-at-least-one-bitstream_condition"
|
||||
class="org.dspace.content.logic.condition.BitstreamCountCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="bundle" value="ORIGINAL"/>
|
||||
<entry key="min" value="1"/>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="is-archived_condition" class="org.dspace.content.logic.condition.IsArchivedCondition">
|
||||
<property name="parameters">
|
||||
<map></map>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="is-withdrawn_condition" class="org.dspace.content.logic.condition.IsWithdrawnCondition">
|
||||
<property name="parameters">
|
||||
<map></map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- DEFINE OPERATORS
|
||||
Operators can be defined too, if a particular AND or OR statement needs to be re-used a lot, though
|
||||
it may be easier in most cases to turn that into a filter and reference the filter in other sub-statements
|
||||
-->
|
||||
<bean class="org.dspace.content.logic.operator.Or" id="a-common-or_statement">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="type-equals-journal-article_condition"/>
|
||||
<ref bean="type-equals-dataset_condition"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- DEFINE FILTERS -->
|
||||
<!-- Note that this filter is almost the same as the above "or" bean but the advantage is we
|
||||
can reference the type_filter directly for item logic *and* as a sub-statement of other filters
|
||||
whereas the operator class can only be a sub-statement
|
||||
-->
|
||||
|
||||
<!-- Example DOI Filter. An item has to pass the filter (filter returns true) to get a DOI.
|
||||
If the filter returns false on an item, minting of a new DOI for that item is prevented. -->
|
||||
<bean id="doi-filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- Make sure the item is archived -->
|
||||
<ref bean="is-archived_condition"/>
|
||||
<!-- Make sure the item is not withdrawn -->
|
||||
<bean class="org.dspace.content.logic.operator.Not">
|
||||
<property name="statements" ref="is-withdrawn_condition"/>
|
||||
</bean>
|
||||
<!-- Don't create new DOIs for items that already have one -->
|
||||
<bean class="org.dspace.content.logic.operator.Not">
|
||||
<property name="statements" ref="dc-identifier-uri-contains-doi_condition"/>
|
||||
</bean>
|
||||
<!-- Create DOIs for items only that do have at least one bitstream. -->
|
||||
<ref bean="has-at-least-one-bitstream_condition"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="type_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<!-- the below is the same as referencing the above, eg:
|
||||
<ref bean="a-common-r_statement"/> -->
|
||||
<bean class="org.dspace.content.logic.operator.Or">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="type-equals-journal-article_condition"/>
|
||||
<ref bean="type-equals-dataset_condition"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- A very simple demonstration filter, using the metadata match condition -->
|
||||
<bean id="simple-demo_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement" ref="title-contains-demo_condition"/>
|
||||
</bean>
|
||||
|
||||
<!-- A very simple filter for items with at least one bitstream -->
|
||||
<bean id="has-bitstream_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement" ref="has-at-least-one-bitstream_condition"/>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
a more complex example:
|
||||
title contains 'demo' AND (title starts with 'Pattern' OR item is in one of the listed collections)
|
||||
-->
|
||||
<bean id="demo_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<!-- title contains 'demo' AND (the result of the OR substatement is true) -->
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="title-contains-demo_condition"/>
|
||||
<bean class="org.dspace.content.logic.operator.Or">
|
||||
<!-- title starts with Lily OR the item in one of the listed collections -->
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="title-starts-with-pattern_condition"/>
|
||||
<bean class="org.dspace.content.logic.condition.InCollectionCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="collections">
|
||||
<list>
|
||||
<value>123456789/3</value>
|
||||
<value>123456789/4</value>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- An example of an OpenAIRE compliance filter based on the same rules in xoai.xml
|
||||
some sub-statements are defined within this bean, and some are referenced from earlier definitions
|
||||
-->
|
||||
<bean id="openaire_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- Has a non-empty title -->
|
||||
<bean id="has-title_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value=".*" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- AND has a non-empty author -->
|
||||
<bean id="has-author_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.contributor.author" />
|
||||
<entry key="pattern" value=".*" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- AND has a valid DRIVER document type (defined earlier) -->
|
||||
<ref bean="driver-document-type_condition" />
|
||||
<!-- AND (the item is publicly accessible OR withdrawn) -->
|
||||
<bean class="org.dspace.content.logic.operator.Or">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- item is public, defined earlier -->
|
||||
<ref bean="item-is-public_condition" />
|
||||
<!-- OR item is withdrawn, for tombstoning -->
|
||||
<bean class="org.dspace.content.logic.condition.IsWithdrawnCondition">
|
||||
<property name="parameters"><map></map></property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- AND the dc.relation is a valid OpenAIRE identifier
|
||||
(starts with "info:eu-repo/grantAgreement/") -->
|
||||
<bean id="has-openaire-relation_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.relation" />
|
||||
<entry key="pattern" value="^info:eu-repo/grantAgreement/" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="example-doi_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- Has a non-empty title -->
|
||||
<bean id="has-title_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value=".*" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -15,9 +15,12 @@
|
||||
<bean id="selectrevieweractionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.SelectReviewerAction" scope="prototype">
|
||||
<property name="role" ref="scoreassignedreviewer"/>
|
||||
</bean>
|
||||
<bean id="scorereviewactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction" scope="prototype"/>
|
||||
<bean id="scorereviewactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreReviewAction" scope="prototype">
|
||||
<property name="descriptionRequired" value="true"/>
|
||||
<property name="maxValue" value="5"/>
|
||||
</bean>
|
||||
<bean id="evaluationactionAPI" class="org.dspace.xmlworkflow.state.actions.processingaction.ScoreEvaluationAction" scope="prototype">
|
||||
<property name="minimumAcceptanceScore" value="50" />
|
||||
<property name="minimumAcceptanceScore" value="3" />
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -63,6 +66,12 @@
|
||||
<property name="requiresUI" value="true"/>
|
||||
</bean>
|
||||
|
||||
<bean id="ratingreviewaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
||||
<constructor-arg type="java.lang.String" value="ratingreviewaction"/>
|
||||
<property name="processingAction" ref="ratingreviewactionAPI" />
|
||||
<property name="requiresUI" value="true"/>
|
||||
</bean>
|
||||
|
||||
<!--Autmatic step that evaluates scores (workflow.score) and checks if they match the configured minimum for archiving -->
|
||||
<bean id="evaluationaction" class="org.dspace.xmlworkflow.state.actions.WorkflowActionConfig" scope="prototype">
|
||||
<constructor-arg type="java.lang.String" value="evaluationaction"/>
|
||||
|
@@ -153,6 +153,7 @@
|
||||
<bean id="scoreassignedreviewer" class="org.dspace.xmlworkflow.Role">
|
||||
<property name="scope" value="#{ T(org.dspace.xmlworkflow.Role.Scope).ITEM}"/>
|
||||
<property name="name" value="Reviewer"/>
|
||||
<property name="deleteTemporaryGroup" value="true"/>
|
||||
</bean>
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user