97425: Create "System Wide Alerts" feature

This commit is contained in:
Yana De Pauw
2022-12-23 10:35:35 +01:00
parent 4cdb66267e
commit 45e4748482
17 changed files with 1224 additions and 0 deletions

View File

@@ -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.alerts;
/**
* Enum representing the options for allowing sessions
*/
public enum AllowSessionsEnum {
ALL(0),
CURRENT(1),
ADMIN(2);
private int allowSessionsType;
AllowSessionsEnum(int allowSessionsType) {
this.allowSessionsType = allowSessionsType;
}
public int getValue() {
return allowSessionsType;
}
public static AllowSessionsEnum fromInt(Integer alertAllowSessionType) {
if (alertAllowSessionType == null) {
return AllowSessionsEnum.ALL;
}
switch (alertAllowSessionType) {
case 0:
return AllowSessionsEnum.ALL;
case 1:
return AllowSessionsEnum.CURRENT;
case 2:
return AllowSessionsEnum.ADMIN;
default:
throw new IllegalArgumentException("No corresponding enum value for integer");
}
}
}

View 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 int 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 int getAllowSessions() {
return 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(final int allowSessions) {
this.allowSessions = allowSessions;
}
/**
* 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();
}
}

View File

@@ -0,0 +1,110 @@
/**
* 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.dspace.eperson.service.EPersonService;
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;
@Autowired
private EPersonService ePersonService;
public SystemWideAlert create(final Context context, final String message,
final AllowSessionsEnum allowSessionsType,
final Date countdownTo, final boolean active) throws SQLException {
SystemWideAlert systemWideAlert = new SystemWideAlert();
systemWideAlert.setMessage(message);
systemWideAlert.setAllowSessions(allowSessionsType.getValue());
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;
}
public SystemWideAlert find(final Context context, final int alertId) throws SQLException {
return systemWideAlertDAO.findByID(context, SystemWideAlert.class, alertId);
}
public List<SystemWideAlert> findAll(final Context context) throws SQLException {
return systemWideAlertDAO.findAll(context, SystemWideAlert.class);
}
public List<SystemWideAlert> findAll(final Context context, final int limit, final int offset) throws SQLException {
return systemWideAlertDAO.findAll(context, limit, offset);
}
public List<SystemWideAlert> findAllActive(final Context context, final int limit, final int offset)
throws SQLException {
return systemWideAlertDAO.findAllActive(context, limit, offset);
}
public void delete(final Context context, final SystemWideAlert systemWideAlert)
throws SQLException, IOException, AuthorizeException {
systemWideAlertDAO.delete(context, systemWideAlert);
log.info(LogHelper.getHeader(context, "system_wide_alert_create",
"System Wide Alert with ID " + systemWideAlert.getID() + " has been deleted"));
}
public void update(final Context context, final SystemWideAlert systemWideAlert) throws SQLException {
systemWideAlertDAO.save(context, systemWideAlert);
}
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.ALL.getValue();
}
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.ADMIN.getValue();
}
}

View File

@@ -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;
}

View File

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

View File

@@ -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 ProcessService 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;
/**
* 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;
/**
* 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;
}

View File

@@ -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 INTEGER,
countdown_to TIMESTAMP,
active BOOLEAN
);

View File

@@ -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 INTEGER,
countdown_to TIMESTAMP,
active BOOLEAN
);

View File

@@ -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 INTEGER,
countdown_to TIMESTAMP,
active BOOLEAN
);

View File

@@ -0,0 +1,39 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.converter;
import org.dspace.alerts.SystemWideAlert;
import org.dspace.app.rest.model.SystemWideAlertRest;
import org.dspace.app.rest.projection.Projection;
import org.springframework.stereotype.Component;
/**
* This converter will convert an object of {@Link SystemWideAlert} to an object of {@link SystemWideAlertRest}
*/
@Component
public class SystemWideAlertConverter implements DSpaceConverter<SystemWideAlert, SystemWideAlertRest> {
@Override
public SystemWideAlertRest convert(SystemWideAlert systemWideAlert, Projection projection) {
SystemWideAlertRest systemWideAlertRest = new SystemWideAlertRest();
systemWideAlertRest.setProjection(projection);
systemWideAlertRest.setId(systemWideAlert.getID());
systemWideAlertRest.setAlertId(systemWideAlert.getID());
systemWideAlertRest.setMessage(systemWideAlert.getMessage());
systemWideAlertRest.setAllowSessions(systemWideAlert.getAllowSessions());
systemWideAlertRest.setCountdownTo(systemWideAlert.getCountdownTo());
systemWideAlertRest.setActive(systemWideAlert.isActive());
return systemWideAlertRest;
}
@Override
public Class<SystemWideAlert> getModelClass() {
return SystemWideAlert.class;
}
}

View File

@@ -0,0 +1,88 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.alerts.SystemWideAlert;
import org.dspace.app.rest.RestResourceController;
/**
* This class serves as a REST representation for the {@link SystemWideAlert} class
*/
public class SystemWideAlertRest extends BaseObjectRest<Integer> {
public static final String NAME = "systemwidealert";
public static final String CATEGORY = RestAddressableModel.SYSTEM;
public String getCategory() {
return CATEGORY;
}
public Class getController() {
return RestResourceController.class;
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
private Integer alertId;
private String message;
private Integer allowSessions;
private Date countdownTo;
private boolean active;
public Integer getAlertId() {
return alertId;
}
public void setAlertId(final Integer alertID) {
this.alertId = alertID;
}
public String getMessage() {
return message;
}
public void setMessage(final String message) {
this.message = message;
}
public Integer getAllowSessions() {
return allowSessions;
}
public void setAllowSessions(final Integer allowSessions) {
this.allowSessions = allowSessions;
}
public Date getCountdownTo() {
return countdownTo;
}
public void setCountdownTo(final Date countdownTo) {
this.countdownTo = countdownTo;
}
public boolean isActive() {
return active;
}
public void setActive(final boolean active) {
this.active = active;
}
@JsonIgnore
@Override
public Integer getId() {
return id;
}
}

View File

@@ -0,0 +1,23 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model.hateoas;
import org.dspace.alerts.SystemWideAlert;
import org.dspace.app.rest.model.SystemWideAlertRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
import org.dspace.app.rest.utils.Utils;
/**
* The Resource representation of a {@link SystemWideAlert} object
*/
@RelNameDSpaceResource(SystemWideAlertRest.NAME)
public class SystemWideAlertResource extends DSpaceResource<SystemWideAlertRest> {
public SystemWideAlertResource(SystemWideAlertRest content, Utils utils) {
super(content, utils);
}
}

View File

@@ -0,0 +1,164 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.repository;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.alerts.AllowSessionsEnum;
import org.dspace.alerts.SystemWideAlert;
import org.dspace.alerts.service.SystemWideAlertService;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.SystemWideAlertRest;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
* The repository for the SystemWideAlert workload
*/
@Component(SystemWideAlertRest.CATEGORY + "." + SystemWideAlertRest.NAME)
public class SystemWideAlertRestRepository extends DSpaceRestRepository<SystemWideAlertRest, Integer> {
private static final Logger log = LogManager.getLogger();
@Autowired
private SystemWideAlertService systemWideAlertService;
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected SystemWideAlertRest createAndReturn(Context context) throws SQLException, AuthorizeException {
SystemWideAlert systemWideAlert = createSystemWideAlert(context);
return converter.toRest(systemWideAlert, utils.obtainProjection());
}
@Override
@PreAuthorize("permitAll()")
public SystemWideAlertRest findOne(Context context, Integer id) {
try {
SystemWideAlert systemWideAlert = systemWideAlertService.find(context, id);
if (systemWideAlert == null) {
throw new ResourceNotFoundException(
"systemWideAlert with id " + systemWideAlert.getID() + " was not found");
}
return converter.toRest(systemWideAlert, utils.obtainProjection());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
@Override
@PreAuthorize("permitAll()")
public Page<SystemWideAlertRest> findAll(Context context, Pageable pageable) {
try {
List<SystemWideAlert> systemWideAlerts = systemWideAlertService.findAll(context, pageable.getPageSize(),
Math.toIntExact(
pageable.getOffset()));
return converter.toRestPage(systemWideAlerts, pageable, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected SystemWideAlertRest put(Context context, HttpServletRequest request, String apiCategory, String model,
Integer id, JsonNode jsonNode) throws SQLException, AuthorizeException {
SystemWideAlertRest systemWideAlertRest;
try {
systemWideAlertRest = new ObjectMapper().readValue(jsonNode.toString(), SystemWideAlertRest.class);
} catch (JsonProcessingException e) {
throw new UnprocessableEntityException("Cannot parse JSON in request body", e);
}
if (systemWideAlertRest == null || isBlank(systemWideAlertRest.getMessage())) {
throw new UnprocessableEntityException("system alert message cannot be blank");
}
SystemWideAlert systemWideAlert = systemWideAlertService.find(context, id);
if (systemWideAlert == null) {
throw new ResourceNotFoundException("system wide alert with id: " + id + " not found");
}
systemWideAlert.setMessage(systemWideAlertRest.getMessage());
systemWideAlert.setAllowSessions(systemWideAlertRest.getAllowSessions());
systemWideAlert.setCountdownTo(systemWideAlertRest.getCountdownTo());
systemWideAlert.setActive(systemWideAlertRest.isActive());
systemWideAlertService.update(context, systemWideAlert);
context.commit();
return converter.toRest(systemWideAlert, utils.obtainProjection());
}
/**
* Helper method to create a system-wide alert and deny creation when one already exists
* @param context The database context
* @return the created system-wide alert
* @throws SQLException
*/
private SystemWideAlert createSystemWideAlert(Context context)
throws SQLException {
List<SystemWideAlert> all = systemWideAlertService.findAll(context);
if (!all.isEmpty()) {
throw new DSpaceBadRequestException("A system wide alert already exists, no new value can be created. " +
"Try updating the existing one.");
}
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
ObjectMapper mapper = new ObjectMapper();
SystemWideAlertRest systemWideAlertRest;
try {
ServletInputStream input = req.getInputStream();
systemWideAlertRest = mapper.readValue(input, SystemWideAlertRest.class);
} catch (IOException e1) {
throw new UnprocessableEntityException("Error parsing request body.", e1);
}
SystemWideAlert systemWideAlert;
try {
systemWideAlert = systemWideAlertService.create(context, systemWideAlertRest.getMessage(),
AllowSessionsEnum.fromInt(
systemWideAlertRest.getAllowSessions()),
systemWideAlertRest.getCountdownTo(),
systemWideAlertRest.isActive());
systemWideAlertService.update(context, systemWideAlert);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
return systemWideAlert;
}
@Override
public Class<SystemWideAlertRest> getDomainClass() {
return SystemWideAlertRest.class;
}
}

View File

@@ -0,0 +1,293 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static com.jayway.jsonpath.JsonPath.read;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.alerts.AllowSessionsEnum;
import org.dspace.alerts.SystemWideAlert;
import org.dspace.alerts.service.SystemWideAlertService;
import org.dspace.app.rest.model.SystemWideAlertRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.authorize.AuthorizeException;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Test class to test the operations in the SystemWideAlertRestRepository
*/
public class SystemWideAlertRestRepositoryIT extends AbstractControllerIntegrationTest {
private static final Logger log = LogManager.getLogger(SystemWideAlertRestRepositoryIT.class);
@Autowired
private SystemWideAlertService systemWideAlertService;
@After
public void destroy() throws Exception {
context.turnOffAuthorisationSystem();
systemWideAlertService.findAll(context).stream().forEach(systemWideAlert -> {
try {
systemWideAlertService.delete(context, systemWideAlert);
} catch (SQLException | IOException | AuthorizeException e) {
log.error(e);
}
});
context.restoreAuthSystemState();
super.destroy();
}
@Test
public void findAllTest() throws Exception {
Date countdownDate = new Date();
SystemWideAlert systemWideAlert1 = systemWideAlertService.create(context, "Test alert 1",
AllowSessionsEnum.CURRENT, countdownDate,
true);
SystemWideAlert systemWideAlert2 = systemWideAlertService.create(context, "Test alert 2",
AllowSessionsEnum.ADMIN, null,
false);
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
getClient().perform(get("/api/system/systemwidealerts/"))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.systemwidealerts", containsInAnyOrder(
allOf(
hasJsonPath("$.alertId", is(systemWideAlert1.getID())),
hasJsonPath("$.message", is(systemWideAlert1.getMessage())),
hasJsonPath("$.allowSessions", is(systemWideAlert1.getAllowSessions())),
hasJsonPath("$.countdownTo",
startsWith(sdf.format(systemWideAlert1.getCountdownTo()))),
hasJsonPath("$.active", is(systemWideAlert1.isActive()))
),
allOf(
hasJsonPath("$.alertId", is(systemWideAlert2.getID())),
hasJsonPath("$.message", is(systemWideAlert2.getMessage())),
hasJsonPath("$.allowSessions", is(systemWideAlert2.getAllowSessions())),
hasJsonPath("$.countdownTo", is(systemWideAlert2.getCountdownTo())),
hasJsonPath("$.active", is(systemWideAlert2.isActive()))
)
)));
}
@Test
public void findOneTest() throws Exception {
Date countdownDate = new Date();
SystemWideAlert systemWideAlert1 = systemWideAlertService.create(context, "Test alert 1",
AllowSessionsEnum.CURRENT, countdownDate,
true);
SystemWideAlert systemWideAlert2 = systemWideAlertService.create(context, "Test alert 2",
AllowSessionsEnum.ADMIN, null,
false);
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
getClient().perform(get("/api/system/systemwidealerts/" + systemWideAlert1.getID()))
.andExpect(status().isOk())
.andExpect(
jsonPath("$", allOf(
hasJsonPath("$.alertId", is(systemWideAlert1.getID())),
hasJsonPath("$.message", is(systemWideAlert1.getMessage())),
hasJsonPath("$.allowSessions", is(systemWideAlert1.getAllowSessions())),
hasJsonPath("$.countdownTo",
startsWith(sdf.format(systemWideAlert1.getCountdownTo()))),
hasJsonPath("$.active", is(systemWideAlert1.isActive()))
)
));
}
@Test
public void createTest() throws Exception {
SystemWideAlertRest systemWideAlertRest = new SystemWideAlertRest();
systemWideAlertRest.setMessage("Alert test message");
systemWideAlertRest.setCountdownTo(new Date());
systemWideAlertRest.setAllowSessions(1);
systemWideAlertRest.setActive(true);
ObjectMapper mapper = new ObjectMapper();
String authToken = getAuthToken(admin.getEmail(), password);
AtomicReference<Integer> idRef = new AtomicReference<>();
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
getClient(authToken).perform(post("/api/system/systemwidealerts/")
.content(mapper.writeValueAsBytes(systemWideAlertRest))
.contentType(contentType))
.andExpect(status().isCreated())
.andExpect(
jsonPath("$", allOf(
hasJsonPath("$.alertId"),
hasJsonPath("$.message", is(systemWideAlertRest.getMessage())),
hasJsonPath("$.allowSessions",
is(systemWideAlertRest.getAllowSessions())),
hasJsonPath("$.countdownTo",
startsWith(sdf.format(systemWideAlertRest.getCountdownTo()))),
hasJsonPath("$.active", is(systemWideAlertRest.isActive()))
)
))
.andDo(result -> idRef
.set((read(result.getResponse().getContentAsString(), "$.alertId"))));
getClient().perform(get("/api/system/systemwidealerts/" + idRef.get()))
.andExpect(status().isOk())
.andExpect(
jsonPath("$", allOf(
hasJsonPath("$.alertId", is(idRef.get())),
hasJsonPath("$.message", is(systemWideAlertRest.getMessage())),
hasJsonPath("$.allowSessions", is(systemWideAlertRest.getAllowSessions())),
hasJsonPath("$.countdownTo",
startsWith(sdf.format(systemWideAlertRest.getCountdownTo()))),
hasJsonPath("$.active", is(systemWideAlertRest.isActive()))
)
));
}
@Test
public void createForbiddenTest() throws Exception {
SystemWideAlertRest systemWideAlertRest = new SystemWideAlertRest();
systemWideAlertRest.setMessage("Alert test message");
systemWideAlertRest.setCountdownTo(new Date());
systemWideAlertRest.setAllowSessions(1);
systemWideAlertRest.setActive(true);
ObjectMapper mapper = new ObjectMapper();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(post("/api/system/systemwidealerts/")
.content(mapper.writeValueAsBytes(systemWideAlertRest))
.contentType(contentType))
.andExpect(status().isForbidden());
}
@Test
public void createUnAuthorizedTest() throws Exception {
SystemWideAlertRest systemWideAlertRest = new SystemWideAlertRest();
systemWideAlertRest.setMessage("Alert test message");
systemWideAlertRest.setCountdownTo(new Date());
systemWideAlertRest.setAllowSessions(1);
systemWideAlertRest.setActive(true);
ObjectMapper mapper = new ObjectMapper();
getClient().perform(post("/api/system/systemwidealerts/")
.content(mapper.writeValueAsBytes(systemWideAlertRest))
.contentType(contentType))
.andExpect(status().isUnauthorized());
}
@Test
public void createWhenAlreadyExistsTest() throws Exception {
SystemWideAlert systemWideAlert = systemWideAlertService.create(context, "Test alert",
AllowSessionsEnum.ADMIN, null,
false);
SystemWideAlertRest systemWideAlertRest = new SystemWideAlertRest();
systemWideAlertRest.setMessage("Alert test message");
systemWideAlertRest.setCountdownTo(new Date());
systemWideAlertRest.setAllowSessions(1);
systemWideAlertRest.setActive(true);
ObjectMapper mapper = new ObjectMapper();
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/system/systemwidealerts/")
.content(mapper.writeValueAsBytes(systemWideAlertRest))
.contentType(contentType))
.andExpect(status().isBadRequest());
}
@Test
public void putTest() throws Exception {
SystemWideAlert systemWideAlert = systemWideAlertService.create(context, "Alert test message",
AllowSessionsEnum.ADMIN, null,
false);
SystemWideAlertRest systemWideAlertRest = new SystemWideAlertRest();
systemWideAlertRest.setAlertId(systemWideAlert.getID());
systemWideAlertRest.setMessage("Updated alert test message");
systemWideAlertRest.setCountdownTo(new Date());
systemWideAlertRest.setAllowSessions(1);
systemWideAlertRest.setActive(true);
ObjectMapper mapper = new ObjectMapper();
String authToken = getAuthToken(admin.getEmail(), password);
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
getClient(authToken).perform(put("/api/system/systemwidealerts/" + systemWideAlert.getID())
.content(mapper.writeValueAsBytes(systemWideAlertRest))
.contentType(contentType))
.andExpect(status().isOk())
.andExpect(
jsonPath("$", allOf(
hasJsonPath("$.alertId"),
hasJsonPath("$.message", is(systemWideAlertRest.getMessage())),
hasJsonPath("$.allowSessions",
is(systemWideAlertRest.getAllowSessions())),
hasJsonPath("$.countdownTo",
startsWith(sdf.format(systemWideAlertRest.getCountdownTo()))),
hasJsonPath("$.active", is(systemWideAlertRest.isActive()))
)
));
getClient().perform(get("/api/system/systemwidealerts/" + systemWideAlert.getID()))
.andExpect(status().isOk())
.andExpect(
jsonPath("$", allOf(
hasJsonPath("$.alertId", is(systemWideAlert.getID())),
hasJsonPath("$.message", is(systemWideAlertRest.getMessage())),
hasJsonPath("$.allowSessions", is(systemWideAlertRest.getAllowSessions())),
hasJsonPath("$.countdownTo",
startsWith(sdf.format(systemWideAlertRest.getCountdownTo()))),
hasJsonPath("$.active", is(systemWideAlertRest.isActive()))
)
));
}
}

View File

@@ -54,6 +54,7 @@
<mapping class="org.dspace.content.EntityType"/> <mapping class="org.dspace.content.EntityType"/>
<mapping class="org.dspace.scripts.Process"/> <mapping class="org.dspace.scripts.Process"/>
<mapping class="org.dspace.alerts.SystemWideAlert"/>
<mapping class="org.dspace.content.MetadataField"/> <mapping class="org.dspace.content.MetadataField"/>
<mapping class="org.dspace.content.MetadataSchema"/> <mapping class="org.dspace.content.MetadataSchema"/>

View File

@@ -34,6 +34,8 @@
<bean class="org.dspace.content.dao.impl.ProcessDAOImpl"/> <bean class="org.dspace.content.dao.impl.ProcessDAOImpl"/>
<bean class="org.dspace.alerts.dao.impl.SystemWideAlertDAOImpl"/>
<bean class="org.dspace.eperson.dao.impl.EPersonDAOImpl"/> <bean class="org.dspace.eperson.dao.impl.EPersonDAOImpl"/>
<bean class="org.dspace.eperson.dao.impl.Group2GroupCacheDAOImpl"/> <bean class="org.dspace.eperson.dao.impl.Group2GroupCacheDAOImpl"/>
<bean class="org.dspace.eperson.dao.impl.GroupDAOImpl"/> <bean class="org.dspace.eperson.dao.impl.GroupDAOImpl"/>

View File

@@ -60,6 +60,8 @@
<bean class="org.dspace.scripts.ProcessServiceImpl"/> <bean class="org.dspace.scripts.ProcessServiceImpl"/>
<bean class="org.dspace.scripts.ScriptServiceImpl"/> <bean class="org.dspace.scripts.ScriptServiceImpl"/>
<bean class="org.dspace.alerts.SystemWideAlertServiceImpl"/>
<bean class="org.dspace.content.authority.ChoiceAuthorityServiceImpl"/> <bean class="org.dspace.content.authority.ChoiceAuthorityServiceImpl"/>
<bean class="org.dspace.content.authority.MetadataAuthorityServiceImpl" lazy-init="true"/> <bean class="org.dspace.content.authority.MetadataAuthorityServiceImpl" lazy-init="true"/>