Add Email Notifications when one of the collaborators is editing either a DMP or a Dataset (ref #244)
This commit is contained in:
parent
f4cd087672
commit
25988ab272
|
@ -0,0 +1,26 @@
|
||||||
|
package eu.eudat.data.dao.criteria;
|
||||||
|
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
|
|
||||||
|
public class NotificationCriteria {
|
||||||
|
|
||||||
|
private ActiveStatus isActive;
|
||||||
|
private NotifyState notifyState;
|
||||||
|
|
||||||
|
public ActiveStatus getIsActive() {
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsActive(ActiveStatus isActive) {
|
||||||
|
this.isActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotifyState getNotifyState() {
|
||||||
|
return notifyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotifyState(NotifyState notifyState) {
|
||||||
|
this.notifyState = notifyState;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package eu.eudat.data.dao.entities;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.DatabaseAccessLayer;
|
||||||
|
import eu.eudat.data.dao.criteria.NotificationCriteria;
|
||||||
|
import eu.eudat.data.entities.Notification;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface NotificationDao extends DatabaseAccessLayer<Notification, UUID> {
|
||||||
|
|
||||||
|
QueryableList<Notification> getWithCriteria(NotificationCriteria criteria);
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package eu.eudat.data.dao.entities;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.DatabaseAccess;
|
||||||
|
import eu.eudat.data.dao.criteria.NotificationCriteria;
|
||||||
|
import eu.eudat.data.dao.databaselayer.service.DatabaseService;
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.data.entities.Notification;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Service("NotificationDao")
|
||||||
|
public class NotificationDaoImpl extends DatabaseAccess<Notification> implements NotificationDao {
|
||||||
|
@Autowired
|
||||||
|
public NotificationDaoImpl(DatabaseService<Notification> databaseService) {
|
||||||
|
super(databaseService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryableList<Notification> getWithCriteria(NotificationCriteria criteria) {
|
||||||
|
QueryableList<Notification> query = this.getDatabaseService().getQueryable(Notification.class);
|
||||||
|
if (criteria.getIsActive() != null)
|
||||||
|
query.where((builder, root) -> builder.equal(root.get("isActive"), criteria.getIsActive()));
|
||||||
|
if (criteria.getNotifyState() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("notifyState"), criteria.getNotifyState())));
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Notification createOrUpdate(Notification item) {
|
||||||
|
return this.getDatabaseService().createOrUpdate(item, Notification.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Notification> createOrUpdateAsync(Notification item) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> this.getDatabaseService().createOrUpdate(item, Notification.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Notification find(UUID id) {
|
||||||
|
return this.getDatabaseService().getQueryable(Notification.class).where(((builder, root) -> builder.equal(root.get("id"), id))).getSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Notification find(UUID id, String hint) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Notification item) {
|
||||||
|
this.getDatabaseService().delete(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryableList<Notification> asQueryable() {
|
||||||
|
return this.getDatabaseService().getQueryable(Notification.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
package eu.eudat.data.entities;
|
||||||
|
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.ContactType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotificationType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
|
import eu.eudat.queryable.queryableentity.DataEntity;
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "\"Notification\"")
|
||||||
|
public class Notification implements DataEntity<Notification, UUID> {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||||
|
@Column(name = "id", updatable = false, nullable = false, columnDefinition = "BINARY(16)")
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "\"UserId\"")
|
||||||
|
private UserInfo userId;
|
||||||
|
|
||||||
|
@Enumerated
|
||||||
|
@Column(name = "\"IsActive\"", nullable = false)
|
||||||
|
private ActiveStatus isActive;
|
||||||
|
|
||||||
|
@Enumerated
|
||||||
|
@Column(name = "\"Type\"", nullable = false)
|
||||||
|
private NotificationType type;
|
||||||
|
|
||||||
|
@Enumerated
|
||||||
|
@Column(name = "\"ContactTypeHint\"")
|
||||||
|
private ContactType contactTypeHint;
|
||||||
|
|
||||||
|
@Column(name = "\"ContactHint\"")
|
||||||
|
private String contactHint;
|
||||||
|
|
||||||
|
@Column(name = "\"Data\"")
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
@Enumerated
|
||||||
|
@Column(name = "\"NotifyState\"")
|
||||||
|
private NotifyState notifyState;
|
||||||
|
|
||||||
|
@Column(name = "\"NotifiedAt\"")
|
||||||
|
private Date notifiedAt;
|
||||||
|
|
||||||
|
@Column(name = "\"RetryCount\"")
|
||||||
|
private Integer retryCount;
|
||||||
|
|
||||||
|
@Column(name = "\"CreatedAt\"")
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
@Column(name = "\"UpdatedAt\"")
|
||||||
|
private Date updatedAt;
|
||||||
|
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(UserInfo userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActiveStatus getIsActive() {
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsActive(ActiveStatus isActive) {
|
||||||
|
this.isActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(NotificationType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactType getContactTypeHint() {
|
||||||
|
return contactTypeHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactTypeHint(ContactType contactTypeHint) {
|
||||||
|
this.contactTypeHint = contactTypeHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContactHint() {
|
||||||
|
return contactHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactHint(String contactHint) {
|
||||||
|
this.contactHint = contactHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotifyState getNotifyState() {
|
||||||
|
return notifyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotifyState(NotifyState notifyState) {
|
||||||
|
this.notifyState = notifyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getNotifiedAt() {
|
||||||
|
return notifiedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotifiedAt(Date notifiedAt) {
|
||||||
|
this.notifiedAt = notifiedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRetryCount() {
|
||||||
|
return retryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetryCount(Integer retryCount) {
|
||||||
|
this.retryCount = retryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Notification entity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getKeys() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Notification buildFromTuple(List<Tuple> tuple, List<String> fields, String base) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -72,6 +72,9 @@ public class UserInfo implements DataEntity<UserInfo, UUID> {
|
||||||
@OneToMany(mappedBy = "lockedBy", fetch = FetchType.LAZY)
|
@OneToMany(mappedBy = "lockedBy", fetch = FetchType.LAZY)
|
||||||
private Set<Lock> locks = new HashSet<>();
|
private Set<Lock> locks = new HashSet<>();
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "userId", fetch = FetchType.LAZY)
|
||||||
|
private Set<Notification> notifications = new HashSet<>();
|
||||||
|
|
||||||
public Set<DMP> getDmps() {
|
public Set<DMP> getDmps() {
|
||||||
return dmps;
|
return dmps;
|
||||||
}
|
}
|
||||||
|
@ -176,6 +179,14 @@ public class UserInfo implements DataEntity<UserInfo, UUID> {
|
||||||
this.locks = locks;
|
this.locks = locks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Notification> getNotifications() {
|
||||||
|
return notifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotifications(Set<Notification> notifications) {
|
||||||
|
this.notifications = notifications;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(UserInfo entity) {
|
public void update(UserInfo entity) {
|
||||||
this.name = entity.getName();
|
this.name = entity.getName();
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package eu.eudat.data.enumeration.notification;
|
||||||
|
|
||||||
|
public enum ActiveStatus {
|
||||||
|
ACTIVE(0),
|
||||||
|
INACTIVE(1);
|
||||||
|
|
||||||
|
private int status;
|
||||||
|
|
||||||
|
ActiveStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActiveStatus fromInteger(int status) {
|
||||||
|
switch (status) {
|
||||||
|
case 0:
|
||||||
|
return ACTIVE;
|
||||||
|
case 1:
|
||||||
|
return INACTIVE;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unsupported Active Status");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.eudat.data.enumeration.notification;
|
||||||
|
|
||||||
|
public enum ContactType {
|
||||||
|
EMAIL(0);
|
||||||
|
|
||||||
|
private int type;
|
||||||
|
|
||||||
|
ContactType(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactType fromInteger(int type) {
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
return EMAIL;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unsupported Contact Type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package eu.eudat.data.enumeration.notification;
|
||||||
|
|
||||||
|
public enum NotificationType {
|
||||||
|
DMP_MODIFIED(0),
|
||||||
|
DATASET_MODIFIED(1);
|
||||||
|
|
||||||
|
private int type;
|
||||||
|
|
||||||
|
NotificationType(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationType fromInteger(int type) {
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
return DMP_MODIFIED;
|
||||||
|
case 1:
|
||||||
|
return DATASET_MODIFIED;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unsupported Notification Type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.eudat.data.enumeration.notification;
|
||||||
|
|
||||||
|
public enum NotifyState {
|
||||||
|
PENDING(0),
|
||||||
|
PROCESSING(1),
|
||||||
|
SENDING(2),
|
||||||
|
SUCCEEDED(3),
|
||||||
|
ERROR(4);
|
||||||
|
|
||||||
|
private int state;
|
||||||
|
|
||||||
|
NotifyState(int state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotifyState fromInteger(int state) {
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
return PENDING;
|
||||||
|
case 1:
|
||||||
|
return PROCESSING;
|
||||||
|
case 2:
|
||||||
|
return SENDING;
|
||||||
|
case 3:
|
||||||
|
return SUCCEEDED;
|
||||||
|
case 4:
|
||||||
|
return ERROR;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unsupported Notify State");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import eu.eudat.logic.services.operations.authentication.AuthenticationService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
|
@ -15,6 +16,7 @@ import java.util.List;
|
||||||
|
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
public class WebMVCConfiguration extends WebMvcConfigurerAdapter {
|
public class WebMVCConfiguration extends WebMvcConfigurerAdapter {
|
||||||
|
|
||||||
private ApiContext apiContext;
|
private ApiContext apiContext;
|
||||||
|
|
|
@ -9,6 +9,10 @@ import eu.eudat.data.dao.entities.*;
|
||||||
import eu.eudat.data.entities.Organisation;
|
import eu.eudat.data.entities.Organisation;
|
||||||
import eu.eudat.data.entities.Researcher;
|
import eu.eudat.data.entities.Researcher;
|
||||||
import eu.eudat.data.entities.*;
|
import eu.eudat.data.entities.*;
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.ContactType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotificationType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
import eu.eudat.data.query.items.item.dmp.DataManagementPlanCriteriaRequest;
|
import eu.eudat.data.query.items.item.dmp.DataManagementPlanCriteriaRequest;
|
||||||
import eu.eudat.data.query.items.table.datasetprofile.DatasetProfileTableRequestItem;
|
import eu.eudat.data.query.items.table.datasetprofile.DatasetProfileTableRequestItem;
|
||||||
import eu.eudat.data.query.items.table.dmp.DataManagementPlanTableRequest;
|
import eu.eudat.data.query.items.table.dmp.DataManagementPlanTableRequest;
|
||||||
|
@ -474,7 +478,7 @@ public class DataManagementPlanManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DMP createOrUpdate(ApiContext apiContext, DataManagementPlanEditorModel dataManagementPlan, Principal principal) throws Exception {
|
public DMP createOrUpdate(ApiContext apiContext, DataManagementPlanEditorModel dataManagementPlan, Principal principal) throws Exception {
|
||||||
|
boolean setNotification = false;
|
||||||
if (dataManagementPlan.getId() != null) {
|
if (dataManagementPlan.getId() != null) {
|
||||||
DMP dmp1 = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(dataManagementPlan.getId());
|
DMP dmp1 = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(dataManagementPlan.getId());
|
||||||
|
|
||||||
|
@ -491,6 +495,8 @@ public class DataManagementPlanManager {
|
||||||
}
|
}
|
||||||
if (dataManagementPlan.getStatus() == (int) DMP.DMPStatus.FINALISED.getValue() && dmp1.getStatus().equals(DMP.DMPStatus.FINALISED.getValue()))
|
if (dataManagementPlan.getStatus() == (int) DMP.DMPStatus.FINALISED.getValue() && dmp1.getStatus().equals(DMP.DMPStatus.FINALISED.getValue()))
|
||||||
throw new Exception("DMP is finalized, therefore cannot be edited.");
|
throw new Exception("DMP is finalized, therefore cannot be edited.");
|
||||||
|
|
||||||
|
setNotification = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMP newDmp = dataManagementPlan.toDataModel();
|
DMP newDmp = dataManagementPlan.toDataModel();
|
||||||
|
@ -568,9 +574,38 @@ public class DataManagementPlanManager {
|
||||||
if (dataManagementPlan.getAssociatedUsers().size() == 0)
|
if (dataManagementPlan.getAssociatedUsers().size() == 0)
|
||||||
assignUser(newDmp, user);
|
assignUser(newDmp, user);
|
||||||
|
|
||||||
|
if (setNotification) {
|
||||||
|
this.sendNotification(newDmp, user);
|
||||||
|
}
|
||||||
|
|
||||||
return newDmp;
|
return newDmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendNotification(DMP dmp, UserInfo user) {
|
||||||
|
List<UserDMP> userDMPS = databaseRepository.getUserDmpDao().asQueryable().where(((builder, root) -> builder.equal(root.get("dmp").get("id"), dmp.getId()))).toList();
|
||||||
|
for (UserDMP userDMP : userDMPS) {
|
||||||
|
if (!userDMP.getUser().getId().equals(user.getId())) {
|
||||||
|
Notification notification = new Notification();
|
||||||
|
notification.setUserId(user);
|
||||||
|
notification.setType(NotificationType.DMP_MODIFIED);
|
||||||
|
notification.setNotifyState(NotifyState.PENDING);
|
||||||
|
notification.setIsActive(ActiveStatus.ACTIVE);
|
||||||
|
notification.setData("{" +
|
||||||
|
"\"userId\": \"" + userDMP.getUser().getId() + "\"" +
|
||||||
|
", \"id\": \"" + userDMP.getDmp().getId() + "\"" +
|
||||||
|
", \"name\": \"" + userDMP.getDmp().getLabel() + "\"" +
|
||||||
|
", \"path\": \"/plans/edit\"" +
|
||||||
|
"}");
|
||||||
|
notification.setCreatedAt(new Date());
|
||||||
|
notification.setUpdatedAt(notification.getCreatedAt());
|
||||||
|
notification.setContactTypeHint(ContactType.EMAIL);
|
||||||
|
notification.setContactHint(userDMP.getUser().getEmail());
|
||||||
|
databaseRepository.getNotificationDao().createOrUpdate(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assignUser(DMP dmp, UserInfo userInfo) {
|
private void assignUser(DMP dmp, UserInfo userInfo) {
|
||||||
UserDMP userDMP = new UserDMP();
|
UserDMP userDMP = new UserDMP();
|
||||||
|
|
|
@ -5,6 +5,10 @@ import eu.eudat.data.dao.entities.DataRepositoryDao;
|
||||||
import eu.eudat.data.dao.entities.DatasetDao;
|
import eu.eudat.data.dao.entities.DatasetDao;
|
||||||
import eu.eudat.data.dao.entities.RegistryDao;
|
import eu.eudat.data.dao.entities.RegistryDao;
|
||||||
import eu.eudat.data.entities.*;
|
import eu.eudat.data.entities.*;
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.ContactType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotificationType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
import eu.eudat.data.query.items.table.dataset.DatasetPublicTableRequest;
|
import eu.eudat.data.query.items.table.dataset.DatasetPublicTableRequest;
|
||||||
import eu.eudat.data.query.items.table.dataset.DatasetTableRequest;
|
import eu.eudat.data.query.items.table.dataset.DatasetTableRequest;
|
||||||
import eu.eudat.data.query.items.table.datasetprofile.DatasetProfileTableRequestItem;
|
import eu.eudat.data.query.items.table.datasetprofile.DatasetProfileTableRequestItem;
|
||||||
|
@ -400,6 +404,7 @@ public class DatasetManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public eu.eudat.data.entities.Dataset createOrUpdate(DatasetWizardModel datasetWizardModel, Principal principal) throws Exception {
|
public eu.eudat.data.entities.Dataset createOrUpdate(DatasetWizardModel datasetWizardModel, Principal principal) throws Exception {
|
||||||
|
Boolean sendNotification = false;
|
||||||
DMP dmp = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(datasetWizardModel.getDmp().getId());
|
DMP dmp = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(datasetWizardModel.getDmp().getId());
|
||||||
if (datasetWizardModel.getId() != null) {
|
if (datasetWizardModel.getId() != null) {
|
||||||
Dataset tempDataset = apiContext.getOperationsContext().getDatabaseRepository().getDatasetDao().find(datasetWizardModel.getId());
|
Dataset tempDataset = apiContext.getOperationsContext().getDatabaseRepository().getDatasetDao().find(datasetWizardModel.getId());
|
||||||
|
@ -407,6 +412,7 @@ public class DatasetManager {
|
||||||
if (datasetWizardModel.getModified().getTime() != tempDataset.getModified().getTime()) {
|
if (datasetWizardModel.getModified().getTime() != tempDataset.getModified().getTime()) {
|
||||||
throw new Exception("Dataset has been modified already by another user.");
|
throw new Exception("Dataset has been modified already by another user.");
|
||||||
}
|
}
|
||||||
|
sendNotification = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dmp.getStatus().equals(DMP.DMPStatus.FINALISED.getValue()) && datasetWizardModel.getId() != null)
|
if (dmp.getStatus().equals(DMP.DMPStatus.FINALISED.getValue()) && datasetWizardModel.getId() != null)
|
||||||
|
@ -427,9 +433,37 @@ public class DatasetManager {
|
||||||
Dataset dataset1 = apiContext.getOperationsContext().getDatabaseRepository().getDatasetDao().createOrUpdate(dataset);
|
Dataset dataset1 = apiContext.getOperationsContext().getDatabaseRepository().getDatasetDao().createOrUpdate(dataset);
|
||||||
datasetWizardModel.setId(dataset1.getId());
|
datasetWizardModel.setId(dataset1.getId());
|
||||||
updateTags(apiContext.getOperationsContext().getDatasetRepository(), datasetWizardModel);
|
updateTags(apiContext.getOperationsContext().getDatasetRepository(), datasetWizardModel);
|
||||||
|
if (sendNotification) {
|
||||||
|
this.sendNotification(dataset1, dataset1.getDmp(), userInfo);
|
||||||
|
}
|
||||||
return dataset1;
|
return dataset1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendNotification(Dataset dataset, DMP dmp, UserInfo user) {
|
||||||
|
List<UserDMP> userDMPS = databaseRepository.getUserDmpDao().asQueryable().where(((builder, root) -> builder.equal(root.get("dmp").get("id"), dmp.getId()))).toList();
|
||||||
|
for (UserDMP userDMP : userDMPS) {
|
||||||
|
if (!userDMP.getUser().getId().equals(user.getId())) {
|
||||||
|
Notification notification = new Notification();
|
||||||
|
notification.setUserId(user);
|
||||||
|
notification.setType(NotificationType.DATASET_MODIFIED);
|
||||||
|
notification.setNotifyState(NotifyState.PENDING);
|
||||||
|
notification.setIsActive(ActiveStatus.ACTIVE);
|
||||||
|
notification.setData("{" +
|
||||||
|
"\"userId\": \"" + userDMP.getUser().getId() + "\"" +
|
||||||
|
", \"id\": \"" + dataset.getId() + "\"" +
|
||||||
|
", \"name\": \"" + dataset.getLabel() + "\"" +
|
||||||
|
", \"path\": \"/datasets/edit\"" +
|
||||||
|
"}");
|
||||||
|
notification.setCreatedAt(new Date());
|
||||||
|
notification.setUpdatedAt(notification.getCreatedAt());
|
||||||
|
notification.setContactTypeHint(ContactType.EMAIL);
|
||||||
|
notification.setContactHint(userDMP.getUser().getEmail());
|
||||||
|
databaseRepository.getNotificationDao().createOrUpdate(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void checkDatasetValidation(Dataset dataset) throws Exception {
|
private void checkDatasetValidation(Dataset dataset) throws Exception {
|
||||||
List<String> datasetProfileValidators = new LinkedList<>();
|
List<String> datasetProfileValidators = new LinkedList<>();
|
||||||
DatasetProfile profile = apiContext.getOperationsContext().getDatabaseRepository().getDatasetProfileDao().find(dataset.getProfile().getId());
|
DatasetProfile profile = apiContext.getOperationsContext().getDatabaseRepository().getDatasetProfileDao().find(dataset.getProfile().getId());
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
package eu.eudat.logic.managers;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import eu.eudat.data.entities.Notification;
|
||||||
|
import eu.eudat.data.entities.UserInfo;
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotificationType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
|
import eu.eudat.logic.services.ApiContext;
|
||||||
|
import eu.eudat.logic.services.utilities.MailService;
|
||||||
|
import eu.eudat.models.data.mail.SimpleMail;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NotificationManager {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(NotificationManager.class);
|
||||||
|
|
||||||
|
private ApiContext apiContext;
|
||||||
|
private Environment environment;
|
||||||
|
private MailService mailService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public NotificationManager(ApiContext apiContext, Environment environment, MailService mailService) {
|
||||||
|
this.apiContext = apiContext;
|
||||||
|
this.environment = environment;
|
||||||
|
this.mailService = mailService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void sendNotification(Notification notification) throws Exception {
|
||||||
|
if (notification.getNotifyState() == NotifyState.ERROR) {
|
||||||
|
if (notification.getRetryCount() == null) {
|
||||||
|
notification.setRetryCount(0);
|
||||||
|
}
|
||||||
|
notification.setRetryCount(notification.getRetryCount() + 1);
|
||||||
|
if (notification.getRetryCount() >= this.environment.getProperty("notification.maxRetries", Integer.class)) {
|
||||||
|
notification.setIsActive(ActiveStatus.INACTIVE);
|
||||||
|
notification.setUpdatedAt(new Date());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notification.setNotifyState(NotifyState.PROCESSING);
|
||||||
|
notification.setNotifiedAt(new Date());
|
||||||
|
notification.setUpdatedAt(new Date());
|
||||||
|
try {
|
||||||
|
Map<String, String> data = new ObjectMapper().readValue(notification.getData(), HashMap.class);
|
||||||
|
UserInfo userInfo = this.apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(UUID.fromString(data.get("userId")));
|
||||||
|
String subjectTemplate = "";
|
||||||
|
String contentTemplate = "";
|
||||||
|
|
||||||
|
switch (notification.getType()) {
|
||||||
|
case DMP_MODIFIED:
|
||||||
|
case DATASET_MODIFIED:
|
||||||
|
subjectTemplate = this.environment.getProperty("mail.modified.notification.subject");
|
||||||
|
contentTemplate = mailService.getMailTemplateContent("classpath:modifiedNotification.html");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (notification.getContactTypeHint()) {
|
||||||
|
case EMAIL:
|
||||||
|
this.sendEmailNotification(notification, userInfo, data, subjectTemplate, contentTemplate);
|
||||||
|
notification.setNotifyState(NotifyState.SUCCEEDED);
|
||||||
|
notification.setUpdatedAt(new Date());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}catch (Exception e) {
|
||||||
|
notification.setNotifyState(NotifyState.ERROR);
|
||||||
|
notification.setUpdatedAt(new Date());
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendEmailNotification(Notification notification, UserInfo userInfo, Map<String, String> data, String subjectTemplate, String contentTemplate) throws IOException {
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
SimpleMail simpleMail = new SimpleMail();
|
||||||
|
simpleMail.setFrom(this.environment.getProperty("mail.from"));
|
||||||
|
simpleMail.setSubject(makeSubject(data, subjectTemplate));
|
||||||
|
simpleMail.setTo(notification.getContactHint());
|
||||||
|
simpleMail.setContent(makeContent(data, notification, userInfo, contentTemplate));
|
||||||
|
try {
|
||||||
|
mailService.sendSimpleMail(simpleMail);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
notification.setNotifyState(NotifyState.ERROR);
|
||||||
|
notification.setUpdatedAt(new Date());
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeSubject(Map<String, String> data, String subjectTemplate) {
|
||||||
|
return subjectTemplate.replace("{name}", data.get("name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeContent(Map<String, String> data, Notification notification, UserInfo userInfo, String template) {
|
||||||
|
String content = template;
|
||||||
|
content = content.replace("{recipient}", userInfo.getName());
|
||||||
|
content = content.replace("{id}", data.get("id"));
|
||||||
|
content = content.replace("{name}", data.get("name"));
|
||||||
|
content = content.replace("{host}", this.environment.getProperty("dmp.domain"));
|
||||||
|
content = content.replace("{reasonName}", notification.getUserId().getName());
|
||||||
|
content = content.replace("{path}", data.get("path"));
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,5 +54,7 @@ public interface DatabaseRepository {
|
||||||
|
|
||||||
LockDao getLockDao();
|
LockDao getLockDao();
|
||||||
|
|
||||||
|
NotificationDao getNotificationDao();
|
||||||
|
|
||||||
<T> void detachEntity(T entity);
|
<T> void detachEntity(T entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class DatabaseRepositoryImpl implements DatabaseRepository {
|
||||||
private ProjectDao projectDao;
|
private ProjectDao projectDao;
|
||||||
private FunderDao funderDao;
|
private FunderDao funderDao;
|
||||||
private LockDao lockDao;
|
private LockDao lockDao;
|
||||||
|
private NotificationDao notificationDao;
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
|
|
||||||
|
@ -284,6 +285,16 @@ public class DatabaseRepositoryImpl implements DatabaseRepository {
|
||||||
return lockDao;
|
return lockDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotificationDao getNotificationDao() {
|
||||||
|
return notificationDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setNotificationDao(NotificationDao notificationDao) {
|
||||||
|
this.notificationDao = notificationDao;
|
||||||
|
}
|
||||||
|
|
||||||
public <T> void detachEntity(T entity) {
|
public <T> void detachEntity(T entity) {
|
||||||
this.entityManager.detach(entity);
|
this.entityManager.detach(entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.eudat.logic.utilities.schedule.notification;
|
||||||
|
|
||||||
|
import eu.eudat.data.entities.Notification;
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
|
import eu.eudat.logic.managers.NotificationManager;
|
||||||
|
import eu.eudat.logic.services.ApiContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NotificationScheduleJob {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(NotificationScheduleJob.class);
|
||||||
|
|
||||||
|
private ApiContext apiContext;
|
||||||
|
private NotificationManager notificationManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public NotificationScheduleJob(ApiContext apiContext, NotificationManager notificationManager) {
|
||||||
|
this.apiContext = apiContext;
|
||||||
|
this.notificationManager = notificationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Scheduled(fixedRateString = "${notification.rateInterval}")
|
||||||
|
public void sendNotifications() {
|
||||||
|
List<Notification> notifications = this.apiContext.getOperationsContext().getDatabaseRepository().getNotificationDao().asQueryable().where(((builder, root) ->
|
||||||
|
builder.and(
|
||||||
|
builder.or(
|
||||||
|
builder.equal(root.get("notifyState"), NotifyState.PENDING), builder.equal(root.get("notifyState"), NotifyState.ERROR))
|
||||||
|
, builder.equal(root.get("isActive"), ActiveStatus.ACTIVE)))).toList();
|
||||||
|
if (!notifications.isEmpty()) {
|
||||||
|
notifications.forEach(notification -> {
|
||||||
|
try {
|
||||||
|
this.notificationManager.sendNotification(notification);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
package eu.eudat.models.data.notiication;
|
||||||
|
|
||||||
|
import eu.eudat.data.enumeration.notification.ActiveStatus;
|
||||||
|
import eu.eudat.data.enumeration.notification.ContactType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotificationType;
|
||||||
|
import eu.eudat.data.enumeration.notification.NotifyState;
|
||||||
|
import eu.eudat.models.DataModel;
|
||||||
|
import eu.eudat.models.data.userinfo.UserInfo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Notification implements DataModel<eu.eudat.data.entities.Notification, Notification> {
|
||||||
|
|
||||||
|
private UUID id;
|
||||||
|
private UserInfo userId;
|
||||||
|
private ActiveStatus isActive;
|
||||||
|
private NotificationType type;
|
||||||
|
private ContactType contactTypeHint;
|
||||||
|
private String contactHint;
|
||||||
|
private String data;
|
||||||
|
private NotifyState notifyState;
|
||||||
|
private Date notifiedAt;
|
||||||
|
private Integer retryCount;
|
||||||
|
private Date createdAt;
|
||||||
|
private Date updatedAt;
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(UserInfo userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActiveStatus getIsActive() {
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsActive(ActiveStatus isActive) {
|
||||||
|
this.isActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(NotificationType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactType getContactTypeHint() {
|
||||||
|
return contactTypeHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactTypeHint(ContactType contactTypeHint) {
|
||||||
|
this.contactTypeHint = contactTypeHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContactHint() {
|
||||||
|
return contactHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactHint(String contactHint) {
|
||||||
|
this.contactHint = contactHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotifyState getNotifyState() {
|
||||||
|
return notifyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotifyState(NotifyState notifyState) {
|
||||||
|
this.notifyState = notifyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getNotifiedAt() {
|
||||||
|
return notifiedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotifiedAt(Date notifiedAt) {
|
||||||
|
this.notifiedAt = notifiedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRetryCount() {
|
||||||
|
return retryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetryCount(Integer retryCount) {
|
||||||
|
this.retryCount = retryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Notification fromDataModel(eu.eudat.data.entities.Notification entity) {
|
||||||
|
this.id = entity.getId();
|
||||||
|
this.contactHint = entity.getContactHint();
|
||||||
|
this.contactTypeHint = entity.getContactTypeHint();
|
||||||
|
this.createdAt = entity.getCreatedAt();
|
||||||
|
this.data = entity.getData();
|
||||||
|
this.isActive = entity.getIsActive();
|
||||||
|
this.notifiedAt = entity.getNotifiedAt();
|
||||||
|
this.notifyState = entity.getNotifyState();
|
||||||
|
this.retryCount = entity.getRetryCount();
|
||||||
|
this.type = entity.getType();
|
||||||
|
this.updatedAt = entity.getUpdatedAt();
|
||||||
|
this.userId = new UserInfo().fromDataModel(entity.getUserId());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public eu.eudat.data.entities.Notification toDataModel() throws Exception {
|
||||||
|
eu.eudat.data.entities.Notification entity = new eu.eudat.data.entities.Notification();
|
||||||
|
entity.setId(this.id);
|
||||||
|
entity.setContactHint(this.contactHint);
|
||||||
|
entity.setContactTypeHint(this.contactTypeHint);
|
||||||
|
entity.setCreatedAt(this.createdAt);
|
||||||
|
entity.setData(this.data);
|
||||||
|
entity.setIsActive(this.isActive);
|
||||||
|
entity.setNotifiedAt(this.notifiedAt);
|
||||||
|
entity.setNotifyState(this.notifyState);
|
||||||
|
entity.setRetryCount(this.retryCount);
|
||||||
|
entity.setType(this.type);
|
||||||
|
entity.setUpdatedAt(this.updatedAt);
|
||||||
|
entity.setUserId(this.userId.toDataModel());
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHint() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ eu.eudat.logic.proxy.allowed.host=https://eestore.paas2.uninett.no
|
||||||
####################GENERIC MAIL CONFIGURATIONS#################
|
####################GENERIC MAIL CONFIGURATIONS#################
|
||||||
mail.subject=Invitation to DMP Plan {dmpname}
|
mail.subject=Invitation to DMP Plan {dmpname}
|
||||||
mail.from=TheApp@dev.cite.gr
|
mail.from=TheApp@dev.cite.gr
|
||||||
|
mail.modified.notification.subject=[OpenDMP] The {name} has been modified
|
||||||
|
|
||||||
####################SPRING MAIL CONFIGURATIONS#################
|
####################SPRING MAIL CONFIGURATIONS#################
|
||||||
spring.mail.default-encoding=UTF-8
|
spring.mail.default-encoding=UTF-8
|
||||||
|
@ -76,3 +77,8 @@ http-logger.delay = 10
|
||||||
#############GENERIC DATASOURCE CONFIGURATIONS#########
|
#############GENERIC DATASOURCE CONFIGURATIONS#########
|
||||||
database.driver-class-name=org.postgresql.Driver
|
database.driver-class-name=org.postgresql.Driver
|
||||||
database.lock-fail-interval=120000
|
database.lock-fail-interval=120000
|
||||||
|
|
||||||
|
userguide.path=guide/
|
||||||
|
|
||||||
|
notification.rateInterval=30000
|
||||||
|
notification.maxRetries=10
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>Simple Transactional Email</title>
|
||||||
|
<style>
|
||||||
|
/* -------------------------------------
|
||||||
|
GLOBAL RESETS
|
||||||
|
------------------------------------- */
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
max-width: 100%; }
|
||||||
|
body {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
font-family: sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%; }
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
mso-table-lspace: 0pt;
|
||||||
|
mso-table-rspace: 0pt;
|
||||||
|
width: 100%; }
|
||||||
|
table td {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
vertical-align: top; }
|
||||||
|
/* -------------------------------------
|
||||||
|
BODY & CONTAINER
|
||||||
|
------------------------------------- */
|
||||||
|
.body {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
width: 100%; }
|
||||||
|
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
|
||||||
|
.container {
|
||||||
|
display: block;
|
||||||
|
Margin: 0 auto !important;
|
||||||
|
/* makes it centered */
|
||||||
|
max-width: 580px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 580px; }
|
||||||
|
/* This should also be a block element, so that it will fill 100% of the .container */
|
||||||
|
.content {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
Margin: 0 auto;
|
||||||
|
max-width: 580px;
|
||||||
|
padding: 10px; }
|
||||||
|
/* -------------------------------------
|
||||||
|
HEADER, FOOTER, MAIN
|
||||||
|
------------------------------------- */
|
||||||
|
.main {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%; }
|
||||||
|
.wrapper {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 20px; }
|
||||||
|
.content-block {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
clear: both;
|
||||||
|
Margin-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%; }
|
||||||
|
.footer td,
|
||||||
|
.footer p,
|
||||||
|
.footer span,
|
||||||
|
.footer a {
|
||||||
|
color: #999999;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center; }
|
||||||
|
/* -------------------------------------
|
||||||
|
TYPOGRAPHY
|
||||||
|
------------------------------------- */
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4 {
|
||||||
|
color: #000000;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 0;
|
||||||
|
Margin-bottom: 30px; }
|
||||||
|
h1 {
|
||||||
|
font-size: 35px;
|
||||||
|
font-weight: 300;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: capitalize; }
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
|
Margin-bottom: 15px; }
|
||||||
|
p li,
|
||||||
|
ul li,
|
||||||
|
ol li {
|
||||||
|
list-style-position: inside;
|
||||||
|
margin-left: 5px; }
|
||||||
|
a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: underline; }
|
||||||
|
/* -------------------------------------
|
||||||
|
BUTTONS
|
||||||
|
------------------------------------- */
|
||||||
|
.btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%; }
|
||||||
|
.btn > tbody > tr > td {
|
||||||
|
padding-bottom: 15px; }
|
||||||
|
.btn table {
|
||||||
|
width: auto; }
|
||||||
|
.btn table td {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center; }
|
||||||
|
.btn a {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: solid 1px #3498db;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #3498db;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px 25px;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: capitalize; }
|
||||||
|
.btn-primary table td {
|
||||||
|
background-color: #3498db; }
|
||||||
|
.btn-primary a {
|
||||||
|
background-color: #3498db;
|
||||||
|
border-color: #3498db;
|
||||||
|
color: #ffffff; }
|
||||||
|
/* -------------------------------------
|
||||||
|
OTHER STYLES THAT MIGHT BE USEFUL
|
||||||
|
------------------------------------- */
|
||||||
|
.last {
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.first {
|
||||||
|
margin-top: 0; }
|
||||||
|
.align-center {
|
||||||
|
text-align: center; }
|
||||||
|
.align-right {
|
||||||
|
text-align: right; }
|
||||||
|
.align-left {
|
||||||
|
text-align: left; }
|
||||||
|
.clear {
|
||||||
|
clear: both; }
|
||||||
|
.mt0 {
|
||||||
|
margin-top: 0; }
|
||||||
|
.mb0 {
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.preheader {
|
||||||
|
color: transparent;
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
max-height: 0;
|
||||||
|
max-width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
mso-hide: all;
|
||||||
|
visibility: hidden;
|
||||||
|
width: 0; }
|
||||||
|
.powered-by a {
|
||||||
|
text-decoration: none; }
|
||||||
|
hr {
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #f6f6f6;
|
||||||
|
Margin: 20px 0; }
|
||||||
|
/* -------------------------------------
|
||||||
|
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||||
|
------------------------------------- */
|
||||||
|
@media only screen and (max-width: 620px) {
|
||||||
|
table[class=body] h1 {
|
||||||
|
font-size: 28px !important;
|
||||||
|
margin-bottom: 10px !important; }
|
||||||
|
table[class=body] p,
|
||||||
|
table[class=body] ul,
|
||||||
|
table[class=body] ol,
|
||||||
|
table[class=body] td,
|
||||||
|
table[class=body] span,
|
||||||
|
table[class=body] a {
|
||||||
|
font-size: 16px !important; }
|
||||||
|
table[class=body] .wrapper,
|
||||||
|
table[class=body] .article {
|
||||||
|
padding: 10px !important; }
|
||||||
|
table[class=body] .content {
|
||||||
|
padding: 0 !important; }
|
||||||
|
table[class=body] .container {
|
||||||
|
padding: 0 !important;
|
||||||
|
width: 100% !important; }
|
||||||
|
table[class=body] .main {
|
||||||
|
border-left-width: 0 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
border-right-width: 0 !important; }
|
||||||
|
table[class=body] .btn table {
|
||||||
|
width: 100% !important; }
|
||||||
|
table[class=body] .btn a {
|
||||||
|
width: 100% !important; }
|
||||||
|
table[class=body] .img-responsive {
|
||||||
|
height: auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: auto !important; }}
|
||||||
|
/* -------------------------------------
|
||||||
|
PRESERVE THESE STYLES IN THE HEAD
|
||||||
|
------------------------------------- */
|
||||||
|
@media all {
|
||||||
|
.ExternalClass {
|
||||||
|
width: 100%; }
|
||||||
|
.ExternalClass,
|
||||||
|
.ExternalClass p,
|
||||||
|
.ExternalClass span,
|
||||||
|
.ExternalClass font,
|
||||||
|
.ExternalClass td,
|
||||||
|
.ExternalClass div {
|
||||||
|
line-height: 100%; }
|
||||||
|
.apple-link a {
|
||||||
|
color: inherit !important;
|
||||||
|
font-family: inherit !important;
|
||||||
|
font-size: inherit !important;
|
||||||
|
font-weight: inherit !important;
|
||||||
|
line-height: inherit !important;
|
||||||
|
text-decoration: none !important; }
|
||||||
|
.btn-primary table td:hover {
|
||||||
|
background-color: #34495e !important; }
|
||||||
|
.btn-primary a:hover {
|
||||||
|
background-color: #34495e !important;
|
||||||
|
border-color: #34495e !important; } }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" class="body">
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td class="container">
|
||||||
|
<div class="content">
|
||||||
|
|
||||||
|
<!-- START CENTERED WHITE CONTAINER -->
|
||||||
|
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
|
||||||
|
<table class="main">
|
||||||
|
|
||||||
|
<!-- START MAIN CONTENT AREA -->
|
||||||
|
<tr>
|
||||||
|
<td class="wrapper">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p>Dear {recipient},</p>
|
||||||
|
<p>{reasonName} just made changes to the {name}.</p>
|
||||||
|
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align="left">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td> <a href="{host}{path}/{id}" target="_blank">Click here to view it.</a> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- END MAIN CONTENT AREA -->
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- START FOOTER -->
|
||||||
|
<div class="footer">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- END FOOTER -->
|
||||||
|
|
||||||
|
<!-- END CENTERED WHITE CONTAINER -->
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,20 @@
|
||||||
|
CREATE TABLE public."Notification" (
|
||||||
|
id uuid NOT NULL,
|
||||||
|
"UserId" uuid,
|
||||||
|
"IsActive" integer NOT NULL,
|
||||||
|
"Type" integer NOT NULL,
|
||||||
|
"ContactTypeHint" integer,
|
||||||
|
"ContactHint" character varying,
|
||||||
|
"Data" character varying,
|
||||||
|
"NotifyState" integer NOT NULL,
|
||||||
|
"NotifiedAt" timestamp without time zone,
|
||||||
|
"RetryCount" integer,
|
||||||
|
"CreatedAt" timestamp without time zone,
|
||||||
|
"UpdatedAt" timestamp without time zone
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."Notification"
|
||||||
|
ADD CONSTRAINT "Notification_pkey" PRIMARY KEY (id);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."Notification"
|
||||||
|
ADD CONSTRAINT "NotificationUserReference" FOREIGN KEY ("UserId") REFERENCES public."UserInfo"(id);
|
Loading…
Reference in New Issue