diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationContactType.java b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationContactType.java new file mode 100644 index 000000000..904fea9b3 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationContactType.java @@ -0,0 +1,32 @@ +package eu.eudat.commons.enums.notification; + +import com.fasterxml.jackson.annotation.JsonValue; +import eu.eudat.commons.enums.EnumUtils; +import eu.eudat.data.converters.enums.DatabaseEnum; + +import java.util.Map; + +public enum NotificationContactType implements DatabaseEnum { + EMAIL((short)0), + SLACK_BROADCAST((short)1), + SMS((short)2), + IN_APP((short)3); + + private final Short value; + + NotificationContactType(Short value) { + this.value = value; + } + + @JsonValue + public Short getValue() { + return value; + } + + private static final Map map = EnumUtils.getEnumValueMap(NotificationContactType.class); + + public static NotificationContactType of(Short i) { + return map.get(i); + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationNotifyState.java b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationNotifyState.java new file mode 100644 index 000000000..dfc25879f --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationNotifyState.java @@ -0,0 +1,33 @@ +package eu.eudat.commons.enums.notification; + +import com.fasterxml.jackson.annotation.JsonValue; +import eu.eudat.commons.enums.EnumUtils; +import eu.eudat.data.converters.enums.DatabaseEnum; + +import java.util.Map; + +public enum NotificationNotifyState implements DatabaseEnum { + PENDING((short)0), + PROCESSING((short)1), + SUCCESSFUL((short)2), + ERROR((short)3), + OMITTED((short)4); + + private final Short value; + + NotificationNotifyState(Short value) { + this.value = value; + } + + @JsonValue + public Short getValue() { + return value; + } + + private static final Map map = EnumUtils.getEnumValueMap(NotificationNotifyState.class); + + public static NotificationNotifyState of(Short i) { + return map.get(i); + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationTrackingProcess.java b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationTrackingProcess.java new file mode 100644 index 000000000..145f2f85d --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationTrackingProcess.java @@ -0,0 +1,32 @@ +package eu.eudat.commons.enums.notification; + +import com.fasterxml.jackson.annotation.JsonValue; +import eu.eudat.commons.enums.EnumUtils; +import eu.eudat.data.converters.enums.DatabaseEnum; + +import java.util.Map; + +public enum NotificationTrackingProcess implements DatabaseEnum { + PENDING((short)0), + PROCESSING((short)1), + COMPLETED((short)2), + ERROR((short)3), + OMITTED((short)4); + + private final Short value; + + NotificationTrackingProcess(Short value) { + this.value = value; + } + + @JsonValue + public Short getValue() { + return value; + } + + private static final Map map = EnumUtils.getEnumValueMap(NotificationTrackingProcess.class); + + public static NotificationTrackingProcess of(Short i) { + return map.get(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationTrackingState.java b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationTrackingState.java new file mode 100644 index 000000000..6b06c1edf --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/notification/NotificationTrackingState.java @@ -0,0 +1,35 @@ +package eu.eudat.commons.enums.notification; + +import com.fasterxml.jackson.annotation.JsonValue; +import eu.eudat.data.converters.enums.DatabaseEnum; +import eu.eudat.commons.enums.EnumUtils; + +import java.util.Map; + +public enum NotificationTrackingState implements DatabaseEnum { + UNDEFINED((short)0), + NA((short)1), + QUEUED((short)2), + SENT((short)3), + DELIVERED((short)4), + UNDELIVERED((short)5), + FAILED((short)6), + UNSENT((short)7); + + private final Short value; + + NotificationTrackingState(Short value) { + this.value = value; + } + + @JsonValue + public Short getValue() { + return value; + } + + private static final Map map = EnumUtils.getEnumValueMap(NotificationTrackingState.class); + + public static NotificationTrackingState of(Short i) { + return map.get(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/Attachment.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/Attachment.java new file mode 100644 index 000000000..d133aa09a --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/Attachment.java @@ -0,0 +1,36 @@ +package eu.eudat.commons.types.notification; + +public class Attachment { + + private String fileRef, fileName, mimeType; + + public Attachment(String fileRef, String fileName, String mimeType) { + this.fileRef = fileRef; + this.fileName = fileName; + this.mimeType = mimeType; + } + + public String getFileRef() { + return fileRef; + } + + public void setFileRef(String fileRef) { + this.fileRef = fileRef; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/ContactPair.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/ContactPair.java new file mode 100644 index 000000000..f20701af4 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/ContactPair.java @@ -0,0 +1,33 @@ +package eu.eudat.commons.types.notification; + + +import eu.eudat.commons.enums.ContactInfoType; + +public class ContactPair { + private ContactInfoType type; + private String Contact; + + public ContactPair(ContactInfoType type, String contact) { + this.type = type; + Contact = contact; + } + + public ContactPair() { + } + + public ContactInfoType getType() { + return type; + } + + public void setType(ContactInfoType type) { + this.type = type; + } + + public String getContact() { + return Contact; + } + + public void setContact(String contact) { + Contact = contact; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/DataType.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/DataType.java new file mode 100644 index 000000000..2cfde8ed7 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/DataType.java @@ -0,0 +1,42 @@ +package eu.eudat.commons.types.notification; + +import com.fasterxml.jackson.annotation.JsonValue; + +import java.util.HashMap; +import java.util.Map; + +public enum DataType { + Integer(0), + Decimal(1), + Double(2), + DateTime(3), + TimeSpan(4), + String(5); + private static final Map values = new HashMap<>(); + + private final Integer mappedName; + + //For jackson parsing (used by MVC) + @JsonValue + public Integer getMappedName() { + return mappedName; + } + + static { + for (DataType e : values()) { + values.put(e.asInt(), e); + } + } + + private DataType(int mappedName) { + this.mappedName = mappedName; + } + + public Integer asInt() { + return this.mappedName; + } + + public static DataType fromString(Integer value) { + return values.getOrDefault(value, Integer); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/FieldInfo.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/FieldInfo.java new file mode 100644 index 000000000..c93a55261 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/FieldInfo.java @@ -0,0 +1,40 @@ +package eu.eudat.commons.types.notification; + +public class FieldInfo { + private String key; + private DataType type; + private String value; + + public FieldInfo(String key, DataType type, String value) { + this.key = key; + this.type = type; + this.value = value; + } + + public FieldInfo() { + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public DataType getType() { + return type; + } + + public void setType(DataType type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/InAppTrackingData.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/InAppTrackingData.java new file mode 100644 index 000000000..c2abd1f8d --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/InAppTrackingData.java @@ -0,0 +1,31 @@ +package eu.eudat.commons.types.notification; + +import java.util.List; +import java.util.UUID; + +public class InAppTrackingData { + + private UUID inAppNotificationId; + private List traces; + + public InAppTrackingData(UUID inAppNotificationId, List traces) { + this.inAppNotificationId = inAppNotificationId; + this.traces = traces; + } + + public UUID getInAppNotificationId() { + return inAppNotificationId; + } + + public void setInAppNotificationId(UUID inAppNotificationId) { + this.inAppNotificationId = inAppNotificationId; + } + + public List getTraces() { + return traces; + } + + public void setTraces(List traces) { + this.traces = traces; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/NotificationContactData.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/NotificationContactData.java new file mode 100644 index 000000000..a6d50efc5 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/NotificationContactData.java @@ -0,0 +1,39 @@ +package eu.eudat.commons.types.notification; + +import java.util.List; + +public class NotificationContactData { + private List contacts; + private List BCC; + private List CC; + + public NotificationContactData(List contacts, List BCC, List CC) { + this.contacts = contacts; + this.BCC = BCC; + this.CC = CC; + } + + public List getContacts() { + return contacts; + } + + public void setContacts(List contacts) { + this.contacts = contacts; + } + + public List getBCC() { + return BCC; + } + + public void setBCC(List BCC) { + this.BCC = BCC; + } + + public List getCC() { + return CC; + } + + public void setCC(List CC) { + this.CC = CC; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/NotificationFieldData.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/NotificationFieldData.java new file mode 100644 index 000000000..024f3aee7 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/NotificationFieldData.java @@ -0,0 +1,32 @@ +package eu.eudat.commons.types.notification; + +import java.util.List; + +public class NotificationFieldData { + private List fields; + private List attachments; + + public NotificationFieldData(List fields, List attachments) { + this.fields = fields; + this.attachments = attachments; + } + + public NotificationFieldData() { + } + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public List getAttachments() { + return attachments; + } + + public void setAttachments(List attachments) { + this.attachments = attachments; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/RouteTrackingData.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/RouteTrackingData.java new file mode 100644 index 000000000..4b3a7003c --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/RouteTrackingData.java @@ -0,0 +1,30 @@ +package eu.eudat.commons.types.notification; + +import java.util.List; + +public class RouteTrackingData { + + private String trackingId; + private List traces; + + public RouteTrackingData(String trackingId, List traces) { + this.trackingId = trackingId; + this.traces = traces; + } + + public String getTrackingId() { + return trackingId; + } + + public void setTrackingId(String trackingId) { + this.trackingId = trackingId; + } + + public List getTraces() { + return traces; + } + + public void setTraces(List traces) { + this.traces = traces; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/TrackingTrace.java b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/TrackingTrace.java new file mode 100644 index 000000000..c0ed7eb2e --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/types/notification/TrackingTrace.java @@ -0,0 +1,30 @@ +package eu.eudat.commons.types.notification; + +import java.time.Instant; + +public class TrackingTrace { + + private Instant at; + private String data; + + public TrackingTrace(Instant at, String data) { + this.at = at; + this.data = data; + } + + public Instant getAt() { + return at; + } + + public void setAt(Instant at) { + this.at = at; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/configurations/notification/NotificationConfiguration.java b/dmp-backend/core/src/main/java/eu/eudat/configurations/notification/NotificationConfiguration.java new file mode 100644 index 000000000..044fdc5ac --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/configurations/notification/NotificationConfiguration.java @@ -0,0 +1,20 @@ +package eu.eudat.configurations.notification; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties(NotificationProperties.class) +public class NotificationConfiguration { + private final NotificationProperties properties; + + @Autowired + public NotificationConfiguration(NotificationProperties properties) { + this.properties = properties; + } + + public NotificationProperties getProperties() { + return properties; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/configurations/notification/NotificationProperties.java b/dmp-backend/core/src/main/java/eu/eudat/configurations/notification/NotificationProperties.java new file mode 100644 index 000000000..f4c9fd3d7 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/configurations/notification/NotificationProperties.java @@ -0,0 +1,89 @@ +package eu.eudat.configurations.notification; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "notification") +public class NotificationProperties { + + private String confirmation; + private String dataManagementPlan; + private String finalised; + private String mergeConfirmation; + private String modified; + private String modifiedFinalised; + private String publish; + private String template; + private String unlinkConfirmation; + + public String getConfirmation() { + return confirmation; + } + + public void setConfirmation(String confirmation) { + this.confirmation = confirmation; + } + + public String getDataManagementPlan() { + return dataManagementPlan; + } + + public void setDataManagementPlan(String dataManagementPlan) { + this.dataManagementPlan = dataManagementPlan; + } + + public String getFinalised() { + return finalised; + } + + public void setFinalised(String finalised) { + this.finalised = finalised; + } + + public String getMergeConfirmation() { + return mergeConfirmation; + } + + public void setMergeConfirmation(String mergeConfirmation) { + this.mergeConfirmation = mergeConfirmation; + } + + public String getModified() { + return modified; + } + + public void setModified(String modified) { + this.modified = modified; + } + + public String getModifiedFinalised() { + return modifiedFinalised; + } + + public void setModifiedFinalised(String modifiedFinalised) { + this.modifiedFinalised = modifiedFinalised; + } + + public String getPublish() { + return publish; + } + + public void setPublish(String publish) { + this.publish = publish; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public String getUnlinkConfirmation() { + return unlinkConfirmation; + } + + public void setUnlinkConfirmation(String unlinkConfirmation) { + this.unlinkConfirmation = unlinkConfirmation; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/QueueInboxEntity.java b/dmp-backend/core/src/main/java/eu/eudat/data/QueueInboxEntity.java new file mode 100644 index 000000000..dc2e18d51 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/QueueInboxEntity.java @@ -0,0 +1,177 @@ +package eu.eudat.data; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.converters.enums.IsActiveConverter; +import gr.cite.queueinbox.entity.QueueInbox; +import gr.cite.queueinbox.entity.QueueInboxStatus; +import jakarta.persistence.*; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "\"QueueInbox\"") +public class QueueInboxEntity implements QueueInbox { + @Id + @Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false) + private UUID id; + public final static String _id = "id"; + + @Column(name = "\"queue\"", nullable = false, length = 50) + private String queue; + public final static String _queue = "queue"; + + @Column(name = "\"exchange\"", nullable = false, length = 50) + private String exchange; + public final static String _exchange = "exchange"; + + @Column(name = "\"route\"", nullable = false, length = 50) + private String route; + public final static String _route = "route"; + + @Column(name = "\"application_id\"", nullable = false, length = 100) + private String applicationId; + public final static String _applicationId = "applicationId"; + + @Column(name = "\"message_id\"", columnDefinition = "uuid", nullable = false) + private UUID messageId; + public final static String _messageId = "messageId"; + + @Column(name = "\"message\"", columnDefinition = "json", nullable = false) + private String message; + public final static String _message = "message"; + + @Column(name = "\"retry_count\"", nullable = true) + private Integer retryCount; + public final static String _retryCount = "retryCount"; + + @Column(name = "\"tenant\"", columnDefinition = "uuid", nullable = true) + private UUID tenantId; + public final static String _tenantId = "tenantId"; + + @Column(name = "\"is_active\"", length = 20, nullable = false) + @Convert(converter = IsActiveConverter.class) + private IsActive isActive; + public final static String _isActive = "isActive"; + + //TODO: as integer + @Column(name = "\"status\"", length = 50, nullable = false) + @Enumerated(EnumType.STRING) + private QueueInboxStatus status; + public final static String _status = "status"; + + @Column(name = "\"created_at\"", nullable = false) + private Instant createdAt; + public final static String _createdAt = "createdAt"; + + @Column(name = "\"updated_at\"", nullable = false) + @Version + private Instant updatedAt; + public final static String _updatedAt = "updatedAt"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getExchange() { + return exchange; + } + + public void setExchange(String exchange) { + this.exchange = exchange; + } + + public String getRoute() { + return route; + } + + public void setRoute(String route) { + this.route = route; + } + + public UUID getMessageId() { + return messageId; + } + + public void setMessageId(UUID messageId) { + this.messageId = messageId; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public UUID getTenantId() { + return tenantId; + } + + public void setTenantId(UUID tenantId) { + this.tenantId = tenantId; + } + + public IsActive getIsActive() { + return isActive; + } + + public void setIsActive(IsActive isActive) { + this.isActive = isActive; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + public String getQueue() { + return queue; + } + + public void setQueue(String queue) { + this.queue = queue; + } + + public String getApplicationId() { + return applicationId; + } + + public void setApplicationId(String applicationId) { + this.applicationId = applicationId; + } + + @Override + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public QueueInboxStatus getStatus() { + return status; + } + + public void setStatus(QueueInboxStatus status) { + this.status = status; + } +} + diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/QueueOutboxEntity.java b/dmp-backend/core/src/main/java/eu/eudat/data/QueueOutboxEntity.java new file mode 100644 index 000000000..721d5c94d --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/QueueOutboxEntity.java @@ -0,0 +1,175 @@ +package eu.eudat.data; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.converters.enums.IsActiveConverter; +import gr.cite.queueoutbox.entity.QueueOutbox; +import gr.cite.queueoutbox.entity.QueueOutboxNotifyStatus; + +import jakarta.persistence.*; +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "\"QueueOutbox\"") +public class QueueOutboxEntity implements QueueOutbox { + @Id + @Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false) + private UUID id; + public final static String _id = "id"; + + @Column(name = "\"exchange\"", nullable = false, length = 50) + private String exchange; + public final static String _exchange = "exchange"; + + @Column(name = "\"route\"", length = 50) + private String route; + public final static String _route = "route"; + + @Column(name = "\"message_id\"", columnDefinition = "uuid", nullable = false) + private UUID messageId; + public final static String _messageId = "messageId"; + + @Column(name = "\"message\"", columnDefinition = "json", nullable = false) + private String message; + public final static String _message = "message"; + + //TODO: as integer + @Column(name = "\"notify_status\"", length = 20, nullable = false) + @Enumerated(EnumType.STRING) + private QueueOutboxNotifyStatus notifyStatus; + public final static String _notifyStatus = "notifyStatus"; + + @Column(name = "\"retry_count\"", nullable = false) + private int retryCount; + public final static String _retryCount = "retryCount"; + + @Column(name = "\"published_at\"", nullable = true) + private Instant publishedAt; + public final static String _publishedAt = "publishedAt"; + + @Column(name = "\"confirmed_at\"", nullable = true) + private Instant confirmedAt; + public final static String _confirmedAt = "confirmedAt"; + + @Column(name = "\"tenant\"", columnDefinition = "uuid", nullable = true) + private UUID tenantId; + public final static String _tenantId = "tenantId"; + + @Column(name = "\"is_active\"", length = 20, nullable = false) + @Convert(converter = IsActiveConverter.class) + private IsActive isActive; + public final static String _isActive = "isActive"; + + @Column(name = "\"created_at\"", nullable = false) + private Instant createdAt; + public final static String _createdAt = "createdAt"; + + @Column(name = "\"updated_at\"", nullable = false) + private Instant updatedAt; + public final static String _updatedAt = "updatedAt"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getExchange() { + return exchange; + } + + public void setExchange(String exchange) { + this.exchange = exchange; + } + + public String getRoute() { + return route; + } + + public void setRoute(String route) { + this.route = route; + } + + public UUID getMessageId() { + return messageId; + } + + public void setMessageId(UUID messageId) { + this.messageId = messageId; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public QueueOutboxNotifyStatus getNotifyStatus() { + return notifyStatus; + } + + public void setNotifyStatus(QueueOutboxNotifyStatus notifyStatus) { + this.notifyStatus = notifyStatus; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public Instant getPublishedAt() { + return publishedAt; + } + + public void setPublishedAt(Instant publishedAt) { + this.publishedAt = publishedAt; + } + + public Instant getConfirmedAt() { + return confirmedAt; + } + + public void setConfirmedAt(Instant confirmedAt) { + this.confirmedAt = confirmedAt; + } + + public UUID getTenantId() { + return tenantId; + } + + public void setTenantId(UUID tenantId) { + this.tenantId = tenantId; + } + + public IsActive getIsActive() { + return isActive; + } + + public void setIsActive(IsActive isActive) { + this.isActive = isActive; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } +} + diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationContactTypeConverter.java b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationContactTypeConverter.java new file mode 100644 index 000000000..18eef5b44 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationContactTypeConverter.java @@ -0,0 +1,12 @@ +package eu.eudat.data.converters.enums.notification; + +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.data.converters.enums.DatabaseEnumConverter; +import jakarta.persistence.Converter; + +@Converter +public class NotificationContactTypeConverter extends DatabaseEnumConverter { + public NotificationContactType of(Short i) { + return NotificationContactType.of(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationNotifyStateConverter.java b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationNotifyStateConverter.java new file mode 100644 index 000000000..c1d8932af --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationNotifyStateConverter.java @@ -0,0 +1,12 @@ +package eu.eudat.data.converters.enums.notification; + +import eu.eudat.commons.enums.notification.NotificationNotifyState; +import eu.eudat.data.converters.enums.DatabaseEnumConverter; +import jakarta.persistence.Converter; + +@Converter +public class NotificationNotifyStateConverter extends DatabaseEnumConverter { + public NotificationNotifyState of(Short i) { + return NotificationNotifyState.of(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationTrackingProcessConverter.java b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationTrackingProcessConverter.java new file mode 100644 index 000000000..fd12ffcd7 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationTrackingProcessConverter.java @@ -0,0 +1,12 @@ +package eu.eudat.data.converters.enums.notification; + +import eu.eudat.commons.enums.notification.NotificationTrackingProcess; +import eu.eudat.data.converters.enums.DatabaseEnumConverter; +import jakarta.persistence.Converter; + +@Converter +public class NotificationTrackingProcessConverter extends DatabaseEnumConverter { + public NotificationTrackingProcess of(Short i) { + return NotificationTrackingProcess.of(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationTrackingStateConverter.java b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationTrackingStateConverter.java new file mode 100644 index 000000000..149e565df --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/notification/NotificationTrackingStateConverter.java @@ -0,0 +1,13 @@ +package eu.eudat.data.converters.enums.notification; + + +import eu.eudat.commons.enums.notification.NotificationTrackingState; +import eu.eudat.data.converters.enums.DatabaseEnumConverter; +import jakarta.persistence.Converter; + +@Converter +public class NotificationTrackingStateConverter extends DatabaseEnumConverter { + public NotificationTrackingState of(Short i) { + return NotificationTrackingState.of(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/notification/NotificationEntity.java b/dmp-backend/core/src/main/java/eu/eudat/data/notification/NotificationEntity.java new file mode 100644 index 000000000..a4815efc0 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/notification/NotificationEntity.java @@ -0,0 +1,225 @@ +package eu.eudat.data.notification; + + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.commons.enums.notification.NotificationNotifyState; +import eu.eudat.commons.enums.notification.NotificationTrackingProcess; +import eu.eudat.commons.enums.notification.NotificationTrackingState; +import eu.eudat.data.converters.enums.IsActiveConverter; +import eu.eudat.data.converters.enums.notification.NotificationContactTypeConverter; +import eu.eudat.data.converters.enums.notification.NotificationNotifyStateConverter; +import eu.eudat.data.converters.enums.notification.NotificationTrackingProcessConverter; +import eu.eudat.data.converters.enums.notification.NotificationTrackingStateConverter; +import eu.eudat.data.tenant.TenantScopedBaseEntity; +import jakarta.persistence.*; +import jakarta.persistence.Table; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "\"ntf_Notification\"") +public class NotificationEntity extends TenantScopedBaseEntity { + + public static class Field { + public final static String _id = "id"; + public static final String _userId = "userId"; + public static final String _type = "type"; + public static final String _contactTypeHint = "contactTypeHint"; + public static final String _contactHint = "contactHint"; + public final static String _notifiedAt = "notifiedAt"; + public final static String _isActive = "isActive"; + public final static String _createdAt = "createdAt"; + public final static String _updatedAt = "updatedAt"; + public final static String _data = "data"; + public final static String _retryCount = "retryCount"; + public final static String _notifyState = "notifyState"; + public final static String _notifiedWith = "notifiedWith"; + public final static String _trackingState = "trackingState"; + public final static String _trackingProcess = "trackingProcess"; + public final static String _trackingData = "trackingData"; + } + + @Id + @Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false) + private UUID id; + + @Column(name = "\"user\"", columnDefinition = "uuid") + private UUID userId; + + @Column(name = "\"type\"", columnDefinition = "uuid", nullable = false) + private UUID type; + + @Column(name = "\"contact_type_hint\"") + @Convert(converter = NotificationContactTypeConverter.class) + private NotificationContactType contactTypeHint; + + @Column(name = "\"contact_hint\"") + private String contactHint; + + @Column(name = "\"notify_state\"", nullable = false) + @Convert(converter = NotificationNotifyStateConverter.class) + private NotificationNotifyState notifyState; + + @Column(name = "\"notified_with\"") + @Convert(converter = NotificationContactTypeConverter.class) + private NotificationContactType notifiedWith; + @Column(name = "\"notified_at\"") + private Instant notifiedAt; + + @Column(name = "\"data\"") + private String data; + + @Column(name = "\"retry_count\"") + private Integer retryCount; + + @Column(name = "\"is_active\"", length = 20, nullable = false) + @Convert(converter = IsActiveConverter.class) + private IsActive isActive; + + @Column(name = "\"created_at\"", nullable = false) + private Instant createdAt; + + @Column(name = "\"updated_at\"", nullable = false) + private Instant updatedAt; + + @Column(name = "\"tracking_state\"", nullable = false) + @Convert(converter = NotificationTrackingStateConverter.class) + private NotificationTrackingState trackingState; + + @Column(name = "\"tracking_process\"", nullable = false) + @Convert(converter = NotificationTrackingProcessConverter.class) + private NotificationTrackingProcess trackingProcess; + + @Column(name = "\"tracking_data\"") + private String trackingData; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public UUID getType() { + return type; + } + + public void setType(UUID type) { + this.type = type; + } + + public NotificationContactType getContactTypeHint() { + return contactTypeHint; + } + + public void setContactTypeHint(NotificationContactType contactTypeHint) { + this.contactTypeHint = contactTypeHint; + } + + public String getContactHint() { + return contactHint; + } + + public void setContactHint(String contactHint) { + this.contactHint = contactHint; + } + + public NotificationContactType getNotifiedWith() { + return notifiedWith; + } + + public void setNotifiedWith(NotificationContactType notifiedWith) { + this.notifiedWith = notifiedWith; + } + + public NotificationNotifyState getNotifyState() { + return notifyState; + } + + public void setNotifyState(NotificationNotifyState notifyState) { + this.notifyState = notifyState; + } + + public Instant getNotifiedAt() { + return notifiedAt; + } + + public void setNotifiedAt(Instant notifiedAt) { + this.notifiedAt = notifiedAt; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public IsActive getIsActive() { + return isActive; + } + + public void setIsActive(IsActive isActive) { + this.isActive = isActive; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + public NotificationTrackingState getTrackingState() { + return trackingState; + } + + public void setTrackingState(NotificationTrackingState trackingState) { + this.trackingState = trackingState; + } + + public NotificationTrackingProcess getTrackingProcess() { + return trackingProcess; + } + + public void setTrackingProcess(NotificationTrackingProcess trackingProcess) { + this.trackingProcess = trackingProcess; + } + + public String getTrackingData() { + return trackingData; + } + + public void setTrackingData(String trackingData) { + this.trackingData = trackingData; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/AppRabbitConfigurer.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/AppRabbitConfigurer.java new file mode 100644 index 000000000..83348f4a6 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/AppRabbitConfigurer.java @@ -0,0 +1,47 @@ +package eu.eudat.integrationevent; + +import eu.eudat.integrationevent.inbox.InboxProperties; +import eu.eudat.integrationevent.outbox.OutboxProperties; +import gr.cite.queueinbox.repository.InboxRepository; +import gr.cite.rabbitmq.RabbitConfigurer; +import gr.cite.rabbitmq.consumer.InboxBindings; +import gr.cite.rabbitmq.consumer.InboxCreator; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.List; + +@Configuration +@EnableConfigurationProperties({OutboxProperties.class, InboxProperties.class}) +@ConditionalOnProperty(prefix = "queue.rabbitmq", name = "listenerEnabled") +public class AppRabbitConfigurer extends RabbitConfigurer { + private ApplicationContext applicationContext; + private InboxProperties inboxProperties; + + public AppRabbitConfigurer(ApplicationContext applicationContext, InboxProperties inboxProperties) { + this.applicationContext = applicationContext; + this.inboxProperties = inboxProperties; + } + +// @Bean + public InboxBindings inboxBindingsCreator() { + List bindingItems = new ArrayList<>(); + bindingItems.addAll(this.inboxProperties.getUserRemovalTopic()); + bindingItems.addAll(this.inboxProperties.getUserTouchedTopic()); + + return new InboxBindings(bindingItems); + } + + +// @Bean + public InboxCreator inboxCreator() { + return (params) -> { + InboxRepository inboxRepository = this.applicationContext.getBean(InboxRepository.class); + return inboxRepository.create(params) != null; + }; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/InboxIntegrationEventConfigurer.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/InboxIntegrationEventConfigurer.java new file mode 100644 index 000000000..a4a8ddcf1 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/InboxIntegrationEventConfigurer.java @@ -0,0 +1,30 @@ +package eu.eudat.integrationevent; + +import eu.eudat.integrationevent.inbox.InboxProperties; +import eu.eudat.integrationevent.inbox.InboxRepositoryImpl; +import gr.cite.queueinbox.InboxConfigurer; +import gr.cite.queueinbox.repository.InboxRepository; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties({InboxProperties.class}) +@ConditionalOnProperty(prefix = "queue.task.listener", name = "enable", matchIfMissing = false) +public class InboxIntegrationEventConfigurer extends InboxConfigurer { + private ApplicationContext applicationContext; + private InboxProperties inboxProperties; + + public InboxIntegrationEventConfigurer(ApplicationContext applicationContext, InboxProperties inboxProperties) { + this.applicationContext = applicationContext; + this.inboxProperties = inboxProperties; + } + + @Bean + public InboxRepository inboxRepositoryCreator() { + return new InboxRepositoryImpl(this.applicationContext, this.inboxProperties); + } +} + diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/IntegrationEventContextImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/IntegrationEventContextImpl.java new file mode 100644 index 000000000..e6c8d8431 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/IntegrationEventContextImpl.java @@ -0,0 +1,20 @@ +package eu.eudat.integrationevent; + +import gr.cite.rabbitmq.IntegrationEventContext; + +import java.util.UUID; + +public class IntegrationEventContextImpl implements IntegrationEventContext { + private UUID tenant; + + public IntegrationEventContextImpl() { + } + + public UUID getTenant() { + return tenant; + } + + public void setTenant(UUID tenant) { + this.tenant = tenant; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/OutboxIntegrationEventConfigurer.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/OutboxIntegrationEventConfigurer.java new file mode 100644 index 000000000..db9278357 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/OutboxIntegrationEventConfigurer.java @@ -0,0 +1,69 @@ +package eu.eudat.integrationevent; + + +import eu.eudat.integrationevent.outbox.OutboxProperties; +import eu.eudat.integrationevent.outbox.OutboxRepositoryImpl; +import gr.cite.queueoutbox.IntegrationEventContextCreator; +import gr.cite.queueoutbox.OutboxConfigurer; +import gr.cite.queueoutbox.repository.OutboxRepository; +import gr.cite.rabbitmq.IntegrationEventMessageConstants; +import gr.cite.rabbitmq.RabbitProperties; +import gr.cite.rabbitmq.broker.MessageHydrator; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.nio.charset.StandardCharsets; +import java.sql.Date; +import java.time.Instant; +import java.util.UUID; + +@Configuration +@EnableConfigurationProperties({OutboxProperties.class}) +@ConditionalOnProperty(prefix = "queue.task.publisher", name = "enable", matchIfMissing = false) +public class OutboxIntegrationEventConfigurer extends OutboxConfigurer { + private ApplicationContext applicationContext; + private OutboxProperties outboxProperties; + + public OutboxIntegrationEventConfigurer(ApplicationContext applicationContext, OutboxProperties outboxProperties) { + this.applicationContext = applicationContext; + this.outboxProperties = outboxProperties; + } + + @Bean + public MessageHydrator messageHydrator(RabbitProperties rabbitProperties) { + return (message, event, eventContext) -> { + MessageProperties messageProperties = message.getMessageProperties(); + messageProperties.setAppId(rabbitProperties.getAppId()); + messageProperties.setContentEncoding(StandardCharsets.UTF_8.displayName()); + messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON); + //messageProperties.setUserId(userContext.getCurrentUser().toString()); + messageProperties.setTimestamp(Date.from(Instant.now())); + messageProperties.setMessageId(event.getMessageId().toString()); + + if (eventContext != null) { + UUID tenant = ((IntegrationEventContextImpl) eventContext).getTenant(); + if (tenant != null) { + messageProperties.setHeader(IntegrationEventMessageConstants.TENANT, tenant); + } + } + + return message; + }; + } + + @Bean + public IntegrationEventContextCreator integrationEventContextCreator() { + return (message) -> new IntegrationEventContextImpl(); + } + + @Bean + public OutboxRepository outboxRepositoryCreator() { + return new OutboxRepositoryImpl(this.applicationContext, this.outboxProperties); + } +} + + diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/OutboxPropertiesConfiguration.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/OutboxPropertiesConfiguration.java new file mode 100644 index 000000000..fc08550e9 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/OutboxPropertiesConfiguration.java @@ -0,0 +1,11 @@ +package eu.eudat.integrationevent; + +import eu.eudat.integrationevent.outbox.OutboxProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties(OutboxProperties.class) +public class OutboxPropertiesConfiguration { + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/TrackedEvent.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/TrackedEvent.java new file mode 100644 index 000000000..5bc6e205a --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/TrackedEvent.java @@ -0,0 +1,18 @@ +package eu.eudat.integrationevent; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class TrackedEvent { + public String trackingContextTag; + + public String getTrackingContextTag() { + return trackingContextTag; + } + + public void setTrackingContextTag(String trackingContextTag) { + this.trackingContextTag = trackingContextTag; + } + + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/ConsistencyHandler.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/ConsistencyHandler.java new file mode 100644 index 000000000..a08d85386 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/ConsistencyHandler.java @@ -0,0 +1,5 @@ +package eu.eudat.integrationevent.inbox; + +public interface ConsistencyHandler { + Boolean isConsistent(T consistencyPredicates); +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/ConsistencyPredicates.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/ConsistencyPredicates.java new file mode 100644 index 000000000..5bcd43719 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/ConsistencyPredicates.java @@ -0,0 +1,4 @@ +package eu.eudat.integrationevent.inbox; + +public interface ConsistencyPredicates { +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/EventProcessingStatus.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/EventProcessingStatus.java new file mode 100644 index 000000000..bed452b45 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/EventProcessingStatus.java @@ -0,0 +1,8 @@ +package eu.eudat.integrationevent.inbox; + +public enum EventProcessingStatus { + Error, + Success, + Postponed, + Discard +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxPrincipal.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxPrincipal.java new file mode 100644 index 000000000..825fe6d64 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxPrincipal.java @@ -0,0 +1,56 @@ +package eu.eudat.integrationevent.inbox; + +import gr.cite.commons.web.oidc.principal.MyPrincipal; +import org.springframework.security.oauth2.core.ClaimAccessor; +import org.springframework.security.oauth2.jwt.JwtClaimNames; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class InboxPrincipal implements MyPrincipal, ClaimAccessor { + private Map claims; + private boolean isAuthenticated; + + public InboxPrincipal(Boolean isAuthenticated, String name) { + this.claims = new HashMap<>(); + this.put(JwtClaimNames.SUB, name); + this.isAuthenticated = isAuthenticated; + } + + @Override + public Boolean isAuthenticated() { + return this.isAuthenticated; + } + + @Override + public Map getClaims() { + return this.claims; + } + + @Override + public List getClaimAsStringList(String claim) { + if (claims == null) return null; + return this.getClaimAsStringList(claim); + } + + @Override + public String getName() { + return this.getClaimAsString(JwtClaimNames.SUB); + } + + public void put(String key, Object value) { + this.claims.put(key, value); + } + + public static InboxPrincipal build(IntegrationEventProperties properties) { + InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId"); + inboxPrincipal.put("client_id", properties.getAppId()); + inboxPrincipal.put("active", "true"); + inboxPrincipal.put("nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString()); + inboxPrincipal.put("exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString()); + return inboxPrincipal; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxProperties.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxProperties.java new file mode 100644 index 000000000..3971f8fbd --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxProperties.java @@ -0,0 +1,42 @@ +package eu.eudat.integrationevent.inbox; + + +import org.springframework.boot.context.properties.ConfigurationProperties; +//import org.springframework.boot.context.properties.ConstructorBinding; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.constraints.NotNull; +import java.util.List; + +@Validated +@ConfigurationProperties(prefix = "queue.task.listener.options") +//@ConstructorBinding +public class InboxProperties { + @NotNull + private final String exchange; + @NotNull + private final List userRemovalTopic; + @NotNull + private final List userTouchedTopic; + + public InboxProperties( + String exchange, + List userRemovalTopic, + List userTouchedTopic) { + this.exchange = exchange; + this.userRemovalTopic = userRemovalTopic; + this.userTouchedTopic = userTouchedTopic; + } + + public List getUserRemovalTopic() { + return userRemovalTopic; + } + + public List getUserTouchedTopic() { + return userTouchedTopic; + } + + public String getExchange() { + return exchange; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxRepositoryImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxRepositoryImpl.java new file mode 100644 index 000000000..d20305d24 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/InboxRepositoryImpl.java @@ -0,0 +1,338 @@ +package eu.eudat.integrationevent.inbox; + + +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.fake.FakeRequestScope; +import eu.eudat.data.QueueInboxEntity; +import eu.eudat.integrationevent.TrackedEvent; +import eu.eudat.integrationevent.inbox.userremoval.UserRemovalIntegrationEventHandler; +import eu.eudat.integrationevent.inbox.usertouched.UserTouchedIntegrationEventHandler; +import eu.eudat.query.QueueInboxQuery; +import gr.cite.queueinbox.entity.QueueInbox; +import gr.cite.queueinbox.entity.QueueInboxStatus; +import gr.cite.queueinbox.repository.CandidateInfo; +import gr.cite.queueinbox.repository.InboxRepository; +import gr.cite.queueinbox.task.MessageOptions; +import gr.cite.rabbitmq.consumer.InboxCreatorParams; +import gr.cite.tools.data.query.Ordering; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.logging.LoggerService; +import jakarta.persistence.*; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; + + +import java.time.Instant; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.function.Function; + +public class InboxRepositoryImpl implements InboxRepository { + + protected final ApplicationContext applicationContext; + private final Random random = new Random(); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(InboxRepositoryImpl.class)); + private final JsonHandlingService jsonHandlingService; + private final InboxProperties inboxProperties; + + public InboxRepositoryImpl( + ApplicationContext applicationContext, + InboxProperties inboxProperties + ) { + this.applicationContext = applicationContext; + this.jsonHandlingService = this.applicationContext.getBean(JsonHandlingService.class); + this.inboxProperties = inboxProperties; + } + + + @Override + public CandidateInfo candidate(Instant lastCandidateCreationTimestamp, MessageOptions options) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + CandidateInfo candidate = null; + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + entityManager = entityManagerFactory.createEntityManager(); + + transaction = entityManager.getTransaction(); + transaction.begin(); + + QueueInboxEntity item = queryFactory.query(QueueInboxQuery.class) + .isActives(IsActive.Active) + .status(QueueInboxStatus.PENDING, QueueInboxStatus.ERROR) + .retryThreshold(options.getRetryThreashold()) + .createdAfter(lastCandidateCreationTimestamp) + .ordering(new Ordering().addAscending(QueueInboxEntity._createdAt)) + .first(); + + if (item != null) { + QueueInboxStatus prevState = item.getStatus(); + item.setStatus(QueueInboxStatus.PROCESSING); + + entityManager.merge(item); + entityManager.flush(); + + candidate = new CandidateInfo(); + candidate.setId(item.getId()); + candidate.setCreatedAt(item.getCreatedAt()); + candidate.setPreviousState(prevState); + } + + transaction.commit(); + } catch (OptimisticLockException ex) { + // we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working + this.logger.debug("Concurrency exception getting queue inbox. Skipping: {} ", ex.getMessage()); + if (transaction != null) transaction.rollback(); + candidate = null; + } catch (Exception ex) { + this.logger.error("Problem getting list of queue inbox. Skipping: {}", ex.getMessage(), ex); + if (transaction != null) transaction.rollback(); + candidate = null; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem getting list of queue inbox. Skipping: {}", ex.getMessage(), ex); + } + + return candidate; + } + + @Override + public Boolean shouldOmit(CandidateInfo candidate, Function shouldOmit) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + QueueInboxEntity item = queryFactory.query(QueueInboxQuery.class).ids(candidate.getId()).first(); + + if (item == null) { + this.logger.warn("Could not lookup queue inbox {} to process. Continuing...", candidate.getId()); + } else { + if (shouldOmit.apply(item)) { + item.setStatus(QueueInboxStatus.OMITTED); + + entityManager.merge(item); + entityManager.flush(); + success = true; + } + } + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return success; + } + + @Override + public boolean shouldWait(CandidateInfo candidate, Function itIsTimeFunc) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + QueueInboxEntity item = queryFactory.query(QueueInboxQuery.class).ids(candidate.getId()).first(); + + if (item.getRetryCount() != null && item.getRetryCount() >= 1) { + Boolean itIsTime = itIsTimeFunc.apply(item); + + if (!itIsTime) { + item.setStatus(candidate.getPreviousState()); + + entityManager.merge(item); + entityManager.flush(); + success = true; + } + + success = !itIsTime; + } + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return success; + } + + @Override + public QueueInbox create(InboxCreatorParams inboxCreatorParams) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + QueueInboxEntity queueMessage = null; + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + queueMessage = this.createQueueInboxEntity(inboxCreatorParams); + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + + transaction.begin(); + + entityManager.persist(queueMessage); + entityManager.flush(); + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return queueMessage; + } + + private QueueInboxEntity createQueueInboxEntity(InboxCreatorParams inboxCreatorParams) { + + QueueInboxEntity queueMessage = new QueueInboxEntity(); + queueMessage.setId(UUID.randomUUID()); + queueMessage.setTenantId(null); + queueMessage.setExchange(this.inboxProperties.getExchange()); + queueMessage.setRoute(inboxCreatorParams.getRoutingKey()); + queueMessage.setQueue(inboxCreatorParams.getQueueName()); + queueMessage.setApplicationId(inboxCreatorParams.getAppId()); + queueMessage.setMessageId(UUID.fromString(inboxCreatorParams.getMessageId())); + queueMessage.setMessage(inboxCreatorParams.getMessageBody()); + queueMessage.setIsActive(IsActive.Active); + queueMessage.setStatus(QueueInboxStatus.PENDING); + queueMessage.setRetryCount(0); + queueMessage.setCreatedAt(Instant.now()); + + return queueMessage; + } + + + @Override + public Boolean emit(CandidateInfo candidateInfo) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + QueueInboxEntity queueInboxMessage = queryFactory.query(QueueInboxQuery.class).ids(candidateInfo.getId()).first(); + + if (queueInboxMessage == null) { + this.logger.warn("Could not lookup queue inbox {} to process. Continuing...", candidateInfo.getId()); + } else { + + EventProcessingStatus status = this.processMessage(queueInboxMessage.getRoute(), queueInboxMessage.getMessageId().toString(), queueInboxMessage.getApplicationId(), queueInboxMessage.getMessage()); + switch (status) { + case Success: { + queueInboxMessage.setStatus(QueueInboxStatus.SUCCESSFUL); + break; + } + case Postponed: { + queueInboxMessage.setStatus(QueueInboxStatus.PARKED); + break; + } + case Error: { + queueInboxMessage.setStatus(QueueInboxStatus.ERROR); + queueInboxMessage.setRetryCount(queueInboxMessage.getRetryCount() != null ? queueInboxMessage.getRetryCount() + 1 : 0); + break; + } + case Discard: + default: { + queueInboxMessage.setStatus(QueueInboxStatus.DISCARD); + break; + } + } + success = status == EventProcessingStatus.Success; + + entityManager.merge(queueInboxMessage); + entityManager.flush(); + } + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return success; + } + + private EventProcessingStatus processMessage(String routingKey, String messageId, String appId, String message) { + IntegrationEventHandler handler; + if (this.RoutingKeyMatched(routingKey, this.inboxProperties.getUserRemovalTopic())) handler = this.applicationContext.getBean(UserRemovalIntegrationEventHandler.class); + else if (this.RoutingKeyMatched(routingKey, this.inboxProperties.getUserTouchedTopic())) handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class); + else handler = null; + + if (handler == null) return EventProcessingStatus.Discard; + + IntegrationEventProperties properties = new IntegrationEventProperties(); + properties.setAppId(appId); + properties.setMessageId(messageId); + + TrackedEvent event = this.jsonHandlingService.fromJsonSafe(TrackedEvent.class, message); +// using (LogContext.PushProperty(this._logTrackingConfig.LogTrackingContextName, @event.TrackingContextTag)) +// { + try { + return handler.handle(properties, message); + } catch (Exception ex) { + logger.error("problem handling event from routing key " + routingKey + ". Setting nack and continuing...", ex); + return EventProcessingStatus.Error; + } +// } + } + + private Boolean RoutingKeyMatched(String routingKey, List topics) { + if (topics == null || topics.size() == 0) return false; + return topics.stream().anyMatch(x -> x.equals(routingKey)); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/IntegrationEventHandler.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/IntegrationEventHandler.java new file mode 100644 index 000000000..fec42f871 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/IntegrationEventHandler.java @@ -0,0 +1,5 @@ +package eu.eudat.integrationevent.inbox; + +public interface IntegrationEventHandler { + EventProcessingStatus handle(IntegrationEventProperties properties, String message); +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/IntegrationEventProperties.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/IntegrationEventProperties.java new file mode 100644 index 000000000..90acd1d92 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/IntegrationEventProperties.java @@ -0,0 +1,22 @@ +package eu.eudat.integrationevent.inbox; + +public class IntegrationEventProperties { + private String messageId; + private String appId; + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalConsistencyHandler.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalConsistencyHandler.java new file mode 100644 index 000000000..825e2fe41 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalConsistencyHandler.java @@ -0,0 +1,26 @@ +package eu.eudat.integrationevent.inbox.userremoval; + +import eu.eudat.integrationevent.inbox.ConsistencyHandler; +import eu.eudat.query.UserQuery; +import gr.cite.tools.data.query.QueryFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class UserRemovalConsistencyHandler implements ConsistencyHandler { + + private final QueryFactory queryFactory; + + public UserRemovalConsistencyHandler(QueryFactory queryFactory) { + this.queryFactory = queryFactory; + } + + @Override + public Boolean isConsistent(UserRemovalConsistencyPredicates consistencyPredicates) { + long count = this.queryFactory.query(UserQuery.class).ids(consistencyPredicates.getUserId()).count(); + if (count == 0) return false; + return true; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalConsistencyPredicates.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalConsistencyPredicates.java new file mode 100644 index 000000000..911065e3f --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalConsistencyPredicates.java @@ -0,0 +1,21 @@ +package eu.eudat.integrationevent.inbox.userremoval; + +import eu.eudat.integrationevent.inbox.ConsistencyPredicates; + +import java.util.UUID; + +public class UserRemovalConsistencyPredicates implements ConsistencyPredicates { + public UserRemovalConsistencyPredicates(UUID userId) { + this.userId = userId; + } + + private UUID userId; + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEvent.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEvent.java new file mode 100644 index 000000000..49b81b156 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEvent.java @@ -0,0 +1,26 @@ +package eu.eudat.integrationevent.inbox.userremoval; + +import eu.eudat.integrationevent.TrackedEvent; + +import java.util.UUID; + +public class UserRemovalIntegrationEvent extends TrackedEvent { + private UUID userId; + private UUID tenant; + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public UUID getTenant() { + return tenant; + } + + public void setTenant(UUID tenant) { + this.tenant = tenant; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEventHandler.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEventHandler.java new file mode 100644 index 000000000..7861c4446 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEventHandler.java @@ -0,0 +1,6 @@ +package eu.eudat.integrationevent.inbox.userremoval; + +import eu.eudat.integrationevent.inbox.IntegrationEventHandler; + +public interface UserRemovalIntegrationEventHandler extends IntegrationEventHandler { +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEventHandlerImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEventHandlerImpl.java new file mode 100644 index 000000000..cb4f44619 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/userremoval/UserRemovalIntegrationEventHandlerImpl.java @@ -0,0 +1,125 @@ +package eu.eudat.integrationevent.inbox.userremoval; + +import eu.eudat.audit.AuditableAction; +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.fake.FakeRequestScope; +import eu.eudat.data.TenantEntity; +import eu.eudat.errorcode.ErrorThesaurusProperties; +import eu.eudat.integrationevent.inbox.EventProcessingStatus; +import eu.eudat.integrationevent.inbox.InboxPrincipal; +import eu.eudat.integrationevent.inbox.IntegrationEventProperties; +import eu.eudat.query.TenantQuery; +import eu.eudat.service.user.UserService; +import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; + +import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.logging.LoggerService; +import jakarta.persistence.*; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Scope; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Component; + + +import java.util.AbstractMap; +import java.util.Map; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegrationEventHandler { + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserRemovalIntegrationEventHandlerImpl.class)); + private final JsonHandlingService jsonHandlingService; + protected final ApplicationContext applicationContext; + private final ErrorThesaurusProperties errors; + private final MessageSource messageSource; + + public UserRemovalIntegrationEventHandlerImpl( + JsonHandlingService jsonHandlingService, + ApplicationContext applicationContext, + ErrorThesaurusProperties errors, + MessageSource messageSource + ) { + this.jsonHandlingService = jsonHandlingService; + this.applicationContext = applicationContext; + this.errors = errors; + this.messageSource = messageSource; + } + + @Override + public EventProcessingStatus handle(IntegrationEventProperties properties, String message) { + UserRemovalIntegrationEvent event = this.jsonHandlingService.fromJsonSafe(UserRemovalIntegrationEvent.class, message); + if (event == null) return EventProcessingStatus.Error; + if (event.getUserId() == null) throw new MyValidationException(this.errors.getModelValidation().getCode(), "userId", messageSource.getMessage("Validation_Required", new Object[]{"userId"}, LocaleContextHolder.getLocale())); + + EntityManager entityManager = null; + EntityTransaction transaction = null; + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); +// TenantScope scope = this.applicationContext.getBean(TenantScope.class); +// if (scope.isMultitenant() && event.getTenant() != null) { +// TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); +// if (tenant == null) { +// logger.error("missing tenant from event message"); +// return EventProcessingStatus.Error; +// } +// scope.setTenant(event.getTenant(), tenant.getCode()); +// } else if (scope.isMultitenant()) { +// logger.error("missing tenant from event message"); +// return EventProcessingStatus.Error; +// } + + CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); + currentPrincipalResolver.push(InboxPrincipal.build(properties)); + + UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class); + if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId())))) return EventProcessingStatus.Postponed; + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + entityManager = entityManagerFactory.createEntityManager(); + + transaction = entityManager.getTransaction(); + transaction.begin(); + + try { + UserService userService = this.applicationContext.getBean(UserService.class); + userService.deleteAndSave(event.getUserId()); + + AuditService auditService = this.applicationContext.getBean(AuditService.class); + + auditService.track(AuditableAction.User_Delete, Map.ofEntries( + new AbstractMap.SimpleEntry("id", event.getUserId()) + )); + //auditService.trackIdentity(AuditableAction.IdentityTracking_Action); + + transaction.commit(); + } catch (Exception e) { + transaction.rollback(); + throw e; + } finally { + currentPrincipalResolver.pop(); + } + + transaction.commit(); + } catch (OptimisticLockException ex) { + // we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working + this.logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage()); + if (transaction != null) transaction.rollback(); + } catch (Exception ex) { + this.logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex); + if (transaction != null) transaction.rollback(); + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex); + } + return null; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEvent.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEvent.java new file mode 100644 index 000000000..0ca679bff --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEvent.java @@ -0,0 +1,45 @@ +package eu.eudat.integrationevent.inbox.usertouched; + + +import eu.eudat.integrationevent.TrackedEvent; + +import java.util.UUID; + +public class UserTouchedIntegrationEvent extends TrackedEvent { + private UUID id; + private UUID tenant; + private String firstName; + private String lastName; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public UUID getTenant() { + return tenant; + } + + public void setTenant(UUID tenant) { + this.tenant = tenant; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEventHandler.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEventHandler.java new file mode 100644 index 000000000..ffc6db6cc --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEventHandler.java @@ -0,0 +1,6 @@ +package eu.eudat.integrationevent.inbox.usertouched; + +import eu.eudat.integrationevent.inbox.IntegrationEventHandler; + +public interface UserTouchedIntegrationEventHandler extends IntegrationEventHandler { +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java new file mode 100644 index 000000000..44bdd0e34 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/inbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java @@ -0,0 +1,116 @@ +package eu.eudat.integrationevent.inbox.usertouched; + +import eu.eudat.audit.AuditableAction; +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.fake.FakeRequestScope; +import eu.eudat.integrationevent.inbox.EventProcessingStatus; +import eu.eudat.integrationevent.inbox.InboxPrincipal; +import eu.eudat.integrationevent.inbox.IntegrationEventProperties; +import eu.eudat.service.user.UserService; +import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; +import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.validation.ValidationService; +import jakarta.persistence.*; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.AbstractMap; +import java.util.Map; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegrationEventHandler { + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserTouchedIntegrationEventHandlerImpl.class)); + private final JsonHandlingService jsonHandlingService; + protected final ApplicationContext applicationContext; + + public UserTouchedIntegrationEventHandlerImpl( + JsonHandlingService jsonHandlingService, + ApplicationContext applicationContext + ) { + this.jsonHandlingService = jsonHandlingService; + this.applicationContext = applicationContext; + } + + @Override + public EventProcessingStatus handle(IntegrationEventProperties properties, String message) { + UserTouchedIntegrationEvent event = this.jsonHandlingService.fromJsonSafe(UserTouchedIntegrationEvent.class, message); + if (event == null) return EventProcessingStatus.Error; + +// UserTouchedIntegrationEventPersist model = new UserTouchedIntegrationEventPersist(); +// model.setId(event.getId()); +// model.setFirstName(event.getFirstName()); +// model.setLastName(event.getLastName()); + + EntityManager entityManager = null; + EntityTransaction transaction = null; + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); +// TenantScope scope = this.applicationContext.getBean(TenantScope.class); +// if (scope.isMultitenant() && event.getTenant() != null) { +// TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); +// if (tenant == null) { +// logger.error("missing tenant from event message"); +// return EventProcessingStatus.Error; +// } +// scope.setTenant(event.getTenant(), tenant.getCode()); +// } else if (scope.isMultitenant()) { +// logger.error("missing tenant from event message"); +// return EventProcessingStatus.Error; +// } +// +// ValidationService validator = this.applicationContext.getBean(ValidationService.class); +// validator.validateForce(model); + + + CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); + currentPrincipalResolver.push(InboxPrincipal.build(properties)); + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + entityManager = entityManagerFactory.createEntityManager(); + + transaction = entityManager.getTransaction(); + transaction.begin(); + + try { + UserService userService = this.applicationContext.getBean(UserService.class); +// userService.persist(model, null); + + AuditService auditService = this.applicationContext.getBean(AuditService.class); + + auditService.track(AuditableAction.User_Persist, Map.ofEntries( +// new AbstractMap.SimpleEntry("model", model) + )); + + transaction.commit(); + } catch (Exception e) { + transaction.rollback(); + throw e; + } finally { + currentPrincipalResolver.pop(); + } + + transaction.commit(); + } catch (OptimisticLockException ex) { + // we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working + this.logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage()); + if (transaction != null) transaction.rollback(); + } catch (Exception ex) { + this.logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex); + if (transaction != null) transaction.rollback(); + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex); + } + return null; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxIntegrationEvent.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxIntegrationEvent.java new file mode 100644 index 000000000..d492544e9 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxIntegrationEvent.java @@ -0,0 +1,27 @@ +package eu.eudat.integrationevent.outbox; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import eu.eudat.integrationevent.TrackedEvent; +import gr.cite.rabbitmq.IntegrationEvent; + + +@JsonIgnoreProperties(ignoreUnknown = true) +public class OutboxIntegrationEvent extends IntegrationEvent { + public static final String FORGET_ME_COMPLETED = "FORGET_ME_COMPLETED"; + public static final String NOTIFY = "NOTIFY"; + public static final String TENANT_REACTIVATE = "TENANT_REACTIVATE"; + public static final String TENANT_REMOVE = "TENANT_REMOVE"; + public static final String TENANT_TOUCH = "TENANT_TOUCH"; + public static final String TENANT_USER_INVITE = "TENANT_USER_INVITE"; + public static final String WHAT_YOU_KNOW_ABOUT_ME_COMPLETED = "WHAT_YOU_KNOW_ABOUT_ME_COMPLETED"; + public static final String GENERATE_FILE = "GENERATE_FILE"; + private TrackedEvent event; + + public TrackedEvent getEvent() { + return event; + } + + public void setEvent(TrackedEvent event) { + this.event = event; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxProperties.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxProperties.java new file mode 100644 index 000000000..e9e0c9680 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxProperties.java @@ -0,0 +1,89 @@ +package eu.eudat.integrationevent.outbox; + + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.bind.ConstructorBinding; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.constraints.NotNull; + +@Validated +@ConfigurationProperties(prefix = "queue.task.publisher.options") +//@ConstructorBinding +public class OutboxProperties { + @NotNull + private final String exchange; + @NotNull + private final String tenantTouchTopic; + @NotNull + private final String tenantRemovalTopic; + @NotNull + private final String tenantReactivationTopic; + @NotNull + private final String tenantUserInviteTopic; + @NotNull + private final String notifyTopic; + @NotNull + private final String forgetMeCompletedTopic; + @NotNull + private final String whatYouKnowAboutMeCompletedTopic; + @NotNull + private final String generateFileTopic; + + public OutboxProperties(String exchange, + String tenantTouchTopic, + String tenantRemovalTopic, + String tenantReactivationTopic, + String tenantUserInviteTopic, + String notifyTopic, + String forgetMeCompletedTopic, + String whatYouKnowAboutMeCompletedTopic, + String generateFileTopic + ) { + this.exchange = exchange; + this.tenantTouchTopic = tenantTouchTopic; + this.tenantRemovalTopic = tenantRemovalTopic; + this.tenantReactivationTopic = tenantReactivationTopic; + this.tenantUserInviteTopic = tenantUserInviteTopic; + this.notifyTopic = notifyTopic; + this.forgetMeCompletedTopic = forgetMeCompletedTopic; + this.whatYouKnowAboutMeCompletedTopic = whatYouKnowAboutMeCompletedTopic; + this.generateFileTopic = generateFileTopic; + } + + public String getExchange() { + return exchange; + } + + public String getTenantTouchTopic() { + return tenantTouchTopic; + } + + public String getTenantRemovalTopic() { + return tenantRemovalTopic; + } + + public String getTenantReactivationTopic() { + return tenantReactivationTopic; + } + + public String getTenantUserInviteTopic() { + return tenantUserInviteTopic; + } + + public String getNotifyTopic() { + return notifyTopic; + } + + public String getForgetMeCompletedTopic() { + return forgetMeCompletedTopic; + } + + public String getWhatYouKnowAboutMeCompletedTopic() { + return whatYouKnowAboutMeCompletedTopic; + } + + public String getGenerateFileTopic() { + return generateFileTopic; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxRepositoryImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxRepositoryImpl.java new file mode 100644 index 000000000..a9e36748c --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxRepositoryImpl.java @@ -0,0 +1,428 @@ +package eu.eudat.integrationevent.outbox; + +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.fake.FakeRequestScope; +import eu.eudat.data.QueueOutboxEntity; +import eu.eudat.query.QueueOutboxQuery; +import gr.cite.queueoutbox.entity.QueueOutbox; +import gr.cite.queueoutbox.entity.QueueOutboxNotifyStatus; +import gr.cite.queueoutbox.repository.CandidateInfo; +import gr.cite.queueoutbox.repository.OutboxRepository; +import gr.cite.queueoutbox.task.MessageOptions; +import gr.cite.rabbitmq.IntegrationEvent; +import gr.cite.tools.data.query.Ordering; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.logging.LoggerService; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import jakarta.persistence.OptimisticLockException; +import java.time.Instant; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class OutboxRepositoryImpl implements OutboxRepository { + + protected final ApplicationContext applicationContext; + private final Random random = new Random(); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxRepositoryImpl.class)); + private final JsonHandlingService jsonHandlingService; + private final OutboxProperties outboxProperties; + + public OutboxRepositoryImpl( + ApplicationContext applicationContext, + OutboxProperties outboxProperties + ) { + this.applicationContext = applicationContext; + this.jsonHandlingService = this.applicationContext.getBean(JsonHandlingService.class); + this.outboxProperties = outboxProperties; + } + + @Override + public CandidateInfo candidate(Instant lastCandidateCreationTimestamp, MessageOptions messageOptions, Function onConfirmTimeout) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + CandidateInfo candidate = null; + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + entityManager = entityManagerFactory.createEntityManager(); + + transaction = entityManager.getTransaction(); + transaction.begin(); + + QueueOutboxEntity item = queryFactory.query(QueueOutboxQuery.class) + .isActives(IsActive.Active) + .notifyStatus(QueueOutboxNotifyStatus.PENDING, QueueOutboxNotifyStatus.WAITING_CONFIRMATION, QueueOutboxNotifyStatus.ERROR) + .retryThreshold(messageOptions.getRetryThreashold()) + .confirmTimeout(messageOptions.getConfirmTimeoutSeconds()) + .createdAfter(lastCandidateCreationTimestamp) + .ordering(new Ordering().addAscending(QueueOutboxEntity._createdAt)) + .first(); + + if (item != null) { + boolean confirmTimeout = onConfirmTimeout.apply(item); + + QueueOutboxNotifyStatus prevState = item.getNotifyStatus(); + item.setNotifyStatus(QueueOutboxNotifyStatus.PROCESSING); + + entityManager.merge(item); + entityManager.flush(); + + candidate = new CandidateInfo(); + candidate.setId(item.getId()); + candidate.setCreatedAt(item.getCreatedAt()); + candidate.setPreviousState(prevState); + } + + transaction.commit(); + } catch (OptimisticLockException ex) { + // we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working + this.logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage()); + if (transaction != null) transaction.rollback(); + candidate = null; + } catch (Exception ex) { + this.logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex); + if (transaction != null) transaction.rollback(); + candidate = null; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex); + } + + return candidate; + } + + @Override + public Boolean shouldOmit(CandidateInfo candidate, Function shouldOmit) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + QueueOutboxEntity item = queryFactory.query(QueueOutboxQuery.class).ids(candidate.getId()).first(); + + if (item == null) { + this.logger.warn("Could not lookup queue outbox {} to process. Continuing...", candidate.getId()); + } else { + if (shouldOmit.apply(item)) { + item.setNotifyStatus(QueueOutboxNotifyStatus.OMITTED); + + entityManager.merge(item); + entityManager.flush(); + success = true; + } + } + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return success; + } + + @Override + public Boolean shouldWait(CandidateInfo candidate, Function itIsTimeFunc) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + QueueOutboxEntity item = queryFactory.query(QueueOutboxQuery.class).ids(candidate.getId()).first(); + + if (item.getRetryCount() != null && item.getRetryCount() >= 1) { + Boolean itIsTime = itIsTimeFunc.apply(item); + + if (!itIsTime) { + item.setNotifyStatus(candidate.getPreviousState()); + + entityManager.merge(item); + entityManager.flush(); + success = true; + } + + success = !itIsTime; + } + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return success; + } + + @Override + public Boolean process(CandidateInfo candidateInfo, Boolean isAutoconfirmOnPublish, Function publish) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + QueueOutboxEntity item = queryFactory.query(QueueOutboxQuery.class).ids(candidateInfo.getId()).first(); + + if (item == null) { + this.logger.warn("Could not lookup queue outbox {} to process. Continuing...", candidateInfo.getId()); + } else { + + success = publish.apply(item); + if (success) { + if (isAutoconfirmOnPublish) { + item.setNotifyStatus(QueueOutboxNotifyStatus.CONFIRMED); + item.setConfirmedAt(Instant.now()); + } else { + item.setNotifyStatus(QueueOutboxNotifyStatus.WAITING_CONFIRMATION); + } + item.setPublishedAt(Instant.now()); + } else { + item.setNotifyStatus(QueueOutboxNotifyStatus.ERROR); + item.setRetryCount(item.getRetryCount() != null ? item.getRetryCount() + 1 : 0); + item.setPublishedAt(null); + } + + entityManager.merge(item); + entityManager.flush(); + } + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return success; + } + + @Override + public void handleConfirm(List confirmedMessages) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + List queueOutboxMessages = queryFactory.query(QueueOutboxQuery.class).ids(confirmedMessages).collect(); + + if (queueOutboxMessages == null) { + this.logger.warn("Could not lookup messages {} to process. Continuing...", String.join(",", confirmedMessages.stream().map(x -> x.toString()).collect(Collectors.toList()))); + } else { + + for (QueueOutboxEntity queueOutboxMessage : queueOutboxMessages) { + queueOutboxMessage.setNotifyStatus(QueueOutboxNotifyStatus.CONFIRMED); + queueOutboxMessage.setConfirmedAt(Instant.now()); + entityManager.merge(queueOutboxMessage); + } + + entityManager.flush(); + } + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + } + + @Override + public void handleNack(List nackedMessages) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + transaction.begin(); + + QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); + List queueOutboxMessages = queryFactory.query(QueueOutboxQuery.class).ids(nackedMessages).collect(); + + if (queueOutboxMessages == null) { + this.logger.warn("Could not lookup messages {} to process. Continuing...", String.join(",", nackedMessages.stream().map(x -> x.toString()).collect(Collectors.toList()))); + } else { + + for (QueueOutboxEntity queueOutboxMessage : queueOutboxMessages) { + queueOutboxMessage.setNotifyStatus(QueueOutboxNotifyStatus.ERROR); + queueOutboxMessage.setRetryCount(queueOutboxMessage.getRetryCount() != null ? queueOutboxMessage.getRetryCount() + 1 : 0); + entityManager.merge(queueOutboxMessage); + } + + entityManager.flush(); + } + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + } + + @Override + public QueueOutbox create(IntegrationEvent item) { + EntityTransaction transaction = null; + EntityManager entityManager = null; + Boolean success = false; + QueueOutboxEntity queueMessage = null; + try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) { + try { + queueMessage = this.mapEvent((OutboxIntegrationEvent) item); + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + transaction = entityManager.getTransaction(); + + transaction.begin(); + + entityManager.persist(queueMessage); + entityManager.flush(); + + transaction.commit(); + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + if (transaction != null) transaction.rollback(); + success = false; + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + this.logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + return queueMessage; + } + + private QueueOutboxEntity mapEvent(OutboxIntegrationEvent event) { + String routingKey; + switch (event.getType()) { + case OutboxIntegrationEvent.TENANT_REACTIVATE: { + routingKey = this.outboxProperties.getTenantReactivationTopic(); + break; + } + case OutboxIntegrationEvent.TENANT_REMOVE: { + routingKey = this.outboxProperties.getTenantRemovalTopic(); + break; + } + case OutboxIntegrationEvent.TENANT_TOUCH: { + routingKey = this.outboxProperties.getTenantTouchTopic(); + break; + } + case OutboxIntegrationEvent.TENANT_USER_INVITE: { + routingKey = this.outboxProperties.getTenantUserInviteTopic(); + break; + } + case OutboxIntegrationEvent.FORGET_ME_COMPLETED: { + routingKey = this.outboxProperties.getForgetMeCompletedTopic(); + break; + } + case OutboxIntegrationEvent.NOTIFY: { + routingKey = this.outboxProperties.getNotifyTopic(); + break; + } + case OutboxIntegrationEvent.WHAT_YOU_KNOW_ABOUT_ME_COMPLETED: { + routingKey = this.outboxProperties.getWhatYouKnowAboutMeCompletedTopic(); + break; + } + case OutboxIntegrationEvent.GENERATE_FILE: { + routingKey = this.outboxProperties.getGenerateFileTopic(); + break; + } + default: { + logger.error("unrecognized outgoing integration event {}. Skipping...", event.getType()); + return null; + } + } + + UUID correlationId = UUID.randomUUID(); + if (event.getEvent() != null) event.getEvent().setTrackingContextTag(correlationId.toString()); + event.setMessage(this.jsonHandlingService.toJsonSafe(event.getEvent())); + //this._logTrackingService.Trace(correlationId.ToString(), $"Correlating current tracking context with new correlationId {correlationId}"); + + QueueOutboxEntity queueMessage = new QueueOutboxEntity(); + queueMessage.setId(UUID.randomUUID()); + queueMessage.setTenantId(null); + queueMessage.setExchange(this.outboxProperties.getExchange()); + queueMessage.setRoute(routingKey); + queueMessage.setMessageId(event.getMessageId()); + queueMessage.setMessage(this.jsonHandlingService.toJsonSafe(event)); + queueMessage.setIsActive(IsActive.Active); + queueMessage.setNotifyStatus(QueueOutboxNotifyStatus.PENDING); + queueMessage.setRetryCount(0); + queueMessage.setCreatedAt(Instant.now()); + queueMessage.setUpdatedAt(Instant.now()); + + return queueMessage; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxService.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxService.java new file mode 100644 index 000000000..ba72e08a9 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxService.java @@ -0,0 +1,5 @@ +package eu.eudat.integrationevent.outbox; + +public interface OutboxService { + void publish(OutboxIntegrationEvent event); +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxServiceImpl.java new file mode 100644 index 000000000..3d1a5b7be --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/OutboxServiceImpl.java @@ -0,0 +1,43 @@ +package eu.eudat.integrationevent.outbox; + + +import eu.eudat.commons.JsonHandlingService; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.RequestScope; + +@Component +@RequestScope +public class OutboxServiceImpl implements OutboxService { + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxServiceImpl.class)); + + private final OutboxProperties config; + private final JsonHandlingService jsonHandlingService; + private final ApplicationEventPublisher eventPublisher; + + public OutboxServiceImpl( + OutboxProperties config, + JsonHandlingService jsonHandlingService, + ApplicationEventPublisher eventPublisher + ) { + this.config = config; + this.jsonHandlingService = jsonHandlingService; + this.eventPublisher = eventPublisher; + } + + @Override + public void publish(OutboxIntegrationEvent event) { + try { + eventPublisher.publishEvent(event); + return; + } catch (Exception ex) { + logger.error(new MapLogEntry(String.format("Could not save message ", event.getMessage())).And("message", event.getMessage()).And("ex", ex)); + //Still want to skip it from processing + return; + } + + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEvent.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEvent.java new file mode 100644 index 000000000..e39375d9a --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEvent.java @@ -0,0 +1,74 @@ +package eu.eudat.integrationevent.outbox.notification; + +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.commons.enums.old.notification.NotificationType; +import eu.eudat.integrationevent.TrackedEvent; + +import java.util.UUID; + +public class NotificationIntegrationEvent extends TrackedEvent { + + private UUID userId; + private UUID tenant; + private UUID notificationType; + private NotificationContactType contactTypeHint; + private String contactHint; + private String data; + private String provenanceRef; + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public UUID getTenant() { + return tenant; + } + + public void setTenant(UUID tenant) { + this.tenant = tenant; + } + + public UUID getNotificationType() { + return notificationType; + } + + public void setNotificationType(UUID notificationType) { + this.notificationType = notificationType; + } + + public NotificationContactType getContactTypeHint() { + return contactTypeHint; + } + + public void setContactTypeHint(NotificationContactType 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 String getProvenanceRef() { + return provenanceRef; + } + + public void setProvenanceRef(String provenanceRef) { + this.provenanceRef = provenanceRef; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEventHandler.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEventHandler.java new file mode 100644 index 000000000..656aba6e7 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEventHandler.java @@ -0,0 +1,7 @@ +package eu.eudat.integrationevent.outbox.notification; + +import javax.management.InvalidApplicationException; + +public interface NotificationIntegrationEventHandler { + void handle(NotificationIntegrationEvent event) throws InvalidApplicationException; +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEventHandlerImpl.java b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEventHandlerImpl.java new file mode 100644 index 000000000..130d6b20d --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/integrationevent/outbox/notification/NotificationIntegrationEventHandlerImpl.java @@ -0,0 +1,106 @@ +package eu.eudat.integrationevent.outbox.notification; + + +import eu.eudat.audit.AuditableAction; +import eu.eudat.commons.enums.ContactInfoType; +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.commons.enums.notification.NotificationNotifyState; +import eu.eudat.commons.enums.notification.NotificationTrackingProcess; +import eu.eudat.commons.enums.notification.NotificationTrackingState; +import eu.eudat.data.UserContactInfoEntity; +import eu.eudat.data.UserEntity; +import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent; +import eu.eudat.integrationevent.outbox.OutboxService; +import eu.eudat.model.persist.notification.NotificationPersist; +import eu.eudat.query.UserContactInfoQuery; +import eu.eudat.query.UserQuery; +import eu.eudat.service.notification.NotificationService; +import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.validation.ValidationService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.RequestScope; + +import javax.management.InvalidApplicationException; +import java.time.Instant; +import java.util.List; +import java.util.UUID; + +@Component +@RequestScope +public class NotificationIntegrationEventHandlerImpl implements NotificationIntegrationEventHandler { + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotificationIntegrationEventHandlerImpl.class)); + private final NotificationService notificationService; + private final ValidationService validationService; + private final QueryFactory queryFactory; + private final AuditService auditService; + private final OutboxService outboxService; + + @Autowired + public NotificationIntegrationEventHandlerImpl( + OutboxService outboxService, + NotificationService notificationService, + ValidationService validationService, + QueryFactory queryFactory, + AuditService auditService) { + this.outboxService = outboxService; + this.notificationService = notificationService; + this.validationService = validationService; + this.queryFactory = queryFactory; + this.auditService = auditService; + } + + @Override + public void handle(NotificationIntegrationEvent event) throws InvalidApplicationException { +// OutboxIntegrationEvent message = new OutboxIntegrationEvent(); +// message.setMessageId(UUID.randomUUID()); +// message.setType(OutboxIntegrationEvent.NOTIFY); +// message.setEvent(event); +// this.outboxService.publish(message); + NotificationPersist persist = new NotificationPersist(); + persist.setType(event.getNotificationType()); + persist.setUserId(event.getUserId()); + persist.setContactHint(event.getContactHint()); + persist.setContactTypeHint(event.getContactTypeHint()); + persist.setData(event.getData()); + persist.setNotifyState(NotificationNotifyState.PENDING); + persist.setNotifiedWith(NotificationContactType.EMAIL); + persist.setRetryCount(0); + persist.setTrackingState(NotificationTrackingState.UNDEFINED); + persist.setTrackingProcess(NotificationTrackingProcess.PENDING); + persist.setTrackingData(null); + persist.setProvenanceRef(event.getProvenanceRef()); + persist.setNotifiedAt(Instant.now()); + //validationService.validateForce(persist); + if (isNotificationConsistent(persist)) { + notificationService.persist(persist, null); + auditService.track(AuditableAction.Notification_Persist, "notification_event", event); + } + } + + private boolean isNotificationConsistent(NotificationPersist notification) { + switch (notification.getContactTypeHint()){ + case IN_APP:{ + if (notification.getUserId() == null) return false; + + List users = this.queryFactory.query(UserQuery.class).ids(notification.getUserId()).collect(); + return users.size() > 0; + } + case EMAIL:{ + if (notification.getContactHint() != null && !notification.getContactHint().isBlank()) return true; + + if (notification.getUserId() == null) return false; + + List userContactInfoEntities = this.queryFactory.query(UserContactInfoQuery.class).types(ContactInfoType.Email).userIds(notification.getUserId()).collect(); + return userContactInfoEntities.size() > 0; + } + default: + throw new MyApplicationException("invalid type " + notification.getContactTypeHint()); + + } + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/persist/notification/NotificationPersist.java b/dmp-backend/core/src/main/java/eu/eudat/model/persist/notification/NotificationPersist.java new file mode 100644 index 000000000..358556800 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/persist/notification/NotificationPersist.java @@ -0,0 +1,169 @@ +package eu.eudat.model.persist.notification; + +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.commons.enums.notification.NotificationNotifyState; +import eu.eudat.commons.enums.notification.NotificationTrackingProcess; +import eu.eudat.commons.enums.notification.NotificationTrackingState; +import eu.eudat.commons.validation.FieldNotNullIfOtherSet; +import eu.eudat.commons.validation.ValidId; +import jakarta.validation.constraints.NotNull; + + +import java.time.Instant; +import java.util.UUID; + +@FieldNotNullIfOtherSet(message = "{validation.hashempty}") +public class NotificationPersist { + + @ValidId(message = "{validation.invalidid}") + private UUID id; + + @NotNull(message = "{validation.empty}") + private UUID userId; + + private UUID type; + + private NotificationContactType contactTypeHint; + + private String contactHint; + + private String data; + + private NotificationNotifyState notifyState; + + private NotificationContactType notifiedWith; + + private Integer retryCount; + + private NotificationTrackingState trackingState; + + private NotificationTrackingProcess trackingProcess; + + private String trackingData; + + private String provenanceRef; + + private Instant notifiedAt; + + private String hash; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public UUID getType() { + return type; + } + + public void setType(UUID type) { + this.type = type; + } + + public NotificationContactType getContactTypeHint() { + return contactTypeHint; + } + + public void setContactTypeHint(NotificationContactType 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 NotificationNotifyState getNotifyState() { + return notifyState; + } + + public void setNotifyState(NotificationNotifyState notifyState) { + this.notifyState = notifyState; + } + + public NotificationContactType getNotifiedWith() { + return notifiedWith; + } + + public void setNotifiedWith(NotificationContactType notifiedWith) { + this.notifiedWith = notifiedWith; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public NotificationTrackingState getTrackingState() { + return trackingState; + } + + public void setTrackingState(NotificationTrackingState trackingState) { + this.trackingState = trackingState; + } + + public NotificationTrackingProcess getTrackingProcess() { + return trackingProcess; + } + + public void setTrackingProcess(NotificationTrackingProcess trackingProcess) { + this.trackingProcess = trackingProcess; + } + + public String getTrackingData() { + return trackingData; + } + + public void setTrackingData(String trackingData) { + this.trackingData = trackingData; + } + + public String getProvenanceRef() { + return provenanceRef; + } + + public void setProvenanceRef(String provenanceRef) { + this.provenanceRef = provenanceRef; + } + + public Instant getNotifiedAt() { + return notifiedAt; + } + + public void setNotifiedAt(Instant notifiedAt) { + this.notifiedAt = notifiedAt; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/QueueInboxQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/QueueInboxQuery.java new file mode 100644 index 000000000..9d0877822 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/query/QueueInboxQuery.java @@ -0,0 +1,219 @@ +package eu.eudat.query; + + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.QueueInboxEntity; +import gr.cite.queueinbox.entity.QueueInboxStatus; +import gr.cite.tools.data.query.FieldResolver; +import gr.cite.tools.data.query.Ordering; +import gr.cite.tools.data.query.QueryBase; +import gr.cite.tools.data.query.QueryContext; +import jakarta.persistence.Tuple; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.*; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class QueueInboxQuery extends QueryBase { + + private Collection ids; + private Instant createdAfter; + private Collection isActives; + private Collection exchanges; + private Collection routes; + private Collection status; + private Integer retryThreshold; + + public QueueInboxQuery ids(UUID value) { + this.ids = List.of(value); + return this; + } + + public QueueInboxQuery ids(UUID... value) { + this.ids = Arrays.asList(value); + return this; + } + + public QueueInboxQuery ids(List value) { + this.ids = value; + return this; + } + + public QueueInboxQuery isActives(IsActive value) { + this.isActives = List.of(value); + return this; + } + + public QueueInboxQuery isActives(IsActive... value) { + this.isActives = Arrays.asList(value); + return this; + } + + public QueueInboxQuery isActives(List value) { + this.isActives = value; + return this; + } + + public QueueInboxQuery exchanges(String value) { + this.exchanges = List.of(value); + return this; + } + + public QueueInboxQuery exchanges(String... value) { + this.exchanges = Arrays.asList(value); + return this; + } + + public QueueInboxQuery exchanges(List value) { + this.exchanges = value; + return this; + } + + public QueueInboxQuery routes(String value) { + this.routes = List.of(value); + return this; + } + + public QueueInboxQuery routes(String... value) { + this.routes = Arrays.asList(value); + return this; + } + + public QueueInboxQuery routes(List value) { + this.routes = value; + return this; + } + + public QueueInboxQuery status(QueueInboxStatus value) { + this.status = List.of(value); + return this; + } + + public QueueInboxQuery status(QueueInboxStatus... value) { + this.status = Arrays.asList(value); + return this; + } + + public QueueInboxQuery status(List value) { + this.status = value; + return this; + } + + public QueueInboxQuery createdAfter(Instant value) { + this.createdAfter = value; + return this; + } + + public QueueInboxQuery retryThreshold(Integer value) { + this.retryThreshold = value; + return this; + } + + public QueueInboxQuery ordering(Ordering ordering) { + this.setOrder(ordering); + return this; + } + + @Override + protected Class entityClass() { + return QueueInboxEntity.class; + } + + @Override + protected Boolean isFalseQuery() { + return this.isEmpty(this.ids) || this.isEmpty(this.isActives) || this.isEmpty(this.exchanges) + || this.isEmpty(this.routes) || this.isEmpty(this.status); + } + + @Override + protected Predicate applyFilters(QueryContext queryContext) { + List predicates = new ArrayList<>(); + if (this.ids != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueInboxEntity._id)); + for (UUID item : this.ids) inClause.value(item); + predicates.add(inClause); + } + + if (this.createdAfter != null) { + predicates.add(queryContext.CriteriaBuilder.greaterThan(queryContext.Root.get(QueueInboxEntity._createdAt), this.createdAfter)); + } + if (this.isActives != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueInboxEntity._isActive)); + for (IsActive item : this.isActives) inClause.value(item); + predicates.add(inClause); + } + if (this.exchanges != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueInboxEntity._exchange)); + for (String item : this.exchanges) inClause.value(item); + predicates.add(inClause); + } + if (this.routes != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueInboxEntity._route)); + for (String item : this.routes) inClause.value(item); + predicates.add(inClause); + } + + if (this.status != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueInboxEntity._status)); + for (QueueInboxStatus item : this.status) inClause.value(item); + predicates.add(inClause); + } + + if (this.retryThreshold != null) { + predicates.add(queryContext.CriteriaBuilder.or(queryContext.CriteriaBuilder.isNull(queryContext.Root.get(QueueInboxEntity._retryCount)), + queryContext.CriteriaBuilder.lessThanOrEqualTo(queryContext.Root.get(QueueInboxEntity._retryCount), this.retryThreshold))); + } + + if (predicates.size() > 0) { + Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); + return queryContext.CriteriaBuilder.and(predicatesArray); + } else { + return null; + } + } + + @Override + protected QueueInboxEntity convert(Tuple tuple, Set columns) { + QueueInboxEntity item = new QueueInboxEntity(); + item.setId(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._id, UUID.class)); + item.setExchange(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._exchange, String.class)); + item.setTenantId(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._tenantId, UUID.class)); + item.setRoute(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._route, String.class)); + item.setMessage(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._message, String.class)); + item.setMessageId(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._messageId, UUID.class)); + item.setCreatedAt(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._createdAt, Instant.class)); + item.setIsActive(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._isActive, IsActive.class)); + item.setStatus(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._status, QueueInboxStatus.class)); + item.setRetryCount(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._retryCount, Integer.class)); + item.setQueue(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._queue, String.class)); + item.setApplicationId(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._applicationId, String.class)); + item.setCreatedAt(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._createdAt, Instant.class)); + item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, QueueInboxEntity._updatedAt, Instant.class)); + return item; + } + + @Override + protected String fieldNameOf(FieldResolver item) { + if (item.match(QueueInboxEntity._id)) return QueueInboxEntity._id; + else if (item.match(QueueInboxEntity._exchange)) return QueueInboxEntity._exchange; + else if (item.match(QueueInboxEntity._tenantId)) return QueueInboxEntity._tenantId; + else if (item.match(QueueInboxEntity._route)) return QueueInboxEntity._route; + else if (item.match(QueueInboxEntity._message)) return QueueInboxEntity._message; + else if (item.match(QueueInboxEntity._messageId)) return QueueInboxEntity._messageId; + else if (item.match(QueueInboxEntity._createdAt)) return QueueInboxEntity._createdAt; + else if (item.match(QueueInboxEntity._isActive)) return QueueInboxEntity._isActive; + else if (item.match(QueueInboxEntity._status)) return QueueInboxEntity._status; + else if (item.match(QueueInboxEntity._retryCount)) return QueueInboxEntity._retryCount; + else if (item.match(QueueInboxEntity._queue)) return QueueInboxEntity._queue; + else if (item.match(QueueInboxEntity._applicationId)) return QueueInboxEntity._applicationId; + else if (item.match(QueueInboxEntity._createdAt)) return QueueInboxEntity._createdAt; + else if (item.match(QueueInboxEntity._updatedAt)) return QueueInboxEntity._updatedAt; + else return null; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/QueueOutboxQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/QueueOutboxQuery.java new file mode 100644 index 000000000..05c5d9c45 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/query/QueueOutboxQuery.java @@ -0,0 +1,236 @@ +package eu.eudat.query; + + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.QueueOutboxEntity; +import gr.cite.queueoutbox.entity.QueueOutboxNotifyStatus; +import gr.cite.tools.data.query.FieldResolver; +import gr.cite.tools.data.query.Ordering; +import gr.cite.tools.data.query.QueryBase; +import gr.cite.tools.data.query.QueryContext; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import jakarta.persistence.Tuple; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import java.time.Instant; +import java.util.*; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class QueueOutboxQuery extends QueryBase { + + private Collection ids; + private Instant createdAfter; + private Collection isActives; + private Collection exchanges; + private Collection routes; + private Collection notifyStatus; + private Integer retryThreshold; + private Integer confirmTimeout; + + public QueueOutboxQuery ids(UUID value) { + this.ids = List.of(value); + return this; + } + + public QueueOutboxQuery ids(UUID... value) { + this.ids = Arrays.asList(value); + return this; + } + + public QueueOutboxQuery ids(List value) { + this.ids = value; + return this; + } + + public QueueOutboxQuery isActives(IsActive value) { + this.isActives = List.of(value); + return this; + } + + public QueueOutboxQuery isActives(IsActive... value) { + this.isActives = Arrays.asList(value); + return this; + } + + public QueueOutboxQuery isActives(List value) { + this.isActives = value; + return this; + } + + public QueueOutboxQuery exchanges(String value) { + this.exchanges = List.of(value); + return this; + } + + public QueueOutboxQuery exchanges(String... value) { + this.exchanges = Arrays.asList(value); + return this; + } + + public QueueOutboxQuery exchanges(List value) { + this.exchanges = value; + return this; + } + + public QueueOutboxQuery routes(String value) { + this.routes = List.of(value); + return this; + } + + public QueueOutboxQuery routes(String... value) { + this.routes = Arrays.asList(value); + return this; + } + + public QueueOutboxQuery routes(List value) { + this.routes = value; + return this; + } + + public QueueOutboxQuery notifyStatus(QueueOutboxNotifyStatus value) { + this.notifyStatus = List.of(value); + return this; + } + + public QueueOutboxQuery notifyStatus(QueueOutboxNotifyStatus... value) { + this.notifyStatus = Arrays.asList(value); + return this; + } + + public QueueOutboxQuery notifyStatus(List value) { + this.notifyStatus = value; + return this; + } + + public QueueOutboxQuery createdAfter(Instant value) { + this.createdAfter = value; + return this; + } + + public QueueOutboxQuery retryThreshold(Integer value) { + this.retryThreshold = value; + return this; + } + + public QueueOutboxQuery confirmTimeout(Integer value) { + this.confirmTimeout = value; + return this; + } + + public QueueOutboxQuery ordering(Ordering ordering) { + this.setOrder(ordering); + return this; + } + + @Override + protected Class entityClass() { + return QueueOutboxEntity.class; + } + + @Override + protected Boolean isFalseQuery() { + return this.isEmpty(this.ids) || this.isEmpty(this.isActives) || this.isEmpty(this.exchanges) + || this.isEmpty(this.routes) || this.isEmpty(this.notifyStatus); + } + + @Override + protected Predicate applyFilters(QueryContext queryContext) { + List predicates = new ArrayList<>(); + if (this.ids != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueOutboxEntity._id)); + for (UUID item : this.ids) inClause.value(item); + predicates.add(inClause); + } + + if (this.createdAfter != null) { + predicates.add(queryContext.CriteriaBuilder.greaterThan(queryContext.Root.get(QueueOutboxEntity._createdAt), this.createdAfter)); + } + if (this.isActives != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueOutboxEntity._isActive)); + for (IsActive item : this.isActives) inClause.value(item); + predicates.add(inClause); + } + if (this.exchanges != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueOutboxEntity._exchange)); + for (String item : this.exchanges) inClause.value(item); + predicates.add(inClause); + } + if (this.routes != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueOutboxEntity._route)); + for (String item : this.routes) inClause.value(item); + predicates.add(inClause); + } + + if (this.notifyStatus != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(QueueOutboxEntity._notifyStatus)); + for (QueueOutboxNotifyStatus item : this.notifyStatus) inClause.value(item); + predicates.add(inClause); + } + + if (this.retryThreshold != null) { + predicates.add(queryContext.CriteriaBuilder.or(queryContext.CriteriaBuilder.isNull(queryContext.Root.get(QueueOutboxEntity._retryCount)), + queryContext.CriteriaBuilder.lessThanOrEqualTo(queryContext.Root.get(QueueOutboxEntity._retryCount), this.retryThreshold))); + } + + if (this.confirmTimeout != null) { + predicates.add(queryContext.CriteriaBuilder.or(queryContext.CriteriaBuilder.isNull(queryContext.Root.get(QueueOutboxEntity._publishedAt)), + queryContext.CriteriaBuilder.and( + queryContext.CriteriaBuilder.isNotNull(queryContext.Root.get(QueueOutboxEntity._publishedAt)), + queryContext.CriteriaBuilder.isNull(queryContext.Root.get(QueueOutboxEntity._confirmedAt)), + queryContext.CriteriaBuilder.lessThan(queryContext.Root.get(QueueOutboxEntity._publishedAt), Instant.now().minusSeconds(this.confirmTimeout)) + ) + )); + } + + + if (predicates.size() > 0) { + Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); + return queryContext.CriteriaBuilder.and(predicatesArray); + } else { + return null; + } + } + + @Override + protected QueueOutboxEntity convert(Tuple tuple, Set columns) { + QueueOutboxEntity item = new QueueOutboxEntity(); + item.setId(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._id, UUID.class)); + item.setExchange(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._exchange, String.class)); + item.setTenantId(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._tenantId, UUID.class)); + item.setRoute(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._route, String.class)); + item.setMessage(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._message, String.class)); + item.setMessageId(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._messageId, UUID.class)); + item.setCreatedAt(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._createdAt, Instant.class)); + item.setIsActive(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._isActive, IsActive.class)); + item.setNotifyStatus(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._notifyStatus, QueueOutboxNotifyStatus.class)); + item.setRetryCount(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._retryCount, Integer.class)); + item.setPublishedAt(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._publishedAt, Instant.class)); + item.setConfirmedAt(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._confirmedAt, Instant.class)); + item.setCreatedAt(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._createdAt, Instant.class)); + item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, QueueOutboxEntity._updatedAt, Instant.class)); + return item; + } + + @Override + protected String fieldNameOf(FieldResolver item) { + if (item.match(QueueOutboxEntity._id)) return QueueOutboxEntity._id; + else if (item.match(QueueOutboxEntity._exchange)) return QueueOutboxEntity._exchange; + else if (item.match(QueueOutboxEntity._tenantId)) return QueueOutboxEntity._tenantId; + else if (item.match(QueueOutboxEntity._route)) return QueueOutboxEntity._route; + else if (item.match(QueueOutboxEntity._message)) return QueueOutboxEntity._message; + else if (item.match(QueueOutboxEntity._messageId)) return QueueOutboxEntity._messageId; + else if (item.match(QueueOutboxEntity._createdAt)) return QueueOutboxEntity._createdAt; + else if (item.match(QueueOutboxEntity._isActive)) return QueueOutboxEntity._isActive; + else if (item.match(QueueOutboxEntity._notifyStatus)) return QueueOutboxEntity._notifyStatus; + else if (item.match(QueueOutboxEntity._retryCount)) return QueueOutboxEntity._retryCount; + else if (item.match(QueueOutboxEntity._publishedAt)) return QueueOutboxEntity._publishedAt; + else if (item.match(QueueOutboxEntity._confirmedAt)) return QueueOutboxEntity._confirmedAt; + else if (item.match(QueueOutboxEntity._createdAt)) return QueueOutboxEntity._createdAt; + else if (item.match(QueueOutboxEntity._updatedAt)) return QueueOutboxEntity._updatedAt; + else return null; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/descriptiontemplate/DescriptionTemplateServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/descriptiontemplate/DescriptionTemplateServiceImpl.java index 8a55703a6..3d0a88588 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/descriptiontemplate/DescriptionTemplateServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/descriptiontemplate/DescriptionTemplateServiceImpl.java @@ -6,15 +6,21 @@ import eu.eudat.authorization.Permission; import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.XmlHandlingService; import eu.eudat.commons.enums.*; +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.commons.scope.tenant.TenantScope; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.types.descriptiontemplate.*; import eu.eudat.commons.types.descriptiontemplate.fielddata.BaseFieldDataEntity; import eu.eudat.commons.types.descriptiontemplate.importexport.*; +import eu.eudat.commons.types.notification.*; +import eu.eudat.configurations.notification.NotificationProperties; import eu.eudat.convention.ConventionService; import eu.eudat.data.DescriptionTemplateEntity; import eu.eudat.data.UserDescriptionTemplateEntity; import eu.eudat.data.UserEntity; import eu.eudat.errorcode.ErrorThesaurusProperties; +import eu.eudat.integrationevent.outbox.notification.NotificationIntegrationEvent; +import eu.eudat.integrationevent.outbox.notification.NotificationIntegrationEventHandler; import eu.eudat.model.DescriptionTemplate; import eu.eudat.model.UserContactInfo; import eu.eudat.model.builder.DescriptionTemplateBuilder; @@ -34,8 +40,6 @@ import eu.eudat.query.UserContactInfoQuery; import eu.eudat.query.UserDescriptionTemplateQuery; import eu.eudat.service.fielddatahelper.FieldDataHelperService; import eu.eudat.service.fielddatahelper.FieldDataHelperServiceProvider; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.mail.SimpleMail; import eu.eudat.service.responseutils.ResponseUtilsService; import eu.eudat.service.storage.StorageFileService; import gr.cite.commons.web.authz.service.AuthorizationService; @@ -67,10 +71,7 @@ import org.xml.sax.SAXException; import javax.management.InvalidApplicationException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.ArrayList; @@ -100,11 +101,13 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic private final QueryFactory queryFactory; private final ErrorThesaurusProperties errors; private final ValidationService validationService; - private final MailService mailService; + private final TenantScope tenantScope; private final Environment environment; private final ResponseUtilsService responseUtilsService; private final StorageFileService storageFileService; private final JsonHandlingService jsonHandlingService; + private final NotificationIntegrationEventHandler eventHandler; + private final NotificationProperties notificationProperties; @Autowired public DescriptionTemplateServiceImpl( @@ -115,7 +118,7 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic ConventionService conventionService, MessageSource messageSource, XmlHandlingService xmlHandlingService, - FieldDataHelperServiceProvider fieldDataHelperServiceProvider, QueryFactory queryFactory, ErrorThesaurusProperties errors, ValidationService validationService, MailService mailService, Environment environment, ResponseUtilsService responseUtilsService, StorageFileService storageFileService, JsonHandlingService jsonHandlingService) { + FieldDataHelperServiceProvider fieldDataHelperServiceProvider, QueryFactory queryFactory, ErrorThesaurusProperties errors, ValidationService validationService, TenantScope tenantScope, Environment environment, ResponseUtilsService responseUtilsService, StorageFileService storageFileService, JsonHandlingService jsonHandlingService, NotificationIntegrationEventHandler eventHandler, NotificationProperties notificationProperties) { this.entityManager = entityManager; this.userScope = userScope; this.authorizationService = authorizationService; @@ -128,11 +131,13 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic this.queryFactory = queryFactory; this.errors = errors; this.validationService = validationService; - this.mailService = mailService; + this.tenantScope = tenantScope; this.environment = environment; this.responseUtilsService = responseUtilsService; this.storageFileService = storageFileService; this.jsonHandlingService = jsonHandlingService; + this.eventHandler = eventHandler; + this.notificationProperties = notificationProperties; } //region Persist @@ -204,26 +209,32 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic this.deleterFactory.deleter(UserDescriptionTemplateDeleter.class).delete(toDelete); } - private void sendJoinMail(UserDescriptionTemplateEntity userDatasetProfile) { - SimpleMail mail = new SimpleMail(); + private void sendJoinMail(UserDescriptionTemplateEntity userDatasetProfile) throws InvalidApplicationException { + NotificationIntegrationEvent event = new NotificationIntegrationEvent(); + event.setTenant(tenantScope.getTenant()); + event.setUserId(userScope.getUserIdSafe()); + UserEntity user = this.entityManager.find(UserEntity.class, userDatasetProfile.getUserId()); DescriptionTemplateEntity descriptionTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).isActive(IsActive.Active).ids(userDatasetProfile.getDescriptionTemplateId()).first(); - mail.setSubject(environment.getProperty("admin.mail.subject").replace( "{templateName}", descriptionTemplate.getLabel())); - String content = this.mailService.getMailTemplateContent(environment.getProperty("email.dataset.template")); - content = content.replace("{recipient}", user.getName()); - content = content.replace("{templateName}", descriptionTemplate.getLabel()); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - content = content.replace("{templateID}", descriptionTemplate.getId().toString()); - mail.setContent(content); UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); - mail.setTo(query.first().getValue()); - try { - this.mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } + + List contactPairs = new ArrayList<>(); + contactPairs.add(new ContactPair(ContactInfoType.Email, query.first().getValue())); + NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); + event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); + event.setContactTypeHint(NotificationContactType.EMAIL); + event.setNotificationType(UUID.fromString(notificationProperties.getTemplate())); + NotificationFieldData data = new NotificationFieldData(); + List fieldInfoList = new ArrayList<>(); + fieldInfoList.add(new FieldInfo("{recipient}", DataType.String, user.getName())); + fieldInfoList.add(new FieldInfo("{templateName}", DataType.String, descriptionTemplate.getLabel())); + fieldInfoList.add(new FieldInfo("{host}", DataType.String, this.environment.getProperty("dmp.domain"))); + fieldInfoList.add(new FieldInfo("{templateID}", DataType.String, descriptionTemplate.getId().toString())); + data.setFields(fieldInfoList); + event.setData(jsonHandlingService.toJsonSafe(data)); + eventHandler.handle(event); } private void addOwner(DescriptionTemplateEntity descriptionTemplateEntity) throws InvalidApplicationException { diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/KeycloakRole.java b/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/KeycloakRole.java index ced1de75b..bb509ed57 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/KeycloakRole.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/KeycloakRole.java @@ -2,6 +2,6 @@ package eu.eudat.service.keycloak; public enum KeycloakRole { - Admin, DatasetTemplateEditor, Manager, User + Admin, DescriptionTemplateEditor, Manager, User } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/MyKeycloakAdminRestApi.java b/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/MyKeycloakAdminRestApi.java index 179bdf64a..744e0a06a 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/MyKeycloakAdminRestApi.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/keycloak/MyKeycloakAdminRestApi.java @@ -24,9 +24,8 @@ public class MyKeycloakAdminRestApi { @Autowired public MyKeycloakAdminRestApi(KeycloakClientConfiguration configuration) { this.configuration = configuration; - try (Keycloak client = this.initClient()) { - this.realm = client.realm(configuration.getProperties().getRealm()); - } + Keycloak client = this.initClient(); + this.realm = client.realm(configuration.getProperties().getRealm()); logger.info("Custom Keycloak client initialized. Keycloak serving from {}", configuration.getProperties().getServerUrl().replace("/auth", "").replaceAll("https?://", "")); } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockService.java b/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockService.java index 48d2591a6..eadb08c56 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockService.java @@ -2,7 +2,6 @@ package eu.eudat.service.lock; import eu.eudat.model.Lock; import eu.eudat.model.persist.LockPersist; -import eu.eudat.query.lookup.LockLookup; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyNotFoundException; @@ -16,9 +15,9 @@ public interface LockService { Lock persist(LockPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException; - boolean isLocked(LockLookup lookup) throws InvalidApplicationException; + boolean isLocked(UUID target) throws InvalidApplicationException; - void unlock(LockLookup lookup) throws InvalidApplicationException; + void unlock(UUID target) throws InvalidApplicationException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java index 8d4327940..db83d6bad 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java @@ -107,35 +107,32 @@ public class LockServiceImpl implements LockService { return this.builderFactory.builder(LockBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, Lock._id), data); } - public boolean isLocked(LockLookup lookup) throws InvalidApplicationException { - if (lookup !=null && lookup.getTargetIds() != null && lookup.getTargetIds().size() > 0){ - LockQuery query = this.queryFactory.query(LockQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).targetIds(lookup.getTargetIds()); - if (query.count() == 1) { - LockEntity lock = query.firstAs(lookup.getProject()); - if (lock.getLockedBy().equals(this.userScope.getUserId())) { - lock.setTouchedAt(Instant.now()); - this.entityManager.merge(lock); - this.entityManager.flush(); - return false; - } - return this.forceUnlock(lookup) > 0; - } else if (query.count() > 1) { - this.forceUnlock(lookup); - return this.isLocked(lookup); + public boolean isLocked(UUID target) throws InvalidApplicationException { + LockQuery query = this.queryFactory.query(LockQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).targetIds(target); + if (query.count() == 1) { + LockEntity lock = query.first(); + if (lock.getLockedBy().equals(this.userScope.getUserId())) { + lock.setTouchedAt(Instant.now()); + this.entityManager.merge(lock); + this.entityManager.flush(); + return false; } - return false; - } else{ - throw new InvalidApplicationException("Wrong LockLookup"); + return this.forceUnlock(target) > 0; + } else if (query.count() > 1) { + this.forceUnlock(target); + return this.isLocked(target); } + return false; + } - private Long forceUnlock(LockLookup lookup) throws InvalidApplicationException { + private Long forceUnlock(UUID target) throws InvalidApplicationException { - LockQuery query = this.queryFactory.query(LockQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).targetIds(lookup.getTargetIds()); + LockQuery query = this.queryFactory.query(LockQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).targetIds(target); Long availableLocks = query.count(); long deletedLocks = 0L; if (availableLocks > 0) { - List locks = query.collectAs(lookup.getProject()); + List locks = query.collect(); for (LockEntity lock : locks) { if (new Date().getTime() - Date.from(lock.getTouchedAt()).getTime() > 120000) { this.deleteAndSave(lock.getId()); @@ -155,17 +152,17 @@ public class LockServiceImpl implements LockService { return availableLocks - deletedLocks; } - public void unlock(LockLookup lookup) throws InvalidApplicationException { + public void unlock(UUID target) throws InvalidApplicationException { - LockQuery query = this.queryFactory.query(LockQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).targetIds(lookup.getTargetIds()); + LockQuery query = this.queryFactory.query(LockQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).targetIds(target); if (query.count() == 1) { - LockEntity lock = query.firstAs(lookup.getProject()); + LockEntity lock = query.first(); if (!lock.getLockedBy().equals(this.userScope.getUserId())) { throw new InvalidApplicationException("Only the user who created that lock can delete it"); } this.deleteAndSave(lock.getId()); } else if (query.count() > 1) { - List locks = query.collectAs(lookup.getProject()); + List locks = query.collect(); locks.stream().filter(lock -> lock.getLockedBy().equals(this.userScope.getUserIdSafe())).forEach(lock -> { try { this.deleteAndSave(lock.getId()); diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/mail/MailService.java b/dmp-backend/core/src/main/java/eu/eudat/service/mail/MailService.java deleted file mode 100644 index aa6c087a3..000000000 --- a/dmp-backend/core/src/main/java/eu/eudat/service/mail/MailService.java +++ /dev/null @@ -1,12 +0,0 @@ -package eu.eudat.service.mail; - -import jakarta.mail.MessagingException; - - -public interface MailService { - void sendSimpleMail(SimpleMail mail) throws MessagingException; - - String getMailTemplateContent(String resourceTemplate); - - String getMailTemplateSubject(); -} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/mail/MailServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/mail/MailServiceImpl.java deleted file mode 100644 index db652f312..000000000 --- a/dmp-backend/core/src/main/java/eu/eudat/service/mail/MailServiceImpl.java +++ /dev/null @@ -1,140 +0,0 @@ -package eu.eudat.service.mail; - -import jakarta.mail.BodyPart; -import jakarta.mail.Message; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeBodyPart; -import jakarta.mail.internet.MimeMessage; -import jakarta.mail.internet.MimeMultipart; -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.core.env.Environment; -import org.springframework.core.io.Resource; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - - -@Service("mailService") -public class MailServiceImpl implements MailService { - private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class); - - private Environment env; - - private JavaMailSender emailSender; - - private ApplicationContext applicationContext; - - @Autowired - public MailServiceImpl(Environment env, JavaMailSender emailSender, ApplicationContext applicationContext) { - this.env = env; - this.emailSender = emailSender; - this.applicationContext = applicationContext; - } - - @Override - public void sendSimpleMail(SimpleMail mail) throws MessagingException { - List imageSources = parseImages(mail.getContent()); - List cids = new ArrayList<>(); - if (!imageSources.isEmpty()) { - for (int i = 0; i < imageSources.size(); i++) { - cids.add(UUID.randomUUID().toString()); - } - mail.setContent(replaceImageSources(mail.getContent(), cids)); - } - MimeMultipart content = new MimeMultipart("related"); - BodyPart messageBodyPart = new MimeBodyPart(); - messageBodyPart.setContent(mail.getContent(), "text/html; charset=UTF-8"); - content.addBodyPart(messageBodyPart); - if (!imageSources.isEmpty()) { - for (int i =0; i < imageSources.size(); i++) { - MimeBodyPart imagePart = new MimeBodyPart(); - try { - imagePart.attachFile(applicationContext.getResource(imageSources.get(i)).getFile()); - imagePart.setContentID("<" + cids.get(i) + ">"); - imagePart.setDisposition(MimeBodyPart.INLINE); - content.addBodyPart(imagePart); - } catch (IOException | MessagingException e) { - logger.error(e.getMessage(), e); - } - } - } - MimeMessage message = this.emailSender.createMimeMessage(); - message.setSubject(mail.getSubject()); - message.setContent(content); - message.addRecipients(Message.RecipientType.TO, mail.getTo()); - message.setFrom(env.getProperty("mail.from")); - this.emailSender.send(message); - } - - public Environment getEnv() { - return env; - } - - @Override - public String getMailTemplateContent(String resourceTemplate) { - Resource resource = applicationContext.getResource(resourceTemplate); - try { - InputStream inputStream = resource.getInputStream(); - StringWriter writer = new StringWriter(); - IOUtils.copy(inputStream, writer, "UTF-8"); - inputStream.close(); - return writer.toString(); - } catch (IOException e) { - logger.error(e.getMessage(), e); - } - return ""; - } - - @Override - public String getMailTemplateSubject() { - return env.getProperty("mail.subject"); - } - - private List parseImages(String content) { - List imagePaths = new ArrayList<>(); - - int lastIndex = 0; - - while (lastIndex != -1) { - lastIndex = content.indexOf("img src=\"", lastIndex); - - if (lastIndex != -1) { - String imagePath = content.substring(lastIndex + 9, content.indexOf("\"", lastIndex + 9)); - if (!imagePath.contains("data:image/png;base64")) { - imagePaths.add(imagePath); - } - lastIndex++; - } - } - - return imagePaths; - } - - private String replaceImageSources(String content, List cids) { - - int lastIndex = 0; - int cidIndex = 0; - - while (lastIndex != -1) { - lastIndex = content.indexOf("img src=\"", lastIndex); - - if (lastIndex != -1) { - content = content.replace(content.substring(lastIndex + 9, content.indexOf("\"", lastIndex + 9)), "cid:" + cids.get(cidIndex)); - lastIndex ++; - cidIndex ++; - } - } - - return content; - } -} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/mail/SimpleMail.java b/dmp-backend/core/src/main/java/eu/eudat/service/mail/SimpleMail.java deleted file mode 100644 index 06812a579..000000000 --- a/dmp-backend/core/src/main/java/eu/eudat/service/mail/SimpleMail.java +++ /dev/null @@ -1,51 +0,0 @@ -package eu.eudat.service.mail; - - -public class SimpleMail { - private String from; - private String to; - private String subject; - private String content; - - public SimpleMail() { - } - - public SimpleMail(String from, String to, String subject, String content) { - this.from = from; - this.to = to; - this.subject = subject; - this.content = content; - } - - public String getFrom() { - return from; - } - - public void setFrom(String from) { - this.from = from; - } - - public String getTo() { - return to; - } - - public void setTo(String to) { - this.to = to; - } - - public String getSubject() { - return subject; - } - - public void setSubject(String subject) { - this.subject = subject; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } -} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/notification/NotificationService.java b/dmp-backend/core/src/main/java/eu/eudat/service/notification/NotificationService.java new file mode 100644 index 000000000..664ab13cf --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/notification/NotificationService.java @@ -0,0 +1,16 @@ +package eu.eudat.service.notification; + +import eu.eudat.model.persist.notification.NotificationPersist; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.FieldSet; + +import javax.management.InvalidApplicationException; + +public interface NotificationService{ + + void persist(NotificationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException; + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/notification/NotificationServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/notification/NotificationServiceImpl.java new file mode 100644 index 000000000..818e5a1d0 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/notification/NotificationServiceImpl.java @@ -0,0 +1,106 @@ +package eu.eudat.service.notification; + +import eu.eudat.authorization.Permission; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.convention.ConventionService; +import eu.eudat.data.TenantEntityManager; +import eu.eudat.data.notification.NotificationEntity; +import eu.eudat.errorcode.ErrorThesaurusProperties; +import eu.eudat.model.persist.notification.NotificationPersist; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.deleter.DeleterFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.web.context.annotation.RequestScope; + +import javax.management.InvalidApplicationException; +import java.time.Instant; +import java.util.UUID; + +@Service +@RequestScope +public class NotificationServiceImpl implements NotificationService { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotificationServiceImpl.class)); + private final TenantEntityManager entityManager; + private final AuthorizationService authorizationService; + private final DeleterFactory deleterFactory; + private final BuilderFactory builderFactory; + private final ConventionService conventionService; + private final ErrorThesaurusProperties errors; + private final MessageSource messageSource; + + @Autowired + public NotificationServiceImpl( + TenantEntityManager entityManager, + AuthorizationService authorizationService, + DeleterFactory deleterFactory, + BuilderFactory builderFactory, + ConventionService conventionService, + ErrorThesaurusProperties errors, + MessageSource messageSource + ) { + this.entityManager = entityManager; + this.authorizationService = authorizationService; + this.deleterFactory = deleterFactory; + this.builderFactory = builderFactory; + this.conventionService = conventionService; + this.errors = errors; + this.messageSource = messageSource; + } + + @Override + public void persist(NotificationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException { + logger.debug(new MapLogEntry("persisting notification").And("model", model).And("fields", fields)); + + //this.authorizationService.authorizeForce(Permission.AuthenticatedRole); + + Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); + + NotificationEntity data = null; + if (isUpdate) { + data = this.entityManager.find(NotificationEntity.class, model.getId()); + if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), NotificationEntity.class.getSimpleName()}, LocaleContextHolder.getLocale())); + if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + } else { + data = new NotificationEntity(); + data.setId(UUID.randomUUID()); + data.setIsActive(IsActive.Active); + data.setCreatedAt(Instant.now()); + } + + data.setNotifiedAt(model.getNotifiedAt()); + data.setContactHint(model.getContactHint()); + data.setContactTypeHint(model.getContactTypeHint()); + data.setType(model.getType()); + data.setUserId(model.getUserId()); + data.setData(model.getData()); + data.setNotifyState(model.getNotifyState()); + data.setNotifiedWith(model.getNotifiedWith()); + data.setRetryCount(model.getRetryCount()); + data.setTrackingState(model.getTrackingState()); + data.setTrackingProcess(model.getTrackingProcess()); + data.setTrackingData(model.getTrackingData()); +// data.setProvenanceRef(model.getProvenanceRef()); + data.setUpdatedAt(Instant.now()); + + if (isUpdate) this.entityManager.merge(data); + else this.entityManager.persist(data); + + this.entityManager.flush(); + + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/user/UserServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/user/UserServiceImpl.java index 08313fa4f..313eb356f 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/user/UserServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/user/UserServiceImpl.java @@ -10,6 +10,7 @@ import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.types.user.AdditionalInfoEntity; import eu.eudat.convention.ConventionService; +import eu.eudat.data.UserCredentialEntity; import eu.eudat.data.UserEntity; import eu.eudat.data.UserRoleEntity; import eu.eudat.errorcode.ErrorThesaurusProperties; @@ -23,6 +24,7 @@ import eu.eudat.model.deleter.UserRoleDeleter; import eu.eudat.model.persist.UserAdditionalInfoPersist; import eu.eudat.model.persist.UserPersist; import eu.eudat.model.persist.UserRolePatchPersist; +import eu.eudat.query.UserCredentialQuery; import eu.eudat.query.UserQuery; import eu.eudat.query.UserRoleQuery; import eu.eudat.service.keycloak.KeycloakRole; @@ -206,6 +208,14 @@ public class UserServiceImpl implements UserService { if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), User.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + List userCredentials = this.queryFactory.query(UserCredentialQuery.class).userIds(data.getId()).collect(); + if (userCredentials.isEmpty()) + throw new MyApplicationException("Currently cannot update roles for this user"); + if (userCredentials.getFirst().getExternalId() == null) + throw new MyApplicationException("Currently cannot update roles for this user"); + UUID subjectId = UUID.fromString(userCredentials.getFirst().getExternalId()); + + List existingItems = this.queryFactory.query(UserRoleQuery.class).userIds(data.getId()).collect(); List foundIds = new ArrayList<>(); for (String roleName : model.getRoles().stream().filter(x-> x != null && !x.isBlank()).distinct().toList()) { @@ -217,7 +227,7 @@ public class UserServiceImpl implements UserService { item.setRole(roleName); item.setCreatedAt(Instant.now()); this.entityManager.persist(item); - this.keycloakService.addUserToGroup(data.getId(), KeycloakRole.valueOf(roleName)); + this.keycloakService.addUserToGroup(subjectId, KeycloakRole.valueOf(roleName)); } foundIds.add(item.getId()); } @@ -225,7 +235,7 @@ public class UserServiceImpl implements UserService { this.entityManager.flush(); List toDelete = existingItems.stream().filter(x-> foundIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList()); - toDelete.forEach(x -> this.keycloakService.removeUserFromGroup(data.getId(), KeycloakRole.valueOf(x.getRole()))); + toDelete.forEach(x -> this.keycloakService.removeUserFromGroup(subjectId, KeycloakRole.valueOf(x.getRole()))); this.deleterFactory.deleter(UserRoleDeleter.class).deleteAndSave(toDelete); this.entityManager.flush(); diff --git a/dmp-backend/notification-service/notification-web/src/main/resources/config/notification.yml b/dmp-backend/notification-service/notification-web/src/main/resources/config/notification.yml index a30eac93a..2fb7dc98a 100644 --- a/dmp-backend/notification-service/notification-web/src/main/resources/config/notification.yml +++ b/dmp-backend/notification-service/notification-web/src/main/resources/config/notification.yml @@ -52,7 +52,7 @@ notification: body-path: classpath:notification_templates/Confirmation/Email/body.{language}.html body-field-options: - mandatory: [ ] + mandatory: [ "{host}", "{confirmationToken}" ] optional: - key: "{expiration_time}" value: -- @@ -72,7 +72,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/DataManagementPlan/Email/body.{language}.html body-field-options: - mandatory: [ "{dmpname}", "{dmprole}" ] + mandatory: [ "{dmpname}", "{dmprole}", "{host}", "{invitationID}" ] optional: - key: "{recipient}" value: @@ -94,7 +94,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/Finalised/Email/body.{language}.html body-field-options: - mandatory: [ "{reasonName}", "{name}" ] + mandatory: [ "{reasonName}", "{name}", "{host}", "{path}", "{id}" ] optional: - key: "{recipient}" value: @@ -116,7 +116,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/MergeConfirmation/Email/body.{language}.html body-field-options: - mandatory: [ "{userName}", "{host}" ] + mandatory: [ "{userName}", "{host}", "{confirmationToken}" ] optional: - key: "{expiration_time}" value: --- @@ -138,7 +138,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/Modified/Email/body.{language}.html body-field-options: - mandatory: [ "{reasonName}", "{name}" ] + mandatory: [ "{reasonName}", "{name}", "{host}", "{path}", "{id}" ] optional: - key: "{recipient}" value: @@ -160,7 +160,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/ModifiedFinalised/Email/body.{language}.html body-field-options: - mandatory: [ "{reasonName}", "{name}" ] + mandatory: [ "{reasonName}", "{name}", "{host}", "{path}", "{id}" ] optional: - key: "{recipient}" value: @@ -182,7 +182,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/Publish/Email/body.{language}.html body-field-options: - mandatory: [ "{reasonName}", "{name}" ] + mandatory: [ "{reasonName}", "{name}", "{host}", "{path}", "{id}" ] optional: - key: "{recipient}" value: @@ -204,7 +204,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/Template/Email/body.{language}.html body-field-options: - mandatory: [ "{templateName}" ] + mandatory: [ "{templateName}", "{host}", "{templateID}" ] optional: - key: "{recipient}" value: @@ -221,7 +221,7 @@ notification: key: C9BC3F16-057E-4BBA-8A5F-36BD835E5604 subject-path: classpath:notification_templates/UnlinkConfirmation/Email/subject.{language}.txt subject-field-options: - mandatory: [ ] + mandatory: ["{host}", "{confirmationToken}"] optional: [ ] body-path: classpath:notification_templates/UnlinkConfirmation/Email/body.{language}.html body-field-options: diff --git a/dmp-backend/notification-service/notification-web/target/classes/config/notification.yml b/dmp-backend/notification-service/notification-web/target/classes/config/notification.yml index a30eac93a..1e7a8897f 100644 --- a/dmp-backend/notification-service/notification-web/target/classes/config/notification.yml +++ b/dmp-backend/notification-service/notification-web/target/classes/config/notification.yml @@ -72,7 +72,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/DataManagementPlan/Email/body.{language}.html body-field-options: - mandatory: [ "{dmpname}", "{dmprole}" ] + mandatory: [ "{dmpname}", "{dmprole}", "{host}", "{invitationID}" ] optional: - key: "{recipient}" value: @@ -116,7 +116,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/MergeConfirmation/Email/body.{language}.html body-field-options: - mandatory: [ "{userName}", "{host}" ] + mandatory: [ "{userName}", "{host}", "{confirmationToken}" ] optional: - key: "{expiration_time}" value: --- @@ -204,7 +204,7 @@ notification: optional: [ ] body-path: classpath:notification_templates/Template/Email/body.{language}.html body-field-options: - mandatory: [ "{templateName}" ] + mandatory: [ "{templateName}", "{host}", "{templateID}" ] optional: - key: "{recipient}" value: @@ -221,7 +221,7 @@ notification: key: C9BC3F16-057E-4BBA-8A5F-36BD835E5604 subject-path: classpath:notification_templates/UnlinkConfirmation/Email/subject.{language}.txt subject-field-options: - mandatory: [ ] + mandatory: ["{host}", "{confirmationToken}"] optional: [ ] body-path: classpath:notification_templates/UnlinkConfirmation/Email/body.{language}.html body-field-options: diff --git a/dmp-backend/pom.xml b/dmp-backend/pom.xml index 8861a1a65..8660d01cb 100644 --- a/dmp-backend/pom.xml +++ b/dmp-backend/pom.xml @@ -355,6 +355,23 @@ 1.0.0 + + gr.cite + queue-inbox + 1.0.0 + + + gr.cite + queue-outbox + 1.0.0 + + + + gr.cite + rabbitmq-core + 1.0.0 + + diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/LockController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/LockController.java index 67994b553..7049d1d37 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/LockController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/LockController.java @@ -2,6 +2,7 @@ package eu.eudat.controllers.v2; import eu.eudat.audit.AuditableAction; import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.authorization.OwnedResource; import eu.eudat.authorization.Permission; import eu.eudat.data.LockEntity; import eu.eudat.model.Lock; @@ -65,6 +66,7 @@ public class LockController { private final MessageSource messageSource; private final AuthorizationService authorizationService; + private final AuthorizationService authService; @Autowired public LockController(BuilderFactory builderFactory, @@ -73,7 +75,7 @@ public class LockController { CensorFactory censorFactory, QueryFactory queryFactory, MessageSource messageSource, - AuthorizationService authorizationService) { + AuthorizationService authorizationService, AuthorizationService authService) { this.builderFactory = builderFactory; this.auditService = auditService; this.lockService = lockService; @@ -81,6 +83,7 @@ public class LockController { this.queryFactory = queryFactory; this.messageSource = messageSource; this.authorizationService = authorizationService; + this.authService = authService; } @PostMapping("query") @@ -154,20 +157,19 @@ public class LockController { } @Transactional - @PostMapping("target/status/{id}") - public @ResponseBody ResponseEntity> getLocked(@RequestBody LockLookup lookup) throws Exception { - this.authorizationService.authorizeForce(Permission.AuthenticatedRole); + @GetMapping("target/status/{id}") + public @ResponseBody Boolean getLocked(@PathVariable("id") UUID targetId) throws Exception { + this.authService.authorizeAtLeastOneForce(targetId != null ? List.of(new OwnedResource(targetId)) : null, Permission.BrowseLock); - boolean locked = this.lockService.isLocked(lookup); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("locked").payload(locked)); + return this.lockService.isLocked(targetId); } @Transactional - @PostMapping("target/unlock/{id}") - public @ResponseBody ResponseEntity> unlock(@RequestBody LockLookup lookup) throws Exception { - this.authorizationService.authorizeForce(Permission.AuthenticatedRole); + @DeleteMapping("target/unlock/{id}") + public @ResponseBody ResponseEntity> unlock(@PathVariable("id") UUID targetId) throws Exception { + this.authService.authorizeAtLeastOneForce(targetId != null ? List.of(new OwnedResource(targetId)) : null, Permission.BrowseLock); - this.lockService.unlock(lookup); + this.lockService.unlock(targetId); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created").payload("Lock Removed")); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ContactEmailManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ContactEmailManager.java index d6f271d55..239ed6d38 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ContactEmailManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ContactEmailManager.java @@ -8,7 +8,6 @@ import eu.eudat.models.data.ContactEmail.ContactEmailModel; import eu.eudat.models.data.ContactEmail.PublicContactEmailModel; import eu.eudat.query.UserContactInfoQuery; import eu.eudat.query.UserQuery; -import eu.eudat.service.mail.SimpleMail; import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.QueryFactory; import org.springframework.core.env.Environment; @@ -35,28 +34,28 @@ public class ContactEmailManager { } public void sendContactEmail(ContactEmailModel contactEmailModel) throws MessagingException, InvalidApplicationException { - UserEntity user = this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserId()).first(); - SimpleMail mail = new SimpleMail(); - UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); - query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); - String enrichedMail = contactEmailModel.getDescription() + "\n\n" + "Send by user: " + query.first().getValue() ; - mail.setSubject(contactEmailModel.getSubject()); - mail.setTo(environment.getProperty("contact_email.mail")); - mail.setContent(enrichedMail); - mail.setFrom(query.first().getValue()); - - apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); +// UserEntity user = this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserId()).first(); +// SimpleMail mail = new SimpleMail(); +// UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); +// query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); +// String enrichedMail = contactEmailModel.getDescription() + "\n\n" + "Send by user: " + query.first().getValue() ; +// mail.setSubject(contactEmailModel.getSubject()); +// mail.setTo(environment.getProperty("contact_email.mail")); +// mail.setContent(enrichedMail); +// mail.setFrom(query.first().getValue()); +// +// apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); } public void sendContactEmailNoAuth(PublicContactEmailModel contactEmailModel) throws MessagingException { - SimpleMail mail = new SimpleMail(); - String enrichedMail = contactEmailModel.getMessage() + "\n\n" + "Send by user: " + contactEmailModel.getEmail() ; - mail.setSubject(contactEmailModel.getAffiliation()); - mail.setTo(environment.getProperty("contact_email.mail")); - mail.setContent(enrichedMail); - mail.setFrom(contactEmailModel.getEmail()); - - apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); +// SimpleMail mail = new SimpleMail(); +// String enrichedMail = contactEmailModel.getMessage() + "\n\n" + "Send by user: " + contactEmailModel.getEmail() ; +// mail.setSubject(contactEmailModel.getAffiliation()); +// mail.setTo(environment.getProperty("contact_email.mail")); +// mail.setContent(enrichedMail); +// mail.setFrom(contactEmailModel.getEmail()); +// +// apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); } public void emailValidation(ContactEmailModel contactEmailModel) throws Exception { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java index b33baca6e..28bb63842 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java @@ -75,12 +75,7 @@ public class EmailConfirmationManager { // if (user.getEmail() != null) //TODO // throw new HasConfirmedEmailException("User already has confirmed his Email."); - apiContext.getUtilitiesService().getConfirmationEmailService().createConfirmationEmail( - databaseRepository.getLoginConfirmationEmailDao(), - apiContext.getUtilitiesService().getMailService(), - email, - this.userScope.getUserId() - ); + apiContext.getUtilitiesService().getConfirmationEmailService().sentConfirmationEmail(databaseRepository.getLoginConfirmationEmailDao(), email, user); } private void mergeNewUserToOld(UserEntity newUser, UserEntity oldUser) throws InvalidApplicationException { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/InvitationsManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/InvitationsManager.java index 942145cb8..64204938e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/InvitationsManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/InvitationsManager.java @@ -9,6 +9,9 @@ import eu.eudat.exceptions.security.UnauthorisedException; import eu.eudat.logic.services.ApiContext; import eu.eudat.model.User; import eu.eudat.models.data.invitation.Invitation; +import eu.eudat.query.DmpQuery; +import eu.eudat.query.UserQuery; +import gr.cite.tools.data.query.QueryFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -25,12 +28,14 @@ public class InvitationsManager { private ApiContext apiContext; private DataManagementPlanManager dataManagementPlanManager; private final UserScope userScope; + private final QueryFactory queryFactory; @Autowired - public InvitationsManager(ApiContext apiContext, DataManagementPlanManager dataManagementPlanManager, UserScope userScope) { + public InvitationsManager(ApiContext apiContext, DataManagementPlanManager dataManagementPlanManager, UserScope userScope, QueryFactory queryFactory) { this.apiContext = apiContext; this.dataManagementPlanManager = dataManagementPlanManager; this.userScope = userScope; + this.queryFactory = queryFactory; } public void inviteUsers(Invitation invitation) throws Exception { @@ -63,9 +68,19 @@ public class InvitationsManager { apiContext.getOperationsContext().getDatabaseRepository().getUserAssociationDao().createOrUpdate(userAssociation); }*/ } - DmpEntity dataManagementPlan = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(invitation.getDataManagementPlan()); -// apiContext.getUtilitiesService().getInvitationService().createInvitations(apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao(), apiContext.getUtilitiesService().getMailService(), invitation.getUsers().stream().map(UserInfoInvitationModel::toDataModel).collect(Collectors.toList()), dataManagementPlan, invitation.getRole(), principalUser); - apiContext.getUtilitiesService().getInvitationService().assignToDmp(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao(), userInfoToUserDmp, dataManagementPlan); + DmpQuery dmpQuery = this.queryFactory.query(DmpQuery.class).ids(invitation.getDataManagementPlan()); + if(dmpQuery != null){ +// DmpEntity dataManagementPlan = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(invitation.getDataManagementPlan()); + DmpEntity dmpEntity = dmpQuery.first(); + UserQuery userQuery = this.queryFactory.query(UserQuery.class).ids(invitation.getUsers().stream().map(user -> user.getId()).collect(Collectors.toList())); + if (userQuery != null){ + List userEntities = userQuery.collect(); +// apiContext.getUtilitiesService().getInvitationService().createInvitations(apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao(), invitation.getUsers().stream().map(UserInfoInvitationModel::toDataModel).collect(Collectors.toList()), dmpEntity, invitation.getRole(), principalUser); + apiContext.getUtilitiesService().getInvitationService().createInvitations(apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao(), userEntities, dmpEntity, invitation.getRole(), principalUser); + apiContext.getUtilitiesService().getInvitationService().assignToDmp(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao(), userInfoToUserDmp, dmpEntity); + } + } + } public List getUsers() throws InstantiationException, IllegalAccessException, InvalidApplicationException { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MergeEmailConfirmationManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MergeEmailConfirmationManager.java index 5c38f7978..6f813a5e4 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MergeEmailConfirmationManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MergeEmailConfirmationManager.java @@ -10,7 +10,10 @@ import eu.eudat.exceptions.emailconfirmation.TokenExpiredException; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.operations.DatabaseRepository; +import eu.eudat.model.UserContactInfo; +import eu.eudat.query.UserContactInfoQuery; import eu.eudat.query.UserQuery; +import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.QueryFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,18 +73,18 @@ public class MergeEmailConfirmationManager { return userToBeMergedEmail; } - public void sendConfirmationEmail(String email, UUID userId, Integer provider) throws HasConfirmedEmailException, InvalidApplicationException { + public void sendMergeConfirmationEmail(String email, Integer provider) throws HasConfirmedEmailException, InvalidApplicationException { UserEntity user = this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserId()).first(); -//TODO -// if (user.getEmail() != null && !user.getEmail().equals(email)) { -// apiContext.getUtilitiesService().getConfirmationEmailService().createMergeConfirmationEmail( -// databaseRepository.getLoginConfirmationEmailDao(), -// apiContext.getUtilitiesService().getMailService(), -// email, -// user, -// provider -// ); -// } + UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); + query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); + if (query.first().getValue() != null && !query.first().getValue().equals(email)) { + apiContext.getUtilitiesService().getConfirmationEmailService().sentMergeConfirmationEmail( + databaseRepository.getLoginConfirmationEmailDao(), + email, + user, + provider + ); + } } @Transactional diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/NotificationManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/NotificationManager.java index 85fd36e4f..ca40c9eb6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/NotificationManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/NotificationManager.java @@ -7,8 +7,6 @@ import eu.eudat.commons.enums.old.notification.ActiveStatus; import eu.eudat.commons.enums.old.notification.NotifyState; import eu.eudat.logic.services.ApiContext; import eu.eudat.query.UserQuery; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.mail.SimpleMail; import gr.cite.tools.data.query.QueryFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,14 +25,14 @@ public class NotificationManager { private ApiContext apiContext; private Environment environment; - private MailService mailService; private final QueryFactory queryFactory; @Autowired - public NotificationManager(ApiContext apiContext, Environment environment, MailService mailService, QueryFactory queryFactory) { + public NotificationManager(ApiContext apiContext, Environment environment, +// MailService mailService, + QueryFactory queryFactory) { this.apiContext = apiContext; this.environment = environment; - this.mailService = mailService; this.queryFactory = queryFactory; } @@ -64,20 +62,20 @@ public class NotificationManager { case DMP_MODIFIED: case DATASET_MODIFIED: subjectTemplate = this.environment.getProperty("notification.modified.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.modified.template")); +// contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.modified.template")); break; case DMP_PUBLISH: subjectTemplate = this.environment.getProperty("notification.publish.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.publish.template")); +// contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.publish.template")); break; case DMP_FINALISED: subjectTemplate = this.environment.getProperty("notification.finalised.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.finalised.template")); +// contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.finalised.template")); break; case DMP_MODIFIED_FINALISED: case DATASET_MODIFIED_FINALISED: subjectTemplate = this.environment.getProperty("notification.modifiedFinalised.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.modified_finalised.template")); +// contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.modified_finalised.template")); break; } @@ -95,20 +93,20 @@ public class NotificationManager { } private void sendEmailNotification(Notification notification, UserEntity userInfo, Map data, String subjectTemplate, String contentTemplate) throws IOException { - 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); - notification.setNotifyState(NotifyState.SUCCEEDED); - notification.setUpdatedAt(new Date()); - } catch (MessagingException e) { - notification.setNotifyState(NotifyState.ERROR); - notification.setUpdatedAt(new Date()); - logger.error(e.getMessage(), e); - } +// 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); +// notification.setNotifyState(NotifyState.SUCCEEDED); +// notification.setUpdatedAt(new Date()); +// } catch (MessagingException e) { +// notification.setNotifyState(NotifyState.ERROR); +// notification.setUpdatedAt(new Date()); +// logger.error(e.getMessage(), e); +// } } private String makeSubject(Map data, String subjectTemplate) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/UnlinkEmailConfirmationManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/UnlinkEmailConfirmationManager.java index 37e66cf3b..281390c78 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/UnlinkEmailConfirmationManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/UnlinkEmailConfirmationManager.java @@ -2,7 +2,7 @@ package eu.eudat.logic.managers; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import eu.eudat.data.UserCredentialEntity; +import eu.eudat.commons.scope.user.UserScope; import eu.eudat.data.old.EmailConfirmation; import eu.eudat.data.UserEntity; import eu.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; @@ -32,12 +32,14 @@ public class UnlinkEmailConfirmationManager { private ApiContext apiContext; private DatabaseRepository databaseRepository; private final QueryFactory queryFactory; + private final UserScope userScope; @Autowired - public UnlinkEmailConfirmationManager(ApiContext apiContext, QueryFactory queryFactory) { + public UnlinkEmailConfirmationManager(ApiContext apiContext, QueryFactory queryFactory, UserScope userScope) { this.apiContext = apiContext; this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); this.queryFactory = queryFactory; + this.userScope = userScope; } @Transactional @@ -79,14 +81,13 @@ public class UnlinkEmailConfirmationManager { // } } - public void sendConfirmationEmail(String email, UUID userId, Integer provider) throws InvalidApplicationException { - UserEntity user = this.queryFactory.query(UserQuery.class).ids(userId).first(); + public void sendUnlinkConfirmationEmail(String email, Integer provider) throws InvalidApplicationException { + UserEntity user = this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserId()).first(); UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); if (query.first().getValue() != null && !query.first().getValue().equals(email)) { - apiContext.getUtilitiesService().getConfirmationEmailService().createUnlinkConfirmationEmail( + apiContext.getUtilitiesService().getConfirmationEmailService().sentUnlinkConfirmationEmail( databaseRepository.getLoginConfirmationEmailDao(), - apiContext.getUtilitiesService().getMailService(), email, user, provider diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailService.java index 80ef61a56..0ee9e097c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailService.java @@ -1,24 +1,15 @@ package eu.eudat.logic.services.utilities; import eu.eudat.data.dao.entities.EmailConfirmationDao; -import eu.eudat.data.old.EmailConfirmation; import eu.eudat.data.UserEntity; -import eu.eudat.service.mail.MailService; import javax.management.InvalidApplicationException; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; + public interface ConfirmationEmailService { - public void createConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UUID userId); - - public void createMergeConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UserEntity user, Integer provider) throws InvalidApplicationException; + public void sentConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, String email, UserEntity user) throws InvalidApplicationException; - public void createUnlinkConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UserEntity user, Integer provider) throws InvalidApplicationException; + public void sentUnlinkConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, String email, UserEntity user, Integer provider) throws InvalidApplicationException; - public CompletableFuture sentConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService); - - public CompletableFuture sentMergeConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService, String userName); - - public CompletableFuture sentUnlinkConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService); + public void sentMergeConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, String email, UserEntity user, Integer provider) throws InvalidApplicationException; } \ No newline at end of file diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java index 009b131dd..36a2f1388 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java @@ -1,16 +1,20 @@ package eu.eudat.logic.services.utilities; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.enums.ContactInfoType; +import eu.eudat.commons.enums.notification.NotificationContactType; import eu.eudat.commons.scope.user.UserScope; +import eu.eudat.commons.types.notification.*; +import eu.eudat.configurations.notification.NotificationProperties; import eu.eudat.data.dao.entities.EmailConfirmationDao; import eu.eudat.data.old.EmailConfirmation; import eu.eudat.data.UserEntity; +import eu.eudat.integrationevent.outbox.notification.NotificationIntegrationEvent; +import eu.eudat.integrationevent.outbox.notification.NotificationIntegrationEventHandler; import eu.eudat.model.UserContactInfo; import eu.eudat.query.UserContactInfoQuery; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.mail.SimpleMail; import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.QueryFactory; import org.slf4j.Logger; @@ -19,11 +23,7 @@ import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import javax.management.InvalidApplicationException; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; +import java.util.*; @Service("ConfirmationEmailService") public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { @@ -32,125 +32,24 @@ public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { private Environment environment; private final UserScope userScope; private final QueryFactory queryFactory; + private final JsonHandlingService jsonHandlingService; + private final NotificationIntegrationEventHandler eventHandler; + private final NotificationProperties notificationProperties; - public ConfirmationEmailServiceImpl(/*Logger logger,*/ Environment environment, UserScope userScope, QueryFactory queryFactory) { + + public ConfirmationEmailServiceImpl(/*Logger logger,*/ Environment environment, UserScope userScope, QueryFactory queryFactory, JsonHandlingService jsonHandlingService, NotificationIntegrationEventHandler eventHandler, NotificationProperties notificationProperties) { // this.logger = logger; this.environment = environment; this.userScope = userScope; this.queryFactory = queryFactory; + this.jsonHandlingService = jsonHandlingService; + this.eventHandler = eventHandler; + this.notificationProperties = notificationProperties; } @Override - public void createConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UUID userId) { - EmailConfirmation confirmationEmail = new EmailConfirmation(); - confirmationEmail.setEmail(email); - confirmationEmail.setExpiresAt(Date - .from(new Date() - .toInstant() - .plusSeconds(Long.parseLong(this.environment.getProperty("conf_email.expiration_time_seconds"))) - ) - ); - confirmationEmail.setUserId(userId); - confirmationEmail.setIsConfirmed(false); - confirmationEmail.setToken(UUID.randomUUID()); - confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); - sentConfirmationEmail(confirmationEmail, mailService); - } + public void sentConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, String email, UserEntity user) throws InvalidApplicationException { - @Override - public CompletableFuture sentConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService) { - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("conf_email.subject")); - mail.setContent(createContent(confirmationEmail.getToken(), mailService)); - mail.setTo(confirmationEmail.getEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - private String createContent(UUID confirmationToken, MailService mailService) { - String content = mailService.getMailTemplateContent(this.environment.getProperty("email.confirmation")); - content = content.replace("{confirmationToken}", confirmationToken.toString()); - content = content.replace("{expiration_time}", secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds")))); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - - return content; - } - - @Override - public CompletableFuture sentMergeConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService, String userName) { - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("conf_email.subject")); - mail.setContent(createMergeContent(confirmationEmail.getToken(), mailService, userName)); - mail.setTo(confirmationEmail.getEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - @Override - public CompletableFuture sentUnlinkConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService) { - String email = null; - try { - Map map = new ObjectMapper().readValue(confirmationEmail.getData(), new TypeReference>() {}); - email = (String) map.get("email"); - } - catch (JsonProcessingException e){ - logger.error(e.getMessage(), e); - } - String finalEmail = email; - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("conf_email.subject")); - mail.setContent(createUnlinkContent(confirmationEmail.getToken(), mailService, finalEmail)); - mail.setTo(confirmationEmail.getEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - private String createMergeContent(UUID confirmationToken, MailService mailService, String userName) { - String content = mailService.getMailTemplateContent(this.environment.getProperty("email.merge")); - content = content.replace("{userName}", userName); - content = content.replace("{confirmationToken}", confirmationToken.toString()); - content = content.replace("{expiration_time}", secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds")))); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - - return content; - } - - private String createUnlinkContent(UUID confirmationToken, MailService mailService, String email) { - String content = mailService.getMailTemplateContent(this.environment.getProperty("email.unlink")); - content = content.replace("{confirmationToken}", confirmationToken.toString()); - content = content.replace("{expiration_time}", secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds")))); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - content = content.replace("{email}", email); - - return content; - } - - private String secondsToTime(int seconds) { - int sec = seconds % 60; - int hour = seconds / 60; - int min = hour % 60; - hour = hour / 60; - return (hour + ":" + min + ":" + sec); - } - - @Override - public void createMergeConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, - String email, UserEntity user, Integer provider) throws InvalidApplicationException { EmailConfirmation confirmationEmail = new EmailConfirmation(); confirmationEmail.setEmail(email); confirmationEmail.setExpiresAt(Date @@ -160,24 +59,30 @@ public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { ) ); confirmationEmail.setUserId(user.getId()); - try { - Map map = new HashMap<>(); - map.put("userId", this.userScope.getUserId()); - map.put("provider", provider.toString()); - confirmationEmail.setData(new ObjectMapper().writeValueAsString(map)); - } catch (JsonProcessingException | InvalidApplicationException e) { - logger.error(e.getMessage(), e); - } confirmationEmail.setIsConfirmed(false); confirmationEmail.setToken(UUID.randomUUID()); confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); - sentMergeConfirmationEmail(confirmationEmail, mailService, user.getName()); - + + NotificationIntegrationEvent event = new NotificationIntegrationEvent(); + event.setUserId(userScope.getUserIdSafe()); + List contactPairs = new ArrayList<>(); + contactPairs.add(new ContactPair(ContactInfoType.Email, email)); + NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); + event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); + event.setContactTypeHint(NotificationContactType.EMAIL); + event.setNotificationType(UUID.fromString(notificationProperties.getConfirmation())); + NotificationFieldData data = new NotificationFieldData(); + List fieldInfoList = new ArrayList<>(); + fieldInfoList.add(new FieldInfo("{host}", DataType.String, this.environment.getProperty("dmp.domain"))); + fieldInfoList.add(new FieldInfo("{confirmationToken}", DataType.String, confirmationEmail.getToken().toString())); + fieldInfoList.add(new FieldInfo("{expiration_time}", DataType.String, this.secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds"))))); + data.setFields(fieldInfoList); + event.setData(jsonHandlingService.toJsonSafe(data)); + eventHandler.handle(event); } @Override - public void createUnlinkConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, - String email, UserEntity user, Integer provider) throws InvalidApplicationException { + public void sentUnlinkConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, String email, UserEntity user, Integer provider) throws InvalidApplicationException { EmailConfirmation confirmationEmail = new EmailConfirmation(); UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); @@ -200,6 +105,77 @@ public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { confirmationEmail.setIsConfirmed(false); confirmationEmail.setToken(UUID.randomUUID()); confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); - sentUnlinkConfirmationEmail(confirmationEmail, mailService); + + NotificationIntegrationEvent event = new NotificationIntegrationEvent(); + event.setUserId(userScope.getUserIdSafe()); + List contactPairs = new ArrayList<>(); + contactPairs.add(new ContactPair(ContactInfoType.Email, email)); + NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); + event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); + event.setContactTypeHint(NotificationContactType.EMAIL); + event.setNotificationType(UUID.fromString(notificationProperties.getUnlinkConfirmation())); + NotificationFieldData data = new NotificationFieldData(); + List fieldInfoList = new ArrayList<>(); + fieldInfoList.add(new FieldInfo("{host}", DataType.String, this.environment.getProperty("dmp.domain"))); + fieldInfoList.add(new FieldInfo("{confirmationToken}", DataType.String, confirmationEmail.getToken().toString())); + fieldInfoList.add(new FieldInfo("{email}", DataType.String, email)); + fieldInfoList.add(new FieldInfo("{expiration_time}", DataType.String, this.secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds"))))); + data.setFields(fieldInfoList); + event.setData(jsonHandlingService.toJsonSafe(data)); + eventHandler.handle(event); } + + @Override + public void sentMergeConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, + String email, UserEntity user, Integer provider) throws InvalidApplicationException { + EmailConfirmation confirmationEmail = new EmailConfirmation(); + confirmationEmail.setEmail(email); + confirmationEmail.setExpiresAt(Date + .from(new Date() + .toInstant() + .plusSeconds(Long.parseLong(this.environment.getProperty("conf_email.expiration_time_seconds"))) + ) + ); + confirmationEmail.setUserId(user.getId()); + try { + Map map = new HashMap<>(); + map.put("userId", this.userScope.getUserId()); + map.put("provider", provider.toString()); + confirmationEmail.setData(new ObjectMapper().writeValueAsString(map)); + } catch (JsonProcessingException | InvalidApplicationException e) { + logger.error(e.getMessage(), e); + } + confirmationEmail.setIsConfirmed(false); + confirmationEmail.setToken(UUID.randomUUID()); + confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); + + NotificationIntegrationEvent event = new NotificationIntegrationEvent(); + event.setUserId(userScope.getUserIdSafe()); + List contactPairs = new ArrayList<>(); + contactPairs.add(new ContactPair(ContactInfoType.Email, email)); + NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); + event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); + event.setContactTypeHint(NotificationContactType.EMAIL); + event.setNotificationType(UUID.fromString(notificationProperties.getMergeConfirmation())); + NotificationFieldData data = new NotificationFieldData(); + List fieldInfoList = new ArrayList<>(); + fieldInfoList.add(new FieldInfo("{userName}", DataType.String, user.getName())); + fieldInfoList.add(new FieldInfo("{host}", DataType.String, this.environment.getProperty("dmp.domain"))); + fieldInfoList.add(new FieldInfo("{confirmationToken}", DataType.String, confirmationEmail.getToken().toString())); + fieldInfoList.add(new FieldInfo("{expiration_time}", DataType.String, this.secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds"))))); + data.setFields(fieldInfoList); + event.setData(jsonHandlingService.toJsonSafe(data)); + eventHandler.handle(event); + + } + + private String secondsToTime(int seconds) { + int sec = seconds % 60; + int hour = seconds / 60; + int min = hour % 60; + hour = hour / 60; + return (hour + ":" + min + ":" + sec); + } + + } \ No newline at end of file diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationService.java index d2fdafbad..b7f891888 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationService.java @@ -8,8 +8,9 @@ import eu.eudat.data.dao.entities.InvitationDao; import eu.eudat.data.old.Invitation; import eu.eudat.data.UserEntity; -import eu.eudat.service.mail.MailService; import jakarta.mail.MessagingException; + +import javax.management.InvalidApplicationException; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -19,7 +20,7 @@ public interface InvitationService { void assignToDmp(DMPDao dmpDao, DmpUserEntity user, DmpEntity dmp); - void createInvitations(InvitationDao invitationDao, MailService mailService, List users, DmpEntity dmp, Integer role, UserEntity creator) throws MessagingException; + void createInvitations(InvitationDao invitationDao, List users, DmpEntity dmp, Integer role, UserEntity creator) throws MessagingException, InvalidApplicationException; - CompletableFuture sendInvitationAsync(DmpEntity dmp, Invitation invitation, String recipient, MailService mailService, Integer role) throws MessagingException; + void sendInvitation(DmpEntity dmp, Invitation invitation, UserEntity user, Integer role) throws InvalidApplicationException; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java index 3d15be611..fce27ed9d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java @@ -1,17 +1,24 @@ package eu.eudat.logic.services.utilities; +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.enums.ContactInfoType; +import eu.eudat.commons.enums.DmpUserRole; +import eu.eudat.commons.enums.notification.NotificationContactType; +import eu.eudat.commons.scope.user.UserScope; +import eu.eudat.commons.types.notification.*; +import eu.eudat.configurations.notification.NotificationProperties; import eu.eudat.data.DmpEntity; import eu.eudat.data.DmpUserEntity; import eu.eudat.data.dao.entities.DMPDao; import eu.eudat.data.dao.entities.InvitationDao; import eu.eudat.data.old.Invitation; import eu.eudat.data.UserEntity; +import eu.eudat.integrationevent.outbox.notification.NotificationIntegrationEvent; +import eu.eudat.integrationevent.outbox.notification.NotificationIntegrationEventHandler; import eu.eudat.model.UserContactInfo; import eu.eudat.models.data.invitation.Properties; import eu.eudat.query.UserContactInfoQuery; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.mail.SimpleMail; import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.QueryFactory; import org.slf4j.Logger; @@ -23,20 +30,30 @@ import org.springframework.stereotype.Service; import jakarta.mail.MessagingException; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.Marshaller; + +import javax.management.InvalidApplicationException; import java.io.StringWriter; +import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; @Service("invitationService") public class InvitationServiceImpl implements InvitationService { private static final Logger logger = LoggerFactory.getLogger(InvitationServiceImpl.class); private Environment environment; + private final UserScope userScope; + private final NotificationIntegrationEventHandler eventHandler; + private final JsonHandlingService jsonHandlingService; + private final NotificationProperties notificationProperties; @Autowired - public InvitationServiceImpl(Environment environment, QueryFactory queryFactory) { + public InvitationServiceImpl(Environment environment, UserScope userScope, NotificationIntegrationEventHandler eventHandler, JsonHandlingService jsonHandlingService, NotificationProperties notificationProperties, QueryFactory queryFactory) { this.environment = environment; + this.userScope = userScope; + this.eventHandler = eventHandler; + this.jsonHandlingService = jsonHandlingService; + this.notificationProperties = notificationProperties; this.queryFactory = queryFactory; } private final QueryFactory queryFactory; @@ -58,11 +75,11 @@ public class InvitationServiceImpl implements InvitationService { } @Override - public void createInvitations(InvitationDao invitationDao, MailService mailService, List users, DmpEntity dmp, Integer role, UserEntity creator) throws MessagingException { - for (UserEntity userInfo : users) { + public void createInvitations(InvitationDao invitationDao, List users, DmpEntity dmp, Integer role, UserEntity creator) throws MessagingException, InvalidApplicationException { + for (UserEntity user : users) { Invitation invitation = new Invitation(); // invitation.setDmp(dmp); //TODO - UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(userInfo.getId()); + UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); invitation.setInvitationEmail(query.first().getValue()); invitation.setUser(creator); @@ -80,37 +97,34 @@ public class InvitationServiceImpl implements InvitationService { logger.error(e.getMessage(), e); } invitationDao.createOrUpdate(invitation); - sendInvitationAsync(dmp, invitation, userInfo.getName(), mailService, role); + this.sendInvitation(dmp, invitation, user, role); } } @Override - public CompletableFuture sendInvitationAsync(DmpEntity dmp, Invitation invitation, String recipient, MailService mailService, Integer role) { - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(createSubject(dmp, mailService.getMailTemplateSubject())); - mail.setContent(createContent(invitation.getId(), dmp, recipient, mailService.getMailTemplateContent(this.environment.getProperty("email.invite")), role)); - mail.setTo(invitation.getInvitationEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } + public void sendInvitation(DmpEntity dmp, Invitation invitation, UserEntity user, Integer role) throws InvalidApplicationException { - private String createSubject(DmpEntity dmp, String templateSubject) { - String subject = templateSubject.replace("{dmpname}", dmp.getLabel()); - return subject; - } + NotificationIntegrationEvent event = new NotificationIntegrationEvent(); + event.setUserId(userScope.getUserIdSafe()); - private String createContent(UUID invitationID, DmpEntity dmp, String recipient, String templateContent, Integer role) { - String content = templateContent.replace("{dmpname}", dmp.getLabel()); - content = content.replace("{invitationID}", invitationID.toString()); - content = content.replace("{recipient}", recipient); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); -// content = content.replace("{dmprole}", UserDMP.UserDMPRoles.fromInteger(role).name()); //TODO + UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); + query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); - return content; + List contactPairs = new ArrayList<>(); + contactPairs.add(new ContactPair(ContactInfoType.Email, query.first().getValue())); + NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); + event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); + event.setContactTypeHint(NotificationContactType.EMAIL); + event.setNotificationType(UUID.fromString(notificationProperties.getDataManagementPlan())); + NotificationFieldData data = new NotificationFieldData(); + List fieldInfoList = new ArrayList<>(); + fieldInfoList.add(new FieldInfo("{recipient}", DataType.String, user.getName())); + fieldInfoList.add(new FieldInfo("{invitationID}", DataType.String, invitation.getId().toString())); + fieldInfoList.add(new FieldInfo("{host}", DataType.String, this.environment.getProperty("dmp.domain"))); + fieldInfoList.add(new FieldInfo("{dmpname}", DataType.String, dmp.getLabel())); + fieldInfoList.add(new FieldInfo("{dmprole}", DataType.String, DmpUserRole.of(role.shortValue()).toString())); + data.setFields(fieldInfoList); + event.setData(jsonHandlingService.toJsonSafe(data)); + eventHandler.handle(event); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesService.java index 2959f4433..917284f58 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesService.java @@ -1,7 +1,7 @@ package eu.eudat.logic.services.utilities; import eu.eudat.logic.services.forms.VisibilityRuleService; -import eu.eudat.service.mail.MailService; +//import eu.eudat.service.mail.MailService; /** * Created by ikalyvas on 3/1/2018. @@ -10,7 +10,5 @@ public interface UtilitiesService { InvitationService getInvitationService(); - MailService getMailService(); - ConfirmationEmailService getConfirmationEmailService(); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesServiceImpl.java index 2e50c26fb..d4aa24119 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/UtilitiesServiceImpl.java @@ -1,8 +1,5 @@ package eu.eudat.logic.services.utilities; -import eu.eudat.logic.services.forms.VisibilityRuleService; -import eu.eudat.logic.services.forms.VisibilityRuleServiceImpl; -import eu.eudat.service.mail.MailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -13,13 +10,11 @@ import org.springframework.stereotype.Service; public class UtilitiesServiceImpl implements UtilitiesService { private InvitationService invitationService; - private MailService mailService; private ConfirmationEmailService confirmationEmailService; @Autowired - public UtilitiesServiceImpl(InvitationService invitationService, MailService mailService, ConfirmationEmailService confirmationEmailService) { + public UtilitiesServiceImpl(InvitationService invitationService, ConfirmationEmailService confirmationEmailService) { this.invitationService = invitationService; - this.mailService = mailService; this.confirmationEmailService = confirmationEmailService; } @@ -33,8 +28,4 @@ public class UtilitiesServiceImpl implements UtilitiesService { return invitationService; } - @Override - public MailService getMailService() { - return mailService; - } } diff --git a/dmp-backend/web/src/main/resources/config/application.yml b/dmp-backend/web/src/main/resources/config/application.yml index 1e0ca9ee9..1d4ec23db 100644 --- a/dmp-backend/web/src/main/resources/config/application.yml +++ b/dmp-backend/web/src/main/resources/config/application.yml @@ -25,5 +25,8 @@ spring: optional:classpath:config/errors.yml[.yml], optional:classpath:config/errors-${spring.profiles.active}.yml[.yml], optional:file:../config/errors-${spring.profiles.active}.yml[.yml], optional:classpath:config/storage.yml[.yml], optional:classpath:config/storage-${spring.profiles.active}.yml[.yml], optional:file:../config/storage-${spring.profiles.active}.yml[.yml], optional:classpath:config/reference-type.yml[.yml], optional:classpath:config/reference-type-${spring.profiles.active}.yml[.yml], optional:file:../config/reference-type-${spring.profiles.active}.yml[.yml], - optional:classpath:config/tenant.yml[.yml], optional:classpath:config/tenant-${spring.profiles.active}.yml[.yml], optional:file:../config/tenant-${spring.profiles.active}.yml[.yml] + optional:classpath:config/tenant.yml[.yml], optional:classpath:config/tenant-${spring.profiles.active}.yml[.yml], optional:file:../config/tenant-${spring.profiles.active}.yml[.yml], + optional:classpath:config/queue.yml[.yml], optional:classpath:config/queue-${spring.profiles.active}.yml[.yml], optional:file:../config/queue-${spring.profiles.active}.yml[.yml], + optional:classpath:config/notification.yml[.yml], optional:classpath:config/notification-${spring.profiles.active}.yml[.yml], optional:file:../config/notification-${spring.profiles.active}.yml[.yml] + diff --git a/dmp-backend/web/src/main/resources/config/keycloak-devel.yml b/dmp-backend/web/src/main/resources/config/keycloak-devel.yml index 11fd34853..83303e735 100644 --- a/dmp-backend/web/src/main/resources/config/keycloak-devel.yml +++ b/dmp-backend/web/src/main/resources/config/keycloak-devel.yml @@ -9,6 +9,6 @@ keycloak-resources: Manager: groupId: 1753f7a7-cedb-4ad4-ae5f-96fe9bdabe3e groupTitle: role-manager - DatasetTemplateEditor: - groupId: 969aa109-9c4d-4f12-ba9b-4a84b2e5a394 - groupTitle: role-dataset-template-editor \ No newline at end of file + DescriptionTemplateEditor: + groupId: b0ea3cf3-21b0-4c6b-9c42-fb09f0e09dbb + groupTitle: role-description-template-editor \ No newline at end of file diff --git a/dmp-backend/web/src/main/resources/config/keycloak.yml b/dmp-backend/web/src/main/resources/config/keycloak.yml index 3916f6454..934a3e5f0 100644 --- a/dmp-backend/web/src/main/resources/config/keycloak.yml +++ b/dmp-backend/web/src/main/resources/config/keycloak.yml @@ -7,7 +7,4 @@ keycloak-client: clientSecret: ${KEYCLOAK_API_CLIENT_SECRET:} keycloak-resources: - authorities: null - tenantGroupsNamingStrategy: null - guestsGroup: null - administratorsGroup: null \ No newline at end of file + authorities: null \ No newline at end of file diff --git a/dmp-backend/web/src/main/resources/config/notification.yml b/dmp-backend/web/src/main/resources/config/notification.yml new file mode 100644 index 000000000..bea5c79fc --- /dev/null +++ b/dmp-backend/web/src/main/resources/config/notification.yml @@ -0,0 +1,10 @@ +notification: + confirmation: 4FDBFA80-7A71-4A69-B854-67CBB70648F1 + dataManagementPlan: 065DEECD-21BB-44AF-9983-E660FDF24BC4 + finalised: 90DB0B46-42DE-BD89-AEBF-6F27EFEB256E + mergeConfirmation: BFE68845-CB05-4C5A-A03D-29161A7C9660 + modified: 4542262A-22F8-4BAA-9DB6-1C8E70AC1DBB + modifiedFinalised: D3CD55FE-8DA2-42E7-A501-3795EE4F16D3 + publish: 55736F7A-83AB-4190-AF43-9D031A6F9612 + template: 223BB607-EFA1-4CE7-99EC-4BEABFEF9A8B + unlinkConfirmation: C9BC3F16-057E-4BBA-8A5F-36BD835E5604 \ No newline at end of file diff --git a/dmp-backend/web/src/main/resources/config/permissions.yml b/dmp-backend/web/src/main/resources/config/permissions.yml index e18005768..b71f98911 100644 --- a/dmp-backend/web/src/main/resources/config/permissions.yml +++ b/dmp-backend/web/src/main/resources/config/permissions.yml @@ -13,9 +13,9 @@ permissions: clients: [ ] allowAnonymous: false allowAuthenticated: false - DatasetProfileManagerRole: + DescriptionTemplateEditorRole: roles: - - DatasetProfileManager + - DescriptionTemplateEditor clients: [ ] allowAnonymous: false allowAuthenticated: false @@ -258,21 +258,21 @@ permissions: BrowseDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor clients: [ ] allowAnonymous: false allowAuthenticated: false EditDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor clients: [ ] allowAnonymous: false allowAuthenticated: false DeleteDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor claims: [ ] clients: [ ] allowAnonymous: false @@ -280,7 +280,7 @@ permissions: CloneDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor claims: [ ] clients: [ ] allowAnonymous: false @@ -288,7 +288,7 @@ permissions: CreateNewVersionDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor claims: [ ] clients: [ ] allowAnonymous: false @@ -296,7 +296,7 @@ permissions: ImportDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor claims: [ ] clients: [ ] allowAnonymous: false @@ -304,7 +304,7 @@ permissions: ExportDescriptionTemplate: roles: - Admin - - DatasetProfileManager + - DescriptionTemplateEditor claims: [ ] clients: [ ] allowAnonymous: false diff --git a/dmp-backend/web/src/main/resources/config/queue-devel.yml b/dmp-backend/web/src/main/resources/config/queue-devel.yml new file mode 100644 index 000000000..a5a7d9992 --- /dev/null +++ b/dmp-backend/web/src/main/resources/config/queue-devel.yml @@ -0,0 +1,18 @@ +queue: + rabbitmq: + durable: true + queue: cite_dmp_devel_web_inbox_queue + exchange: cite_dmp_devel_queue + listenerEnabled: true + publisherEnabled: true + task: + publisher: + options: + exchange: cite_dmp_devel_queue + rabbitmq: + enable: true + listener: + options: + exchange: cite_dmp_devel_queue + rabbitmq: + enable: true diff --git a/dmp-backend/web/src/main/resources/config/queue.yml b/dmp-backend/web/src/main/resources/config/queue.yml new file mode 100644 index 000000000..0f04da973 --- /dev/null +++ b/dmp-backend/web/src/main/resources/config/queue.yml @@ -0,0 +1,58 @@ +spring: + rabbitmq: + host: ${RABBIT_HOST} + port: ${RABBIT_PORT} + username: ${RABBIT_USER} + password: ${RABBIT_PASS} + ssl: + enabled: false +queue: + rabbitmq: + enable: true + app-id: ${THE_API_ID} + durable: null + queue: null + exchange: null + listenerEnabled: true + publisherEnabled: true + #TODO + connection-recovery: + enable: true + network-recovery-interval: 5000 + unreachable-recovery-interval: 5000 + task: + publisher: + enable: true + options: + exchange: null + forget-me-completed-topic: forgetme.completed + notify-topic: notification.notify + tenant-reactivation-topic: tenant.reactivated + tenant-removal-topic: tenant.remove + tenant-touch-topic: tenant.touch + tenant-user-invite-topic: tenant.invite + what-you-know-about-me-completed-topic: whatyouknowaboutme.completed + generate-file-topic: generate.file + rabbitmq: + enable: true + interval-seconds: 30 + options: + retry-threashold: 100 + retry-delay-step-seconds: 300 + max-retry-delay-seconds: 10800 + too-old-to-send-seconds: 604800 + confirm-timeout-seconds: 30 + listener: + enable: true + options: + exchange: null + user-removal-topic: [ "user.remove" ] + user-touched-topic: [ "user.touch" ] + rabbitmq: + enable: true + interval-seconds: 30 + options: + retry-threashold: 100 + retry-delay-step-seconds: 300 + max-retry-delay-seconds: 10800 + too-old-to-send-seconds: 604800 \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/app-role.ts b/dmp-frontend/src/app/core/common/enum/app-role.ts index a08ce00a1..b5fbdc70f 100644 --- a/dmp-frontend/src/app/core/common/enum/app-role.ts +++ b/dmp-frontend/src/app/core/common/enum/app-role.ts @@ -2,5 +2,5 @@ export enum AppRole { Admin = "Admin", Manager = "Manager", User = "User", - DatasetTemplateEditor = "DatasetProfileManager" + DescriptionTemplateEditor = "DescriptionTemplateEditor" } diff --git a/dmp-frontend/src/app/core/services/lock/lock.service.ts b/dmp-frontend/src/app/core/services/lock/lock.service.ts index e939cb1ce..9f689c039 100644 --- a/dmp-frontend/src/app/core/services/lock/lock.service.ts +++ b/dmp-frontend/src/app/core/services/lock/lock.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { HttpHeaders, HttpClient } from '@angular/common/http'; +import { HttpHeaders, HttpClient, HttpResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { Lock, LockModel, LockPersist } from '@app/core/model/lock/lock.model'; import { ConfigurationService } from '../configuration/configuration.service'; @@ -50,14 +50,14 @@ export class LockService { catchError((error: any) => throwError(error))); } - //ToDo change Parameters - checkLockStatus(id: string): Observable { - return this.http.get(`${this.apiBase}/target/status/${id}`, { headers: this.headers }); + checkLockStatus(targetId: Guid): Observable { + return this.http.get(`${this.apiBase}/target/status/${targetId}`) + .pipe(catchError((error: any) => throwError(error))); } - //ToDo change Parameters - unlockTarget(id: string): Observable { - return this.http.delete(`${this.apiBase}/target/unlock/${id}`, { headers: this.headers }); + unlockTarget(targetId: Guid): Observable { + return this.http.delete(`${this.apiBase}/target/unlock/${targetId}`) + .pipe(catchError((error: any) => throwError(error))); } getSingleWithTarget(targetId: Guid, reqFields: string[] = []): Observable { diff --git a/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts b/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts index 19573da24..be8df9173 100644 --- a/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts +++ b/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts @@ -58,7 +58,7 @@ export class EnumUtils { case AppRole.Admin: return this.language.instant('TYPES.APP-ROLE.ADMIN'); case AppRole.User: return this.language.instant('TYPES.APP-ROLE.USER'); case AppRole.Manager: return this.language.instant('TYPES.APP-ROLE.MANAGER'); - case AppRole.DatasetTemplateEditor: return this.language.instant('TYPES.APP-ROLE.DESCRIPTION-TEMPLATE-EDITOR'); + case AppRole.DescriptionTemplateEditor: return this.language.instant('TYPES.APP-ROLE.DESCRIPTION-TEMPLATE-EDITOR'); } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.routing.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.routing.ts index 1bf042f25..9d8f971a7 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.routing.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.routing.ts @@ -14,7 +14,7 @@ const routes: Routes = [ data: { title: 'GENERAL.TITLES.DATASET-PROFILES-NEW', authContext: { - permissions: [AppRole.Admin, AppRole.DatasetTemplateEditor] + permissions: [AppRole.Admin, AppRole.DescriptionTemplateEditor] } }, canActivate: [SpecialAuthGuard], @@ -26,7 +26,7 @@ const routes: Routes = [ data: { title: 'GENERAL.TITLES.DATASET-PROFILES-EDIT', authContext: { - permissions: [AppRole.Admin, AppRole.DatasetTemplateEditor] + permissions: [AppRole.Admin, AppRole.DescriptionTemplateEditor] } }, canActivate: [SpecialAuthGuard], @@ -38,7 +38,7 @@ const routes: Routes = [ data: { title: 'GENERAL.TITLES.DATASET-PROFILES-CLONE', authContext: { - permissions: [AppRole.Admin, AppRole.DatasetTemplateEditor] + permissions: [AppRole.Admin, AppRole.DescriptionTemplateEditor] } }, canActivate: [SpecialAuthGuard], @@ -50,7 +50,7 @@ const routes: Routes = [ data: { title: 'GENERAL.TITLES.DATASET-PROFILES-NEW-VERSION', authContext: { - permissions: [AppRole.Admin, AppRole.DatasetTemplateEditor] + permissions: [AppRole.Admin, AppRole.DescriptionTemplateEditor] } }, canActivate: [SpecialAuthGuard], @@ -61,7 +61,7 @@ const routes: Routes = [ component: DatasetProfileListingComponent, data: { authContext: { - permissions: [AppRole.Admin, AppRole.DatasetTemplateEditor] + permissions: [AppRole.Admin, AppRole.DescriptionTemplateEditor] } }, canActivate: [SpecialAuthGuard] @@ -71,7 +71,7 @@ const routes: Routes = [ component: DatasetProfileListingComponent, data: { authContext: { - permissions: [AppRole.Admin, AppRole.DatasetTemplateEditor] + permissions: [AppRole.Admin, AppRole.DescriptionTemplateEditor] } }, canActivate: [SpecialAuthGuard] diff --git a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.html b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.html index d97099255..91819b19c 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.html +++ b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.html @@ -2,7 +2,7 @@
- + {{enumUtils.toAppRoleString(role)}}
diff --git a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss index 47399e7d4..e551c69e1 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss @@ -85,7 +85,7 @@ padding-right: 10px; } - .dataset-template-editor { + .description-template-editor { // display: flex; // justify-content: center; // align-items: center; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index baec1c2d3..0bc56e515 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -197,7 +197,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.datasetWizardService.getSingle(this.itemId) .pipe(takeUntil(this._destroyed)) .subscribe(data => { - this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + this.lockService.checkLockStatus(Guid.parse(data.id)).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { this.lockStatus = lockStatus; this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); this.dmpSectionIndex = this.datasetWizardModel.dmpSectionIndex; @@ -343,7 +343,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.datasetWizardService.getSingle(this.itemId) .pipe(takeUntil(this._destroyed)) .subscribe(data => { - this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + this.lockService.checkLockStatus(Guid.parse(data.id)).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { this.lockStatus = lockStatus; this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); this.dmpSectionIndex = this.datasetWizardModel.dmpSectionIndex; @@ -610,7 +610,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme public cancel(): void { if (!isNullOrUndefined(this.lock)) { - this.lockService.unlockTarget(this.datasetWizardModel.id).pipe(takeUntil(this._destroyed)).subscribe( + this.lockService.unlockTarget(Guid.parse(this.datasetWizardModel.id)).pipe(takeUntil(this._destroyed)).subscribe( complete => { this.publicMode ? this.router.navigate(['/explore-descriptions']) : this.router.navigate(['/datasets']); }, diff --git a/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts b/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts index da184bdb4..2b3aded48 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts @@ -21,6 +21,7 @@ import { takeUntil } from 'rxjs/operators'; import { DatasetStatus } from '../../../../core/common/enum/dataset-status'; import { DatasetListingModel } from '../../../../core/model/dataset/dataset-listing'; import { DatasetCopyDialogueComponent } from '../../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { Guid } from '@common/types/guid'; @Component({ selector: 'app-dataset-listing-item-component', @@ -168,7 +169,7 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit } deleteClicked(id: string) { - this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) + this.lockService.checkLockStatus(Guid.parse(id)).pipe(takeUntil(this._destroyed)) .subscribe(lockStatus => { if (!lockStatus) { this.openDeleteDialog(id); diff --git a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts index 9c372d3ab..5fcb6c281 100644 --- a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts +++ b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts @@ -32,6 +32,7 @@ import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; import { filter, takeUntil } from 'rxjs/operators'; import { DatasetCopyDialogueComponent } from '../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { Guid } from '@common/types/guid'; @Component({ @@ -137,7 +138,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { } checkLockStatus(id: string) { - this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) + this.lockService.checkLockStatus(Guid.parse(id)).pipe(takeUntil(this._destroyed)) .subscribe(lockStatus => { this.lockStatus = lockStatus if (lockStatus) { diff --git a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts index 96ad20b29..68dfe4c74 100644 --- a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts @@ -181,7 +181,7 @@ export class DescriptionListingItemComponent extends BaseComponent implements On } deleteClicked(id: Guid) { - this.lockService.checkLockStatus(id.toString()).pipe(takeUntil(this._destroyed)) + this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) .subscribe(lockStatus => { if (!lockStatus) { this.openDeleteDialog(id); diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts index 550e9ad5d..d0c6b6c0a 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts @@ -16,7 +16,7 @@ import { DmpDatasetProfile } from '@app/core/model/dmp/dmp-dataset-profile/dmp-d import { DmpDatasetProfileSectionsFormModel } from '@app/core/model/dmp/dmp-dataset-profile/dmp-dataset-profile-sections-form.model'; import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; import { LanguageInfo } from '@app/core/model/language-info'; -import { LockModel } from '@app/core/model/lock/lock.model'; +import { Lock, LockPersist } from '@app/core/model/lock/lock.model'; import { UserModel } from '@app/core/model/user/user'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; @@ -58,6 +58,7 @@ import { ProjectFormModel } from '../editor/grant-tab/project-form-model'; import { ReferenceSearchDefinitionLookup, ReferenceSearchLookup } from '@app/core/query/reference-search.lookup'; import { Reference } from '@app/core/model/reference/reference'; import { ReferenceTypeEditorResolver } from '@app/ui/admin/reference-type/editor/reference-type-editor.resolver'; +import { LockTargetType } from '@app/core/common/enum/lock-target-type'; interface Visible { value: boolean; @@ -99,7 +100,8 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im associatedUsers: Array; people: Array; - lock: LockModel; + lock: Lock; + lockPersist: LockPersist; lockStatus: Boolean = false; step: number = 0; @@ -181,7 +183,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im this.dmpService.getSingle(itemId).pipe(map(data => data as DmpModel)) .pipe(takeUntil(this._destroyed)) .subscribe(async data => { - this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + this.lockService.checkLockStatus(Guid.parse(data.id)).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { this.lockStatus = lockStatus; this.dmp = new DmpEditorModel(); @@ -228,10 +230,14 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im if (this.authService.currentAccountIsAuthenticated()) { if (!lockStatus) { - this.lock = new LockModel(data.id, this.getUserFromDMP()); + const persist : LockPersist = null; + persist.target = Guid.parse(data.id); + persist.targetType = LockTargetType.Dmp; + persist.lockedBy = this.getUserFromDMP(); + // this.lock = new LockModel(data.id, this.getUserFromDMP()); - this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { - this.lock.id = Guid.parse(result); + this.lockService.persist(persist).pipe(takeUntil(this._destroyed)).subscribe(async result => { + this.lock = result; interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); }); } @@ -351,7 +357,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im private pumpLock() { this.lock.touchedAt = new Date(); - this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => this.lock.id = Guid.parse(result)); + //his.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => this.lock.id = Guid.parse(result)); } public isDirty(): boolean { diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index 2027b0c2c..26e39daba 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -159,7 +159,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements this.dmpService.getSingle(itemId).pipe(map(data => data as DmpModel)) .pipe(takeUntil(this._destroyed)) .subscribe(async data => { - this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + this.lockService.checkLockStatus(Guid.parse(data.id)).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { this.lockStatus = lockStatus; this.dmpModel = data; @@ -591,7 +591,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements public cancel(id: String): void { if (id != null) { - this.lockService.unlockTarget(this.dmp.id).pipe(takeUntil(this._destroyed)).subscribe( + this.lockService.unlockTarget(Guid.parse(this.dmp.id)).pipe(takeUntil(this._destroyed)).subscribe( complete => { this.router.navigate(['/plans/overview/' + id]); }, diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts index 626781a5b..1e1a282ae 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts @@ -237,7 +237,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit { // } deleteClicked(id: Guid) { - this.lockService.checkLockStatus(id.toString()).pipe(takeUntil(this._destroyed)) + this.lockService.checkLockStatus(Guid.parse(id.toString())).pipe(takeUntil(this._destroyed)) .subscribe(lockStatus => { if (!lockStatus) { this.openDeleteDialog(id); diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index b19a74a90..7e64784ac 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -695,7 +695,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } checkLockStatus(id: Guid) { - this.lockService.checkLockStatus(id.toString()).pipe(takeUntil(this._destroyed)) + this.lockService.checkLockStatus(Guid.parse(id.toString())).pipe(takeUntil(this._destroyed)) .subscribe(lockStatus => { this.lockStatus = lockStatus if (lockStatus) { diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts index 554cf7617..226327617 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts @@ -159,7 +159,7 @@ export class SidebarComponent implements OnInit { title: 'SIDE-BAR.ADMIN', routes: DATASET_TEMPLATE_ROUTES, requiresAuthentication: true, - requiresSpecialPermission: AppRole.DatasetTemplateEditor, + requiresSpecialPermission: AppRole.DescriptionTemplateEditor, requiresAdmin: false, isGeneral: false } diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/ContactEmail.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/ContactEmail.java deleted file mode 100644 index b75018c11..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/ContactEmail.java +++ /dev/null @@ -1,55 +0,0 @@ -package eu.old.eudat.controllers; - -import eu.old.eudat.logic.managers.ContactEmailManager; -import eu.old.eudat.models.data.ContactEmail.ContactEmailModel; -import eu.old.eudat.models.data.ContactEmail.PublicContactEmailModel; -import eu.old.eudat.models.data.helpers.responses.ResponseItem; -import eu.old.eudat.models.data.security.Principal; -import eu.old.eudat.types.ApiMessageCode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import jakarta.transaction.Transactional; - -@RestController -@CrossOrigin -@RequestMapping(value = "api/contactEmail") -public class ContactEmail { - private static final Logger logger = LoggerFactory.getLogger(ContactEmail.class); - - private ContactEmailManager contactEmailManager; - - public ContactEmail(ContactEmailManager contactEmailManager) { - this.contactEmailManager = contactEmailManager; - } - - @Transactional - @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") - public @ResponseBody - ResponseEntity sendContactEmail(@RequestBody ContactEmailModel contactEmailModel, Principal principal) { - try { - this.contactEmailManager.emailValidation(contactEmailModel); - this.contactEmailManager.sendContactEmail(contactEmailModel, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message(ex.getMessage())); - } - } - - @Transactional - @RequestMapping(method = RequestMethod.POST, path = "public", consumes = "application/x-www-form-urlencoded", produces = "application/json") - public @ResponseBody - ResponseEntity sendContactEmailNoAuth(@ModelAttribute PublicContactEmailModel contactEmailModel) { - try { - this.contactEmailManager.sendContactEmailNoAuth(contactEmailModel); - return ResponseEntity.status(HttpStatus.NO_CONTENT).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message(ex.getMessage())); - } - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailConfirmation.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailConfirmation.java deleted file mode 100644 index b3e3bffcd..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailConfirmation.java +++ /dev/null @@ -1,59 +0,0 @@ -package eu.old.eudat.controllers; - -import eu.old.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; -import eu.old.eudat.exceptions.emailconfirmation.TokenExpiredException; -import eu.old.eudat.logic.managers.EmailConfirmationManager; -import eu.old.eudat.models.data.helpers.responses.ResponseItem; -import eu.old.eudat.models.data.security.Principal; -import eu.old.eudat.types.ApiMessageCode; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import jakarta.transaction.Transactional; - -@RestController -@CrossOrigin -@RequestMapping(value = "api/emailConfirmation") -public class EmailConfirmation { - - private EmailConfirmationManager emailConfirmationManager; - - @Autowired - public EmailConfirmation(EmailConfirmationManager emailConfirmationManager) { - this.emailConfirmationManager = emailConfirmationManager; - } - - @Transactional - @RequestMapping(method = RequestMethod.GET, value = {"/{emailToken}"}) - public @ResponseBody - ResponseEntity emailConfirmation(@PathVariable(value = "emailToken") String token) { - try { - this.emailConfirmationManager.confirmEmail(token); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch - (HasConfirmedEmailException | TokenExpiredException ex) { - if (ex instanceof TokenExpiredException) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); - } else { - return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); - } - } - } - - @Transactional - @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") - public @ResponseBody - ResponseEntity sendConfirmatioEmail(@RequestBody String email, Principal principal) { - try { - this.emailConfirmationManager.sendConfirmationEmail(email, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch (Exception ex) { - if (ex instanceof HasConfirmedEmailException) { - return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); - } - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); - } - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailMergeConfirmation.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailMergeConfirmation.java deleted file mode 100644 index 486e9d98f..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailMergeConfirmation.java +++ /dev/null @@ -1,60 +0,0 @@ -package eu.old.eudat.controllers; - -import eu.old.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; -import eu.old.eudat.exceptions.emailconfirmation.TokenExpiredException; -import eu.old.eudat.logic.managers.MergeEmailConfirmationManager; -import eu.old.eudat.models.data.helpers.responses.ResponseItem; -import eu.old.eudat.models.data.security.Principal; -import eu.old.eudat.models.data.userinfo.UserMergeRequestModel; -import eu.old.eudat.types.ApiMessageCode; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import jakarta.transaction.Transactional; - -@RestController -@CrossOrigin -@RequestMapping(value = "api/emailMergeConfirmation") -public class EmailMergeConfirmation { - - private MergeEmailConfirmationManager emailConfirmationManager; - - @Autowired - public EmailMergeConfirmation(MergeEmailConfirmationManager emailConfirmationManager) { - this.emailConfirmationManager = emailConfirmationManager; - } - - @Transactional - @RequestMapping(method = RequestMethod.GET, value = {"/{emailToken}"}) - public @ResponseBody - ResponseEntity> emailConfirmation(@PathVariable(value = "emailToken") String token) { - try { - String emailToBeMerged = this.emailConfirmationManager.confirmEmail(token); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(emailToBeMerged).status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch - (HasConfirmedEmailException | TokenExpiredException ex) { - if (ex instanceof TokenExpiredException) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); - } else { - return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); - } - } - } - - @Transactional - @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") - public @ResponseBody - ResponseEntity sendConfirmatioEmail(@RequestBody UserMergeRequestModel requestModel, Principal principal) { - try { - this.emailConfirmationManager.sendConfirmationEmail(requestModel.getEmail(), principal, requestModel.getUserId(), requestModel.getProvider()); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch (Exception ex) { - if (ex instanceof HasConfirmedEmailException) { - return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); - } - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); - } - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailUnlinkConfirmation.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailUnlinkConfirmation.java deleted file mode 100644 index 1d9dcedb2..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/EmailUnlinkConfirmation.java +++ /dev/null @@ -1,57 +0,0 @@ -package eu.old.eudat.controllers; - -import eu.old.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; -import eu.old.eudat.exceptions.emailconfirmation.TokenExpiredException; -import eu.old.eudat.logic.managers.UnlinkEmailConfirmationManager; -import eu.old.eudat.models.data.helpers.responses.ResponseItem; -import eu.old.eudat.models.data.security.Principal; -import eu.old.eudat.models.data.userinfo.UserUnlinkRequestModel; -import eu.old.eudat.types.ApiMessageCode; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import jakarta.transaction.Transactional; - -@RestController -@CrossOrigin -@RequestMapping(value = "api/emailUnlinkConfirmation") -public class EmailUnlinkConfirmation { - - private UnlinkEmailConfirmationManager unlinkEmailConfirmationManager; - - @Autowired - public EmailUnlinkConfirmation(UnlinkEmailConfirmationManager unlinkEmailConfirmationManager){ - this.unlinkEmailConfirmationManager = unlinkEmailConfirmationManager; - } - - @Transactional - @RequestMapping(method = RequestMethod.GET, value = {"/{emailToken}"}) - public @ResponseBody - ResponseEntity emailConfirmation(@PathVariable(value = "emailToken") String token) { - try { - this.unlinkEmailConfirmationManager.confirmEmail(token); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch (TokenExpiredException | HasConfirmedEmailException ex) { - if (ex instanceof TokenExpiredException) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); - } - else { - return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); - } - } - } - - @Transactional - @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") - public @ResponseBody - ResponseEntity sendUnlinkConfirmationEmail(@RequestBody UserUnlinkRequestModel requestModel, Principal principal) { - try { - this.unlinkEmailConfirmationManager.sendConfirmationEmail(requestModel.getEmail(), principal, requestModel.getUserId(), requestModel.getProvider()); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); - } catch (Exception ex) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).message("Could not send unlink email.")); - } - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/UserInvitationController.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/UserInvitationController.java deleted file mode 100644 index df141b912..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/controllers/UserInvitationController.java +++ /dev/null @@ -1,59 +0,0 @@ -package eu.old.eudat.controllers; - -import eu.old.eudat.data.query.items.item.userinfo.UserInfoRequestItem; -import eu.old.eudat.logic.managers.InvitationsManager; -import eu.old.eudat.logic.services.ApiContext; -import eu.old.eudat.models.data.helpers.responses.ResponseItem; -import eu.old.eudat.models.data.invitation.Invitation; -import eu.old.eudat.models.data.security.Principal; -import eu.old.eudat.models.data.userinfo.UserInfoInvitationModel; -import eu.old.eudat.types.ApiMessageCode; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; - -import jakarta.xml.bind.JAXBException; -import java.io.IOException; -import java.util.List; -import java.util.UUID; - - -@RequestMapping("api/invite/") -@RestController -@CrossOrigin -public class UserInvitationController extends BaseController { - - private InvitationsManager invitationsManager; - @Autowired - public UserInvitationController(ApiContext apiContext, InvitationsManager invitationsManager) { - super(apiContext); - this.invitationsManager = invitationsManager; - } - - @Transactional - @RequestMapping(method = RequestMethod.POST, value = {"/users"}, consumes = "application/json", produces = "application/json") - public @ResponseBody - ResponseEntity> users(@RequestBody Invitation invitation, Principal principal) throws Exception { - this.invitationsManager.inviteUsers(invitation, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("Users have beeen invited")); - } - - @Transactional - @RequestMapping(method = RequestMethod.GET, value = {"/exchange/{invitationID}"}, produces = "application/json") - public @ResponseBody - ResponseEntity> exchange(@PathVariable UUID invitationID, Principal principal) throws JAXBException, IOException { - UUID dmpId = invitationsManager.assignUserAcceptedInvitation(invitationID, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).payload(dmpId)); - } - - @RequestMapping(method = RequestMethod.POST, value = {"/getUsers"}, consumes = "application/json", produces = "application/json") - public @ResponseBody -// ResponseEntity>> getUsers(Principal principal) throws IllegalAccessException, InstantiationException { - ResponseEntity>> getUsers(Principal principal, @RequestBody UserInfoRequestItem userInfoRequestItem) throws IllegalAccessException, InstantiationException { -// List users = invitationsManager.getUsers(principal); - List users = invitationsManager.getUsersWithCriteria(principal, userInfoRequestItem); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.SUCCESS_MESSAGE).payload(users)); - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/ContactEmailManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/ContactEmailManager.java deleted file mode 100644 index b60010d67..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/ContactEmailManager.java +++ /dev/null @@ -1,58 +0,0 @@ -package eu.old.eudat.logic.managers; - -import eu.old.eudat.data.entities.UserInfo; -import eu.old.eudat.logic.services.ApiContext; -import eu.old.eudat.models.data.ContactEmail.ContactEmailModel; -import eu.old.eudat.models.data.ContactEmail.PublicContactEmailModel; -import eu.old.eudat.models.data.security.Principal; -import eu.eudat.service.mail.SimpleMail; -import org.springframework.core.env.Environment; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import jakarta.mail.MessagingException; - -@Component -public class ContactEmailManager { - - private ApiContext apiContext; - private Environment environment; - - @Autowired - public ContactEmailManager(ApiContext apiContext, Environment environment) { - this.apiContext = apiContext; - this.environment = environment; - } - - public void sendContactEmail(ContactEmailModel contactEmailModel, Principal principal) throws MessagingException { - UserInfo user = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); - SimpleMail mail = new SimpleMail(); - String enrichedMail = contactEmailModel.getDescription() + "\n\n" + "Send by user: " + user.getEmail() ; - mail.setSubject(contactEmailModel.getSubject()); - mail.setTo(environment.getProperty("contact_email.mail")); - mail.setContent(enrichedMail); - mail.setFrom(user.getEmail()); - - apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); - } - - public void sendContactEmailNoAuth(PublicContactEmailModel contactEmailModel) throws MessagingException { - SimpleMail mail = new SimpleMail(); - String enrichedMail = contactEmailModel.getMessage() + "\n\n" + "Send by user: " + contactEmailModel.getEmail() ; - mail.setSubject(contactEmailModel.getAffiliation()); - mail.setTo(environment.getProperty("contact_email.mail")); - mail.setContent(enrichedMail); - mail.setFrom(contactEmailModel.getEmail()); - - apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); - } - - public void emailValidation(ContactEmailModel contactEmailModel) throws Exception { - if (contactEmailModel.getSubject() == null || contactEmailModel.getSubject().trim().isEmpty()) { - throw new Exception("Subject is empty"); - } - if (contactEmailModel.getDescription() == null || contactEmailModel.getDescription().trim().isEmpty()) { - throw new Exception("Description is empty"); - } - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/DatasetProfileManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/DatasetProfileManager.java index 7cbdf0cab..9898892fb 100644 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/DatasetProfileManager.java +++ b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/DatasetProfileManager.java @@ -28,7 +28,6 @@ import eu.old.eudat.models.data.listingmodels.UserInfoListingModel; import eu.old.eudat.models.data.security.Principal; import eu.old.eudat.models.data.admin.composite.DatasetProfile; import eu.old.eudat.queryable.QueryableList; -import eu.eudat.service.mail.SimpleMail; import eu.old.eudat.types.Authorities; import eu.old.eudat.types.MetricNames; import org.slf4j.Logger; @@ -322,14 +321,12 @@ public class DatasetProfileManager { userDatasetProfile1.setUser(userInfo1); userDatasetProfile1.setRole(1); apiContext.getOperationsContext().getDatabaseRepository().getUserDatasetProfileDao().createOrUpdate(userDatasetProfile1); - sendJoinMail(userDatasetProfile1); }); entity.getUsers().stream().filter(userDatasetProfile -> model.getUsers().stream() .filter(userInfoListingModel -> userDatasetProfile.getUser().getId().equals(userInfoListingModel.getId())).count() > 0 && userDatasetProfile.getRole() == 2).forEach(userDatasetProfile -> { userDatasetProfile.setRole(1); apiContext.getOperationsContext().getDatabaseRepository().getUserDatasetProfileDao().createOrUpdate(userDatasetProfile); - sendJoinMail(userDatasetProfile); }); } if (entity.getUsers() != null && !entity.getUsers().isEmpty()) { @@ -356,24 +353,6 @@ public class DatasetProfileManager { } } - private void sendJoinMail(UserDatasetProfile userDatasetProfile) { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("admin.mail.subject").replace( "{templateName}", userDatasetProfile.getDatasetProfile().getLabel())); - String content = apiContext.getUtilitiesService().getMailService().getMailTemplateContent(environment.getProperty("email.dataset.template")); - content = content.replace("{recipient}", userDatasetProfile.getUser().getName()); - content = content.replace("{templateName}", userDatasetProfile.getDatasetProfile().getLabel()); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - content = content.replace("{templateID}", userDatasetProfile.getDatasetProfile().getId().toString()); - mail.setContent(content); - mail.setTo(userDatasetProfile.getUser().getEmail()); - try { - apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - - } - public List getSemantics(String query) { List semantics = configLoader.getSemantics(); List filteredSemantics = semantics.stream().map(Semantic::getName).collect(Collectors.toList()); diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/EmailConfirmationManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/EmailConfirmationManager.java index b1d1dcfa9..8d5befc3b 100644 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/EmailConfirmationManager.java +++ b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/EmailConfirmationManager.java @@ -66,19 +66,6 @@ public class EmailConfirmationManager { databaseRepository.getLoginConfirmationEmailDao().createOrUpdate(loginConfirmationEmail); } - public void sendConfirmationEmail(String email, Principal principal) throws HasConfirmedEmailException { - UserInfo user = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); - if (user.getEmail() != null) - throw new HasConfirmedEmailException("User already has confirmed his Email."); - - apiContext.getUtilitiesService().getConfirmationEmailService().createConfirmationEmail( - databaseRepository.getLoginConfirmationEmailDao(), - apiContext.getUtilitiesService().getMailService(), - email, - principal.getId() - ); - } - private void mergeNewUserToOld(UserInfo newUser, UserInfo oldUser) { Credential credential = databaseRepository.getCredentialDao().asQueryable().where((builder, root) -> builder.equal(root.get("userInfo"), newUser)).getSingle(); credential.setUserInfo(oldUser); diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/InvitationsManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/InvitationsManager.java deleted file mode 100644 index e4b9b7d0e..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/InvitationsManager.java +++ /dev/null @@ -1,153 +0,0 @@ -package eu.old.eudat.logic.managers; - -import eu.old.eudat.data.entities.DMP; -import eu.old.eudat.data.entities.UserDMP; -import eu.old.eudat.data.entities.UserInfo; -import eu.old.eudat.data.query.items.item.userinfo.UserInfoRequestItem; -import eu.old.eudat.exceptions.security.UnauthorisedException; -import eu.old.eudat.logic.services.ApiContext; -import eu.old.eudat.logic.utilities.helpers.StreamDistinctBy; -import eu.old.eudat.models.data.invitation.Invitation; -import eu.old.eudat.models.data.invitation.Properties; -import eu.old.eudat.models.data.security.Principal; -import eu.old.eudat.models.data.userinfo.UserInfoInvitationModel; -import eu.old.eudat.queryable.QueryableList; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import jakarta.xml.bind.JAXBContext; -import jakarta.xml.bind.JAXBException; -import jakarta.xml.bind.Unmarshaller; -import java.io.IOException; -import java.io.StringReader; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -@Component -public class InvitationsManager { - - private ApiContext apiContext; - private DataManagementPlanManager dataManagementPlanManager; - - @Autowired - public InvitationsManager(ApiContext apiContext, DataManagementPlanManager dataManagementPlanManager) { - this.apiContext = apiContext; - this.dataManagementPlanManager = dataManagementPlanManager; - } - - public void inviteUsers(Invitation invitation, Principal principal) throws Exception { - UserInfo principalUser = new UserInfo(); - principalUser.setId(principal.getId()); - invitation.getUsers().stream().filter(item -> item.getId() == null).forEach(item -> { - UserInfo existingUser = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().asQueryable().where((builder, root) -> builder.equal(root.get("email"), item.getEmail())).getSingleOrDefault(); - if (existingUser != null) { - item.setId(existingUser.getId()); - } - }); - List alreadySignedInUsers = invitation.getUsers().stream().filter(item -> item.getId() != null).collect(Collectors.toList()); - List alreadySignedInUsersEntities = alreadySignedInUsers.stream().map(UserInfoInvitationModel::toDataModel).collect(Collectors.toList()); - List userInfoToUserDmp = new LinkedList<>(); - for (UserInfo userInfo : alreadySignedInUsersEntities) { - UserDMP userDMP = new UserDMP(); - userDMP.setUser(userInfo); - userDMP.setRole(invitation.getRole()); - userInfoToUserDmp.add(userDMP); - /*if (!apiContext.getOperationsContext().getDatabaseRepository().getUserAssociationDao().areAssociated(principalUser, userInfo)) { - UserAssociation userAssociation = new UserAssociation(); - userAssociation.setFirstUser(principalUser); - userAssociation.setSecondUser(userInfo); - apiContext.getOperationsContext().getDatabaseRepository().getUserAssociationDao().createOrUpdate(userAssociation); - }*/ - } - DMP dataManagementPlan = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(invitation.getDataManagementPlan()); - apiContext.getUtilitiesService().getInvitationService().createInvitations(apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao(), apiContext.getUtilitiesService().getMailService(), invitation.getUsers().stream().map(UserInfoInvitationModel::toDataModel).collect(Collectors.toList()), dataManagementPlan, invitation.getRole(), principalUser); - apiContext.getUtilitiesService().getInvitationService().assignToDmp(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao(), userInfoToUserDmp, dataManagementPlan); - } - - public List getUsers(Principal principal) throws InstantiationException, IllegalAccessException { - /*UserInfo principalUser = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); - List users = apiContext.getOperationsContext().getDatabaseRepository().getUserAssociationDao().getAssociated(principalUser).stream().map(userAssociation -> { - if (userAssociation.getFirstUser().getId().equals(principal.getId())) { - return userAssociation.getSecondUser(); - } else { - return userAssociation.getFirstUser(); - } - }).collect(Collectors.toList());*/ - List users = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao() - .getAuthenticated(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().asQueryable() - .where(((builder, root) -> builder.notEqual(root.get("status"), DMP.DMPStatus.DELETED.getValue()))), principal.getId(), Stream.of(0, 1).collect(Collectors.toList())) - .toList().stream().map(DMP::getUsers).flatMap(Collection::stream).map(UserDMP::getUser) - .filter(userInfo -> !userInfo.getId().equals(principal.getId())).filter(StreamDistinctBy.distinctByKey(UserInfo::getId)).collect(Collectors.toList()); - List userModels = users.stream().map(userInfo -> new UserInfoInvitationModel().fromDataModel(userInfo)).collect(Collectors.toList()); - return userModels; - } - - public List getUsersWithCriteria(Principal principal, UserInfoRequestItem userInfoRequestItem) throws IllegalAccessException, InstantiationException { - List users = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao() - .getAuthenticated(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().asQueryable() - .where(((builder, root) -> - builder.notEqual(root.get("status"), DMP.DMPStatus.DELETED.getValue()))), principal.getId(), Stream.of(0, 1).collect(Collectors.toList())) - .toList().stream().map(DMP::getUsers).flatMap(Collection::stream).map(UserDMP::getUser) - .filter(userInfo -> !userInfo.getId().equals(principal.getId())).filter(StreamDistinctBy.distinctByKey(UserInfo::getId)) - .filter(userInfo -> (userInfoRequestItem == null || userInfoRequestItem.getCriteria() == null || userInfoRequestItem.getCriteria().getLike() == null - || userInfo.getName().toLowerCase().contains(userInfoRequestItem.getCriteria().getLike().toLowerCase()) - || (userInfo.getEmail().toLowerCase().contains(userInfoRequestItem.getCriteria().getLike().toLowerCase())))) - .collect(Collectors.toList()); -// .where((builder, root) -> builder.like(builder.upper(root.get("name")), "%" + userInfoRequestItem.getCriteria().getLike().toUpperCase() + "%")) - - List userModels = users.stream().map(userInfo -> new UserInfoInvitationModel().fromDataModel(userInfo)).collect(Collectors.toList()); - return userModels; - } - - public UUID assignUserAcceptedInvitation(UUID invitationID, Principal principal) throws UnauthorisedException, JAXBException, IOException { - eu.old.eudat.data.entities.Invitation invitation = apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao().find(invitationID); - if (invitation == null) - throw new UnauthorisedException("There is no Data Management Plan assigned to this Link"); - if (invitation.getAcceptedInvitation()) return invitation.getDmp().getId(); //throw new UnauthorisedException("This Url Has Expired"); - JAXBContext context = JAXBContext.newInstance(eu.old.eudat.models.data.invitation.Properties.class); - Unmarshaller unmarshaller = context.createUnmarshaller(); - eu.old.eudat.models.data.invitation.Properties properties = (Properties) unmarshaller.unmarshal(new StringReader(invitation.getProperties())); - UserInfo invitedUser = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); - QueryableList userDMPQueryableList = apiContext.getOperationsContext().getDatabaseRepository().getUserDmpDao().asQueryable().where(((builder, root) -> builder.and(builder.equal(root.get("dmp").get("id"), invitation.getDmp().getId()), builder.equal(root.get("user").get("id"), invitedUser.getId())))); - UserDMP existingUserDMP = userDMPQueryableList.getSingleOrDefault(); - if (existingUserDMP != null) { - if (properties.getRole() != null && existingUserDMP.getRole() > properties.getRole()) { - existingUserDMP.setRole(properties.getRole()); - DMP datamanagementPlan = invitation.getDmp(); - apiContext.getOperationsContext().getDatabaseRepository().getUserDmpDao().createOrUpdate(existingUserDMP); - apiContext.getUtilitiesService().getInvitationService().assignToDmp(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao(), existingUserDMP, datamanagementPlan); - invitation.setAcceptedInvitation(true); - apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao().createOrUpdate(invitation); - datamanagementPlan.setUsers(new HashSet<>(apiContext.getOperationsContext().getDatabaseRepository().getUserDmpDao().asQueryable().where((builder, root) -> builder.equal(root.get("dmp").get("id"), datamanagementPlan.getId())).toList())); - dataManagementPlanManager.updateIndex(datamanagementPlan); - return datamanagementPlan.getId(); - } - } else { - UserDMP userDMP = new UserDMP(); - userDMP.setUser(invitedUser); - userDMP.setDmp(invitation.getDmp()); - - if (properties.getRole() != null) { - userDMP.setRole(properties.getRole()); - } else { - userDMP.setRole(UserDMP.UserDMPRoles.USER.getValue()); - } - /*if (!apiContext.getOperationsContext().getDatabaseRepository().getUserAssociationDao().areAssociated(invitedUser, invitation.getUser())) { - UserAssociation userAssociation = new UserAssociation(); - userAssociation.setFirstUser(invitedUser); - userAssociation.setSecondUser(invitation.getUser()); - apiContext.getOperationsContext().getDatabaseRepository().getUserAssociationDao().createOrUpdate(userAssociation); - }*/ - DMP datamanagementPlan = invitation.getDmp(); - apiContext.getOperationsContext().getDatabaseRepository().getUserDmpDao().createOrUpdate(userDMP); - apiContext.getUtilitiesService().getInvitationService().assignToDmp(apiContext.getOperationsContext().getDatabaseRepository().getDmpDao(), userDMP, datamanagementPlan); - invitation.setAcceptedInvitation(true); - apiContext.getOperationsContext().getDatabaseRepository().getInvitationDao().createOrUpdate(invitation); - datamanagementPlan.setUsers(new HashSet<>(apiContext.getOperationsContext().getDatabaseRepository().getUserDmpDao().asQueryable().where((builder, root) -> builder.equal(root.get("dmp").get("id"), datamanagementPlan.getId())).toList())); - dataManagementPlanManager.updateIndex(datamanagementPlan); - return datamanagementPlan.getId(); - } - return invitation.getDmp().getId(); - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/MergeEmailConfirmationManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/MergeEmailConfirmationManager.java deleted file mode 100644 index 40ee1613e..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/MergeEmailConfirmationManager.java +++ /dev/null @@ -1,149 +0,0 @@ -package eu.old.eudat.logic.managers; - -import eu.old.eudat.data.entities.Credential; -import eu.old.eudat.data.entities.EmailConfirmation; -import eu.old.eudat.data.entities.UserDMP; -import eu.old.eudat.data.entities.UserInfo; -import eu.old.eudat.data.entities.UserToken; -import eu.old.eudat.elastic.criteria.DmpCriteria; -import eu.old.eudat.elastic.entities.Collaborator; -import eu.old.eudat.elastic.entities.Dmp; -import eu.old.eudat.elastic.repository.DmpRepository; -import eu.old.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; -import eu.old.eudat.exceptions.emailconfirmation.TokenExpiredException; -import eu.old.eudat.logic.services.ApiContext; -import eu.old.eudat.logic.services.operations.DatabaseRepository; -import eu.old.eudat.models.data.security.Principal; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import jakarta.transaction.Transactional; -import java.io.IOException; -import java.util.*; - -@Component -public class MergeEmailConfirmationManager { - private static Logger logger = LoggerFactory.getLogger(MergeEmailConfirmationManager.class); - private ApiContext apiContext; - private DatabaseRepository databaseRepository; - private DmpRepository dmpRepository; - - @Autowired - public MergeEmailConfirmationManager(ApiContext apiContext) { - this.apiContext = apiContext; - this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); - this.dmpRepository = apiContext.getOperationsContext().getElasticRepository().getDmpRepository(); - } - - @Transactional - public String confirmEmail(String token) throws TokenExpiredException, HasConfirmedEmailException { - EmailConfirmation loginConfirmationEmail = apiContext.getOperationsContext() - .getDatabaseRepository().getLoginConfirmationEmailDao().asQueryable() - .where((builder, root) -> builder.equal(root.get("token"), UUID.fromString(token))).getSingle(); - - if (loginConfirmationEmail.getExpiresAt().compareTo(new Date()) < 0) - throw new TokenExpiredException("Token has expired."); - - UserInfo userToBeMerged = databaseRepository.getUserInfoDao().asQueryable() - .where((builder, root) -> builder.equal(root.get("id"), loginConfirmationEmail.getUserId())).getSingle(); - String userToBeMergedEmail = userToBeMerged.getEmail(); - try { - Map map = new ObjectMapper().readValue(loginConfirmationEmail.getData(), HashMap.class); - UUID otherUserId = UUID.fromString((String) map.get("userId")); - UserInfo user = databaseRepository.getUserInfoDao().asQueryable() - .where((builder, root) -> builder.equal(root.get("id"), otherUserId)).getSingle(); - - // Checks if mail is used by another user. If it is, merges the new the old. - mergeNewUserToOld(user, userToBeMerged, Integer.valueOf((String) map.get("provider"))); - expireUserToken(userToBeMerged); - loginConfirmationEmail.setIsConfirmed(true); - databaseRepository.getLoginConfirmationEmailDao().createOrUpdate(loginConfirmationEmail); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - - return userToBeMergedEmail; - } - - public void sendConfirmationEmail(String email, Principal principal, UUID userId, Integer provider) throws HasConfirmedEmailException { - UserInfo user = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); - - if (user.getEmail() != null && !user.getEmail().equals(email)) { - apiContext.getUtilitiesService().getConfirmationEmailService().createMergeConfirmationEmail( - databaseRepository.getLoginConfirmationEmailDao(), - apiContext.getUtilitiesService().getMailService(), - email, - userId, - principal, - provider - ); - } - } - - @Transactional - private void mergeNewUserToOld(UserInfo newUser, UserInfo oldUser, Integer provider) { - Credential credential = databaseRepository.getCredentialDao().asQueryable().where((builder, root) -> builder.and(builder.equal(root.get("userInfo"), oldUser), builder.equal(root.get("provider"), provider))).getSingle(); - credential.setUserInfo(newUser); - databaseRepository.getCredentialDao().createOrUpdate(credential); - List userDmps = databaseRepository.getUserDmpDao().asQueryable().where((builder, root) -> builder.equal(root.get("user"), oldUser)).toList(); - userDmps.forEach(userDmp -> { - userDmp.setUser(newUser); - databaseRepository.getUserDmpDao().createOrUpdate(userDmp); - }); - try { - DmpCriteria dmpCriteria = new DmpCriteria(); - dmpCriteria.setCollaborators(Collections.singletonList(oldUser.getId())); - List elasticDmpsIds = dmpRepository.query(dmpCriteria); - for(Dmp dmpId: elasticDmpsIds){ - Dmp dmp = dmpRepository.findDocument(dmpId.getId().toString()); - if(dmp.getDatasets() != null) { - dmp.getDatasets().forEach(dataset -> { - if(dataset.getCollaborators() != null) { - for (Collaborator collaborator : dataset.getCollaborators()) { - if (collaborator.getId().equals(oldUser.getId().toString())) { - collaborator.setId(newUser.getId().toString()); - collaborator.setName(newUser.getName()); - } - } - } - }); - } - if(dmp.getCollaborators() != null) { - for (Collaborator collaborator : dmp.getCollaborators()) { - if (collaborator.getId().equals(oldUser.getId().toString())) { - collaborator.setId(newUser.getId().toString()); - collaborator.setName(newUser.getName()); - } - } - } - dmpRepository.createOrUpdate(dmp); - } - } - catch (IOException e){ - logger.warn("Warning: Could not fetch dmps from elastic.", e); - } - oldUser.setUserStatus((short)1); - oldUser.setEmail(null); - List credentials = databaseRepository.getCredentialDao().asQueryable().where((builder, root) -> builder.equal(root.get("userInfo"), oldUser)).toList(); - credentials.forEach(cred -> { - if (cred.getId() != credential.getId()) { - databaseRepository.getCredentialDao().delete(cred); - } - }); - databaseRepository.getUserInfoDao().createOrUpdate(oldUser); - } - - private void expireUserToken(UserInfo user) { - UserToken userToken = databaseRepository.getUserTokenDao().asQueryable() - .where((builder, root) -> builder.equal(root.get("user"), user)) - .orderBy((builder, root) -> builder.desc(root.get("issuedAt"))) - .take(1).toList().get(0); - userToken.setExpiresAt(new Date()); - databaseRepository.getUserTokenDao().createOrUpdate(userToken); - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/NotificationManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/NotificationManager.java deleted file mode 100644 index d57cdd9c2..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/NotificationManager.java +++ /dev/null @@ -1,124 +0,0 @@ -package eu.old.eudat.logic.managers; - -import com.fasterxml.jackson.databind.ObjectMapper; -import eu.old.eudat.data.entities.Notification; -import eu.old.eudat.data.entities.UserInfo; -import eu.old.eudat.data.enumeration.notification.ActiveStatus; -import eu.old.eudat.data.enumeration.notification.NotifyState; -import eu.old.eudat.logic.services.ApiContext; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.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 jakarta.mail.MessagingException; -import jakarta.transaction.Transactional; -import java.io.IOException; -import java.util.*; - -@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 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("notification.modified.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.modified.template")); - break; - case DMP_PUBLISH: - subjectTemplate = this.environment.getProperty("notification.publish.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.publish.template")); - break; - case DMP_FINALISED: - subjectTemplate = this.environment.getProperty("notification.finalised.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.finalised.template")); - break; - case DMP_MODIFIED_FINALISED: - case DATASET_MODIFIED_FINALISED: - subjectTemplate = this.environment.getProperty("notification.modifiedFinalised.subject"); - contentTemplate = mailService.getMailTemplateContent(this.environment.getProperty("notification.modified_finalised.template")); - break; - } - - - switch (notification.getContactTypeHint()) { - case EMAIL: - this.sendEmailNotification(notification, userInfo, data, subjectTemplate, contentTemplate); - 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 data, String subjectTemplate, String contentTemplate) throws IOException { - 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); - notification.setNotifyState(NotifyState.SUCCEEDED); - notification.setUpdatedAt(new Date()); - } catch (MessagingException e) { - notification.setNotifyState(NotifyState.ERROR); - notification.setUpdatedAt(new Date()); - logger.error(e.getMessage(), e); - } - } - - private String makeSubject(Map data, String subjectTemplate) { - return subjectTemplate.replace("{name}", data.get("name")); - } - - private String makeContent(Map data, Notification notification, UserInfo userInfo, String template) { - String content = template; - content = content.replace("{recipient}", userInfo.getName()); - for (String key : data.keySet()) { - content = content.replace("{" + key +"}", data.get(key)); - } - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - content = content.replace("{reasonName}", notification.getUserId().getName()); - return content; - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/UnlinkEmailConfirmationManager.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/UnlinkEmailConfirmationManager.java deleted file mode 100644 index 5a0f9e33d..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/managers/UnlinkEmailConfirmationManager.java +++ /dev/null @@ -1,89 +0,0 @@ -package eu.old.eudat.logic.managers; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import eu.old.eudat.data.entities.Credential; -import eu.old.eudat.data.entities.EmailConfirmation; -import eu.old.eudat.data.entities.UserInfo; -import eu.old.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; -import eu.old.eudat.exceptions.emailconfirmation.TokenExpiredException; -import eu.old.eudat.logic.services.ApiContext; -import eu.old.eudat.logic.services.operations.DatabaseRepository; -import eu.old.eudat.models.data.security.Principal; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import jakarta.transaction.Transactional; - -import java.util.*; - -@Component -public class UnlinkEmailConfirmationManager { - - private static Logger logger = LoggerFactory.getLogger(UnlinkEmailConfirmationManager.class); - - private ApiContext apiContext; - private DatabaseRepository databaseRepository; - - @Autowired - public UnlinkEmailConfirmationManager(ApiContext apiContext) { - this.apiContext = apiContext; - this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); - } - - @Transactional - public void confirmEmail(String token) throws TokenExpiredException, HasConfirmedEmailException { - EmailConfirmation loginConfirmationEmail = apiContext.getOperationsContext() - .getDatabaseRepository().getLoginConfirmationEmailDao().asQueryable() - .where((builder, root) -> builder.equal(root.get("token"), UUID.fromString(token))).getSingle(); - - if (loginConfirmationEmail.getExpiresAt().compareTo(new Date()) < 0) - throw new TokenExpiredException("Token has expired."); - - if(loginConfirmationEmail.getIsConfirmed()) - throw new HasConfirmedEmailException("Email is already confirmed."); - -// UserInfo userAskingForUnlink = databaseRepository.getUserInfoDao().asQueryable() -// .where((builder, root) -> builder.equal(root.get("id"), loginConfirmationEmail.getUserId())).getSingle(); - - try { - Map map = new ObjectMapper().readValue(loginConfirmationEmail.getData(), new TypeReference>() {}); - String emailTobeUnlinked = (String) map.get("email"); - Integer provider = Integer.valueOf((String) map.get("provider")); - - unlinkUser(emailTobeUnlinked, provider); - - loginConfirmationEmail.setIsConfirmed(true); - databaseRepository.getLoginConfirmationEmailDao().createOrUpdate(loginConfirmationEmail); - } - catch (Exception e) { - logger.error(e.getMessage(), e); - } - } - - @Transactional - private void unlinkUser(String emailTobeUnlinked, Integer provider){ - Credential credential = databaseRepository.getCredentialDao().asQueryable() - .where((builder, root) -> builder.and(builder.equal(root.get("email"), emailTobeUnlinked), builder.equal(root.get("provider"), provider))).getSingle(); - if(credential != null) { - databaseRepository.getCredentialDao().delete(credential); - } - } - - public void sendConfirmationEmail(String email, Principal principal, UUID userId, Integer provider) { - UserInfo user = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); - - if (user.getEmail() != null && !user.getEmail().equals(email)) { - apiContext.getUtilitiesService().getConfirmationEmailService().createUnlinkConfirmationEmail( - databaseRepository.getLoginConfirmationEmailDao(), - apiContext.getUtilitiesService().getMailService(), - email, - userId, - principal, - provider - ); - } - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContext.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContext.java index 2d339ef86..f294d21c7 100644 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContext.java +++ b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContext.java @@ -2,13 +2,10 @@ package eu.old.eudat.logic.services; import eu.old.eudat.logic.services.helpers.HelpersService; import eu.old.eudat.logic.services.operations.OperationsContext; -import eu.old.eudat.logic.services.utilities.UtilitiesService; public interface ApiContext { HelpersService getHelpersService(); OperationsContext getOperationsContext(); - - UtilitiesService getUtilitiesService(); } diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContextImpl.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContextImpl.java index bdde904d7..638781deb 100644 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContextImpl.java +++ b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/ApiContextImpl.java @@ -2,7 +2,6 @@ package eu.old.eudat.logic.services; import eu.old.eudat.logic.services.helpers.HelpersService; import eu.old.eudat.logic.services.operations.OperationsContext; -import eu.old.eudat.logic.services.utilities.UtilitiesService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -12,13 +11,11 @@ public class ApiContextImpl implements ApiContext { private OperationsContext operationsContext; private HelpersService helpersService; - private UtilitiesService utilitiesService; @Autowired - public ApiContextImpl(OperationsContext operationsContext, HelpersService helpersService, UtilitiesService utilitiesService) { + public ApiContextImpl(OperationsContext operationsContext, HelpersService helpersService) { this.operationsContext = operationsContext; this.helpersService = helpersService; - this.utilitiesService = utilitiesService; } @Override @@ -30,9 +27,4 @@ public class ApiContextImpl implements ApiContext { public HelpersService getHelpersService() { return helpersService; } - - @Override - public UtilitiesService getUtilitiesService() { - return utilitiesService; - } } diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/ConfirmationEmailService.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/ConfirmationEmailService.java deleted file mode 100644 index f7e80a8a1..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/ConfirmationEmailService.java +++ /dev/null @@ -1,23 +0,0 @@ -package eu.old.eudat.logic.services.utilities; - -import eu.old.eudat.data.dao.entities.EmailConfirmationDao; -import eu.old.eudat.data.entities.EmailConfirmation; -import eu.old.eudat.models.data.security.Principal; -import eu.eudat.service.mail.MailService; - -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public interface ConfirmationEmailService { - public void createConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UUID userId); - - public void createMergeConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UUID userId, Principal principal, Integer provider); - - public void createUnlinkConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UUID userId, Principal principal, Integer provider); - - public CompletableFuture sentConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService); - - public CompletableFuture sentMergeConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService, String userName); - - public CompletableFuture sentUnlinkConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService); -} \ No newline at end of file diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java deleted file mode 100644 index 61bb883c7..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package eu.old.eudat.logic.services.utilities; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import eu.old.eudat.data.dao.entities.EmailConfirmationDao; -import eu.old.eudat.data.entities.EmailConfirmation; -import eu.old.eudat.models.data.security.Principal; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.mail.SimpleMail; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Service; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -@Service("ConfirmationEmailService") -public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { - private static final Logger logger = LoggerFactory.getLogger(ConfirmationEmailServiceImpl.class); - //private Logger logger; - private Environment environment; - - public ConfirmationEmailServiceImpl(/*Logger logger,*/ Environment environment) { -// this.logger = logger; - this.environment = environment; - } - - @Override - public void createConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, String email, UUID userId) { - EmailConfirmation confirmationEmail = new EmailConfirmation(); - confirmationEmail.setEmail(email); - confirmationEmail.setExpiresAt(Date - .from(new Date() - .toInstant() - .plusSeconds(Long.parseLong(this.environment.getProperty("conf_email.expiration_time_seconds"))) - ) - ); - confirmationEmail.setUserId(userId); - confirmationEmail.setIsConfirmed(false); - confirmationEmail.setToken(UUID.randomUUID()); - confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); - sentConfirmationEmail(confirmationEmail, mailService); - } - - @Override - public CompletableFuture sentConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService) { - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("conf_email.subject")); - mail.setContent(createContent(confirmationEmail.getToken(), mailService)); - mail.setTo(confirmationEmail.getEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - private String createContent(UUID confirmationToken, MailService mailService) { - String content = mailService.getMailTemplateContent(this.environment.getProperty("email.confirmation")); - content = content.replace("{confirmationToken}", confirmationToken.toString()); - content = content.replace("{expiration_time}", secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds")))); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - - return content; - } - - @Override - public CompletableFuture sentMergeConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService, String userName) { - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("conf_email.subject")); - mail.setContent(createMergeContent(confirmationEmail.getToken(), mailService, userName)); - mail.setTo(confirmationEmail.getEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - @Override - public CompletableFuture sentUnlinkConfirmationEmail(EmailConfirmation confirmationEmail, MailService mailService) { - String email = null; - try { - Map map = new ObjectMapper().readValue(confirmationEmail.getData(), new TypeReference>() {}); - email = (String) map.get("email"); - } - catch (JsonProcessingException e){ - logger.error(e.getMessage(), e); - } - String finalEmail = email; - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(environment.getProperty("conf_email.subject")); - mail.setContent(createUnlinkContent(confirmationEmail.getToken(), mailService, finalEmail)); - mail.setTo(confirmationEmail.getEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - private String createMergeContent(UUID confirmationToken, MailService mailService, String userName) { - String content = mailService.getMailTemplateContent(this.environment.getProperty("email.merge")); - content = content.replace("{userName}", userName); - content = content.replace("{confirmationToken}", confirmationToken.toString()); - content = content.replace("{expiration_time}", secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds")))); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - - return content; - } - - private String createUnlinkContent(UUID confirmationToken, MailService mailService, String email) { - String content = mailService.getMailTemplateContent(this.environment.getProperty("email.unlink")); - content = content.replace("{confirmationToken}", confirmationToken.toString()); - content = content.replace("{expiration_time}", secondsToTime(Integer.parseInt(this.environment.getProperty("conf_email.expiration_time_seconds")))); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - content = content.replace("{email}", email); - - return content; - } - - private String secondsToTime(int seconds) { - int sec = seconds % 60; - int hour = seconds / 60; - int min = hour % 60; - hour = hour / 60; - return (hour + ":" + min + ":" + sec); - } - - @Override - public void createMergeConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, - String email, UUID userId, Principal principal, Integer provider) { - EmailConfirmation confirmationEmail = new EmailConfirmation(); - confirmationEmail.setEmail(email); - confirmationEmail.setExpiresAt(Date - .from(new Date() - .toInstant() - .plusSeconds(Long.parseLong(this.environment.getProperty("conf_email.expiration_time_seconds"))) - ) - ); - confirmationEmail.setUserId(userId); - try { - Map map = new HashMap<>(); - map.put("userId", principal.getId()); - map.put("provider", provider.toString()); - confirmationEmail.setData(new ObjectMapper().writeValueAsString(map)); - } catch (JsonProcessingException e) { - logger.error(e.getMessage(), e); - } - confirmationEmail.setIsConfirmed(false); - confirmationEmail.setToken(UUID.randomUUID()); - confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); - sentMergeConfirmationEmail(confirmationEmail, mailService, principal.getName()); - - } - - @Override - public void createUnlinkConfirmationEmail(EmailConfirmationDao loginConfirmationEmailDao, MailService mailService, - String email, UUID userId, Principal principal, Integer provider) { - EmailConfirmation confirmationEmail = new EmailConfirmation(); - confirmationEmail.setEmail(principal.getEmail()); - confirmationEmail.setExpiresAt(Date - .from(new Date() - .toInstant() - .plusSeconds(Long.parseLong(this.environment.getProperty("conf_email.expiration_time_seconds"))) - ) - ); - confirmationEmail.setUserId(userId); - try { - Map map = new HashMap<>(); - map.put("email", email); - map.put("provider", provider.toString()); - confirmationEmail.setData(new ObjectMapper().writeValueAsString(map)); - } catch (JsonProcessingException e) { - logger.error(e.getMessage(), e); - } - confirmationEmail.setIsConfirmed(false); - confirmationEmail.setToken(UUID.randomUUID()); - confirmationEmail = loginConfirmationEmailDao.createOrUpdate(confirmationEmail); - sentUnlinkConfirmationEmail(confirmationEmail, mailService); - } -} \ No newline at end of file diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/InvitationService.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/InvitationService.java deleted file mode 100644 index b7a3a1d6c..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/InvitationService.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.old.eudat.logic.services.utilities; - - -import eu.old.eudat.data.dao.entities.DMPDao; -import eu.old.eudat.data.dao.entities.InvitationDao; -import eu.old.eudat.data.entities.DMP; -import eu.old.eudat.data.entities.Invitation; - -import eu.eudat.service.mail.MailService; -import eu.old.eudat.data.entities.UserDMP; -import eu.old.eudat.data.entities.UserInfo; -import jakarta.mail.MessagingException; -import java.util.List; -import java.util.concurrent.CompletableFuture; - - -public interface InvitationService { - void assignToDmp(DMPDao dmpDao, List users, DMP dmp); - - void assignToDmp(DMPDao dmpDao, UserDMP user, DMP dmp); - - void createInvitations(InvitationDao invitationDao, MailService mailService, List users, DMP dmp, Integer role, UserInfo creator) throws MessagingException; - - CompletableFuture sendInvitationAsync(DMP dmp, Invitation invitation, String recipient, MailService mailService, Integer role) throws MessagingException; -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/InvitationServiceImpl.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/InvitationServiceImpl.java deleted file mode 100644 index 298ec2804..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/InvitationServiceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -package eu.old.eudat.logic.services.utilities; - - -import eu.old.eudat.data.dao.entities.DMPDao; -import eu.old.eudat.data.dao.entities.InvitationDao; -import eu.old.eudat.data.entities.DMP; -import eu.old.eudat.data.entities.Invitation; -import eu.old.eudat.data.entities.UserDMP; -import eu.old.eudat.data.entities.UserInfo; -import eu.old.eudat.models.data.invitation.Properties; -import eu.eudat.service.mail.MailService; -import eu.eudat.service.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.Service; - -import jakarta.mail.MessagingException; -import jakarta.xml.bind.JAXBContext; -import jakarta.xml.bind.Marshaller; -import java.io.StringWriter; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; - - -@Service("invitationService") -public class InvitationServiceImpl implements InvitationService { - private static final Logger logger = LoggerFactory.getLogger(InvitationServiceImpl.class); - private Environment environment; - - @Autowired - public InvitationServiceImpl(Environment environment) { - this.environment = environment; - } - - @Override - public void assignToDmp(DMPDao dmpDao, List users, DMP dmp) { - for (UserDMP user : users) { - dmp.getUsers().add(user); - } - dmpDao.createOrUpdate(dmp); - } - - @Override - public void assignToDmp(DMPDao dmpDao, UserDMP user, DMP dmp) { - if (!dmp.getUsers().stream().map(x -> x.getUser().getId()).collect(Collectors.toList()).contains(user.getId())) { - dmp.getUsers().add(user); - dmpDao.createOrUpdate(dmp); - } - } - - @Override - public void createInvitations(InvitationDao invitationDao, MailService mailService, List users, DMP dmp, Integer role, UserInfo creator) throws MessagingException { - for (UserInfo userInfo : users) { - Invitation invitation = new Invitation(); - invitation.setDmp(dmp); - invitation.setInvitationEmail(userInfo.getEmail()); - invitation.setUser(creator); - invitation.setToken(UUID.randomUUID()); - invitation.setAcceptedInvitation(false); - Properties properties = new Properties(); - properties.setRole(role); - try { - JAXBContext context = JAXBContext.newInstance(Properties.class); - Marshaller marshaller = context.createMarshaller(); - StringWriter propertyWriter = new StringWriter(); - marshaller.marshal(properties, propertyWriter); - invitation.setProperties(propertyWriter.toString()); - }catch (Exception e) { - logger.error(e.getMessage(), e); - } - invitationDao.createOrUpdate(invitation); - sendInvitationAsync(dmp, invitation, userInfo.getName(), mailService, role); - } - } - - @Override - public CompletableFuture sendInvitationAsync(DMP dmp, Invitation invitation, String recipient, MailService mailService, Integer role) { - return CompletableFuture.runAsync(() -> { - SimpleMail mail = new SimpleMail(); - mail.setSubject(createSubject(dmp, mailService.getMailTemplateSubject())); - mail.setContent(createContent(invitation.getId(), dmp, recipient, mailService.getMailTemplateContent(this.environment.getProperty("email.invite")), role)); - mail.setTo(invitation.getInvitationEmail()); - try { - mailService.sendSimpleMail(mail); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - } - }); - } - - private String createSubject(DMP dmp, String templateSubject) { - String subject = templateSubject.replace("{dmpname}", dmp.getLabel()); - return subject; - } - - private String createContent(UUID invitationID, DMP dmp, String recipient, String templateContent, Integer role) { - String content = templateContent.replace("{dmpname}", dmp.getLabel()); - content = content.replace("{invitationID}", invitationID.toString()); - content = content.replace("{recipient}", recipient); - content = content.replace("{host}", this.environment.getProperty("dmp.domain")); - content = content.replace("{dmprole}", UserDMP.UserDMPRoles.fromInteger(role).name()); - - return content; - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/UtilitiesService.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/UtilitiesService.java deleted file mode 100644 index b4b7c97a8..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/UtilitiesService.java +++ /dev/null @@ -1,15 +0,0 @@ -package eu.old.eudat.logic.services.utilities; - -import eu.eudat.service.mail.MailService; - -/** - * Created by ikalyvas on 3/1/2018. - */ -public interface UtilitiesService { - - InvitationService getInvitationService(); - - MailService getMailService(); - - ConfirmationEmailService getConfirmationEmailService(); -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/UtilitiesServiceImpl.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/UtilitiesServiceImpl.java deleted file mode 100644 index 0f395205f..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/services/utilities/UtilitiesServiceImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package eu.old.eudat.logic.services.utilities; - -import eu.eudat.service.mail.MailService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * Created by ikalyvas on 3/1/2018. - */ -@Service("utilitiesService") -public class UtilitiesServiceImpl implements UtilitiesService { - - private InvitationService invitationService; - private MailService mailService; - private ConfirmationEmailService confirmationEmailService; - - @Autowired - public UtilitiesServiceImpl(InvitationService invitationService, MailService mailService, ConfirmationEmailService confirmationEmailService) { - this.invitationService = invitationService; - this.mailService = mailService; - this.confirmationEmailService = confirmationEmailService; - } - - @Override - public ConfirmationEmailService getConfirmationEmailService() { - return confirmationEmailService; - } - - @Override - public InvitationService getInvitationService() { - return invitationService; - } - - @Override - public MailService getMailService() { - return mailService; - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/utilities/schedule/notification/NotificationScheduleJob.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/utilities/schedule/notification/NotificationScheduleJob.java deleted file mode 100644 index b1b84099d..000000000 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/logic/utilities/schedule/notification/NotificationScheduleJob.java +++ /dev/null @@ -1,57 +0,0 @@ -package eu.old.eudat.logic.utilities.schedule.notification; - -import eu.old.eudat.data.entities.Notification; -import eu.old.eudat.data.enumeration.notification.ActiveStatus; -import eu.old.eudat.data.enumeration.notification.NotifyState; -import eu.old.eudat.logic.managers.NotificationManager; -import eu.old.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 jakarta.transaction.Transactional; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -@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> futures = new LinkedList<>(); - 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)))).toListAsync().thenApplyAsync((notifications) -> { - if (!notifications.isEmpty()) { - notifications.forEach(notification -> { - try { - this.notificationManager.sendNotification(notification); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - }); - } - return notifications; - }).thenApplyAsync((notifications) -> { - notifications.forEach((notification) -> futures.add(this.apiContext.getOperationsContext().getDatabaseRepository().getNotificationDao().createOrUpdateAsync(notification))); - return futures; - }).join(); - - } -} diff --git a/dmp-migration-tool/web/src/main/java/eu/old/eudat/migration/DmpUserMigrationService.java b/dmp-migration-tool/web/src/main/java/eu/old/eudat/migration/DmpUserMigrationService.java index 2731a3eee..bd64d37a5 100644 --- a/dmp-migration-tool/web/src/main/java/eu/old/eudat/migration/DmpUserMigrationService.java +++ b/dmp-migration-tool/web/src/main/java/eu/old/eudat/migration/DmpUserMigrationService.java @@ -48,7 +48,7 @@ public class DmpUserMigrationService { DmpUserEntity data = new DmpUserEntity(); data.setId(item.getId()); - data.setDmp(item.getDmp().getId()); + data.setDmpId(item.getDmp().getId()); data.setUserId(item.getUser().getId()); data.setRole(DmpUserRole.of(item.getRole().shortValue())); data.setCreatedAt(item.getDmp().getCreated() != null ? item.getDmp().getCreated().toInstant() : Instant.now());