inapp notification changes

This commit is contained in:
amentis 2024-01-08 18:29:23 +02:00
parent 3fc04a1e3a
commit c36aff22e8
11 changed files with 418 additions and 70 deletions

View File

@ -70,7 +70,7 @@ public class NotificationIntegrationEventHandlerImpl implements NotificationInte
persist.setContactTypeHint(event.getContactTypeHint());
persist.setData(event.getData());
persist.setNotifyState(NotificationNotifyState.PENDING);
persist.setNotifiedWith(NotificationContactType.EMAIL);
persist.setNotifiedWith(event.getContactTypeHint());
persist.setRetryCount(0);
persist.setTrackingState(NotificationTrackingState.UNDEFINED);
persist.setTrackingProcess(NotificationTrackingProcess.PENDING);

View File

@ -39,7 +39,7 @@ import javax.transaction.Transactional;
import java.util.*;
@RestController
@RequestMapping(path = "api/notification/inapp-notification")
@RequestMapping(path = "api/inapp-notification")
public class InAppNotificationController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(InAppNotificationController.class));

View File

@ -16,7 +16,7 @@ notification:
contacts: [ email ]
- #dmpInvitationExistingUser
type: 4904dea2-5079-46d3-83be-3a19c9ab45dc
contacts: [ email ]
contacts: [ inapp, email ]
- #dpmModified
type: 4542262A-22F8-4BAA-9DB6-1C8E70AC1DBB
contacts: [ email ]
@ -314,6 +314,30 @@ notification:
template-cache:
prefix: ${CACHE_DISAMBIGUATION:}
key-pattern: "{prefix}:Notification_Message_Email_Template:{key}:v0"
in-app:
flows:
- #dmpInvitationExistingUser
key: 4904dea2-5079-46d3-83be-3a19c9ab45dc
subject-path: classpath:notification_templates/dmpinvitationexistinguser/inapp/subject.{language}.txt
subject-field-options:
mandatory: [ ]
optional: [ ]
body-path: classpath:notification_templates/dmpinvitationexistinguser/inapp/body.{language}.html
body-field-options:
mandatory: [ "{dmpname}", "{dmprole}", "{reasonName}", "{installation-url}", "{id}" ]
optional:
- key: "{recipient}"
value:
formatting:
'[{dmpname}]': null
'[{dmprole}]': null
'[{reasonName}]': null
'[{recipient}]': null
priority-key: null
cipher-fields: [ ]
template-cache:
prefix: ${CACHE_DISAMBIGUATION:}
key-pattern: "{prefix}:Notification_Message_InApp_Template:{key}:v0"
override-cache:
template-cache:
prefix: ${CACHE_DISAMBIGUATION:}

View File

@ -75,15 +75,13 @@ permissions:
#Notification
BrowseNotification:
roles:
- ic-sti-superuser
- user
- Admin
clients: [ ]
allowAnonymous: true
allowAuthenticated: false
EditNotification:
roles:
- ic-sti-superuser
- user
- Admin
clients: [ ]
allowAnonymous: true
allowAuthenticated: false

View File

@ -0,0 +1,304 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Simple Transactional Email</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%; }
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%; }
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%; }
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top; }
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%; }
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px; }
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px; }
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%; }
.wrapper {
box-sizing: border-box;
padding: 20px; }
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%; }
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center; }
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px; }
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize; }
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px; }
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px; }
a {
color: #3498db;
text-decoration: underline; }
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%; }
.btn > tbody > tr > td {
padding-bottom: 15px; }
.btn table {
width: auto; }
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center; }
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize; }
.btn-primary table td {
background-color: #3498db; }
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff; }
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0; }
.first {
margin-top: 0; }
.align-center {
text-align: center; }
.align-right {
text-align: right; }
.align-left {
text-align: left; }
.clear {
clear: both; }
.mt0 {
margin-top: 0; }
.mb0 {
margin-bottom: 0; }
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0; }
.powered-by a {
text-decoration: none; }
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0; }
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important; }
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important; }
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important; }
table[class=body] .content {
padding: 0 !important; }
table[class=body] .container {
padding: 0 !important;
width: 100% !important; }
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important; }
table[class=body] .btn table {
width: 100% !important; }
table[class=body] .btn a {
width: 100% !important; }
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important; }}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%; }
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%; }
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important; }
.btn-primary table td:hover {
background-color: #34495e !important; }
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important; } }
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p>Dear {recipient},</p>
<p>{reasonName} just add you to collaborate to Data Management plan {dmpname} with role {dmprole}.</p>
<p>Click the button to redirect to {dmpname}.</p>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td> <a href="{installation-url}/plans/edit/{id}" target="_blank">Join</a> </td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- START FOOTER -->
<div class="footer">
</div>
<!-- END FOOTER -->
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -16,7 +16,7 @@ notification:
contacts: [ email ]
- #dmpInvitationExistingUser
type: 4904dea2-5079-46d3-83be-3a19c9ab45dc
contacts: [ email ]
contacts: [ inapp, email ]
- #dpmModified
type: 4542262A-22F8-4BAA-9DB6-1C8E70AC1DBB
contacts: [ email ]
@ -314,6 +314,30 @@ notification:
template-cache:
prefix: ${CACHE_DISAMBIGUATION:}
key-pattern: "{prefix}:Notification_Message_Email_Template:{key}:v0"
in-app:
flows:
- #dmpInvitationExistingUser
key: 4904dea2-5079-46d3-83be-3a19c9ab45dc
subject-path: classpath:notification_templates/dmpinvitationexistinguser/inapp/subject.{language}.txt
subject-field-options:
mandatory: [ ]
optional: [ ]
body-path: classpath:notification_templates/dmpinvitationexistinguser/inapp/body.{language}.html
body-field-options:
mandatory: [ "{dmpname}", "{dmprole}", "{reasonName}", "{installation-url}", "{id}" ]
optional:
- key: "{recipient}"
value:
formatting:
'[{dmpname}]': null
'[{dmprole}]': null
'[{reasonName}]': null
'[{recipient}]': null
priority-key: null
cipher-fields: [ ]
template-cache:
prefix: ${CACHE_DISAMBIGUATION:}
key-pattern: "{prefix}:Notification_Message_InApp_Template:{key}:v0"
override-cache:
template-cache:
prefix: ${CACHE_DISAMBIGUATION:}

View File

@ -75,15 +75,13 @@ permissions:
#Notification
BrowseNotification:
roles:
- ic-sti-superuser
- user
- Admin
clients: [ ]
allowAnonymous: true
allowAuthenticated: false
EditNotification:
roles:
- ic-sti-superuser
- user
- Admin
clients: [ ]
allowAnonymous: true
allowAuthenticated: false

View File

@ -16,58 +16,57 @@ import java.util.UUID;
@Table(name = "\"ntf_InAppNotification\"")
public class InAppNotificationEntity extends TenantScopedBaseEntity {
public static class Field {
public static final String ID = "id";
public static final String USER_ID = "userId";
public static final String IS_ACTIVE = "isActive";
public static final String TYPE = "type";
public static final String READ_TIME = "readTime";
public static final String TRACKING_STATE = "trackingState";
public static final String PRIORITY = "priority";
public static final String SUBJECT = "subject";
public static final String BODY = "body";
public static final String EXTRA_DATA = "extraData";
public static final String CREATED_AT = "createdAt";
public static final String UPDATED_AT = "updatedAt";
public static final String _id = "id";
public static final String _userId = "userId";
public static final String _isActive = "isActive";
public static final String _type = "type";
public static final String _readTime = "readTime";
public static final String _trackingState = "trackingState";
public static final String _priority = "priority";
public static final String _subject = "subject";
public static final String _body = "body";
public static final String _extraData = "extraData";
public static final String _createdAt = "createdAt";
public static final String _updatedAt = "updatedAt";
}
@Id
@Column(name = "id", columnDefinition = "uuid", nullable = false)
@Column(name = "\"id\"", columnDefinition = "uuid", nullable = false)
private UUID id;
@Column(name = "user", columnDefinition = "uuid", nullable = false)
@Column(name = "\"user\"", columnDefinition = "uuid", nullable = false)
private UUID userId;
@Column(name = "is_active", nullable = false)
@Column(name = "\"is_active\"", nullable = false)
@Convert(converter = IsActiveConverter.class)
private IsActive isActive;
@Column(name = "type", columnDefinition = "uuid", nullable = false)
@Column(name = "\"type\"", columnDefinition = "uuid", nullable = false)
private UUID type;
@Column(name = "read_time")
@Column(name = "\"read_time\"")
private Instant readTime;
@Column(name = "tracking_state", nullable = false)
@Column(name = "\"tracking_state\"", nullable = false)
@Convert(converter = NotificationInAppTrackingConverter.class)
private NotificationInAppTracking trackingState;
@Column(name = "priority", nullable = false)
@Column(name = "\"priority\"", nullable = false)
@Convert(converter = InAppNotificationPriorityConverter.class)
private InAppNotificationPriority priority;
@Column(name = "subject")
@Column(name = "\"subject\"")
private String subject;
@Column(name = "body")
@Column(name = "\"body\"")
private String body;
@Column(name = "extra_data")
@Column(name = "\"extra_data\"")
private String extraData;
@Column(name = "created_at", nullable = false)
@Column(name = "\"created_at\"", nullable = false)
private Instant createdAt;
@Column(name = "updated_at", nullable = false)
@Column(name = "\"updated_at\"", nullable = false)
@Version
private Instant updatedAt;

View File

@ -161,19 +161,19 @@ public class InAppNotificationQuery extends QueryBase<InAppNotificationEntity> {
protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) {
List<Predicate> predicates = new ArrayList<>();
if (this.ids != null) {
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field.ID).in(ids));
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field._id).in(ids));
}
if (this.excludeIds != null) {
predicates.add(queryContext.CriteriaBuilder.not(queryContext.Root.get(InAppNotificationEntity.Field.ID).in(ids)));
predicates.add(queryContext.CriteriaBuilder.not(queryContext.Root.get(InAppNotificationEntity.Field._id).in(ids)));
}
if (this.userId != null) {
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field.USER_ID).in(userId));
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field._userId).in(userId));
}
if (this.isActives != null) {
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field.IS_ACTIVE).in(isActives));
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field._isActive).in(isActives));
}
if (this.tenantIds != null) {
@ -181,23 +181,23 @@ public class InAppNotificationQuery extends QueryBase<InAppNotificationEntity> {
}
if (this.type != null) {
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field.TYPE).in(this.type));
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field._type).in(this.type));
}
if (this.trackingState != null) {
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field.TRACKING_STATE).in(trackingState));
predicates.add(queryContext.Root.get(InAppNotificationEntity.Field._trackingState).in(trackingState));
}
if (isRead != null) {
predicates.add(isRead ? queryContext.CriteriaBuilder.isNotNull(queryContext.Root.get(InAppNotificationEntity.Field.READ_TIME)) : queryContext.CriteriaBuilder.isNull(queryContext.Root.get(InAppNotificationEntity.Field.READ_TIME)));
predicates.add(isRead ? queryContext.CriteriaBuilder.isNotNull(queryContext.Root.get(InAppNotificationEntity.Field._readTime)) : queryContext.CriteriaBuilder.isNull(queryContext.Root.get(InAppNotificationEntity.Field._readTime)));
}
if (from != null) {
predicates.add(queryContext.CriteriaBuilder.greaterThanOrEqualTo(queryContext.Root.get(InAppNotificationEntity.Field.CREATED_AT), from));
predicates.add(queryContext.CriteriaBuilder.greaterThanOrEqualTo(queryContext.Root.get(InAppNotificationEntity.Field._createdAt), from));
}
if (to != null) {
predicates.add(queryContext.CriteriaBuilder.lessThanOrEqualTo(queryContext.Root.get(InAppNotificationEntity.Field.CREATED_AT), from));
predicates.add(queryContext.CriteriaBuilder.lessThanOrEqualTo(queryContext.Root.get(InAppNotificationEntity.Field._createdAt), from));
}
if (predicates.size() > 0) {
@ -211,37 +211,37 @@ public class InAppNotificationQuery extends QueryBase<InAppNotificationEntity> {
@Override
protected String fieldNameOf(FieldResolver item) {
if (item.match(InAppNotification.Field.ID)) return InAppNotificationEntity.Field.ID;
else if (item.match(InAppNotification.Field.CREATED_AT)) return InAppNotificationEntity.Field.CREATED_AT;
else if (item.match(InAppNotification.Field.USER)) return InAppNotificationEntity.Field.USER_ID;
else if (item.match(InAppNotification.Field.IS_ACTIVE)) return InAppNotificationEntity.Field.IS_ACTIVE;
else if (item.match(InAppNotification.Field.READ_TIME)) return InAppNotificationEntity.Field.READ_TIME;
else if (item.match(InAppNotification.Field.TRACKING_STATE)) return InAppNotificationEntity.Field.TRACKING_STATE;
else if (item.match(InAppNotification.Field.BODY)) return InAppNotificationEntity.Field.BODY;
else if (item.match(InAppNotification.Field.EXTRA_DATA)) return InAppNotificationEntity.Field.EXTRA_DATA;
else if (item.match(InAppNotification.Field.PRIORITY)) return InAppNotificationEntity.Field.PRIORITY;
else if (item.match(InAppNotification.Field.SUBJECT)) return InAppNotificationEntity.Field.SUBJECT;
if (item.match(InAppNotification.Field.ID)) return InAppNotificationEntity.Field._id;
else if (item.match(InAppNotification.Field.CREATED_AT)) return InAppNotificationEntity.Field._createdAt;
else if (item.match(InAppNotification.Field.USER)) return InAppNotificationEntity.Field._userId;
else if (item.match(InAppNotification.Field.IS_ACTIVE)) return InAppNotificationEntity.Field._isActive;
else if (item.match(InAppNotification.Field.READ_TIME)) return InAppNotificationEntity.Field._readTime;
else if (item.match(InAppNotification.Field.TRACKING_STATE)) return InAppNotificationEntity.Field._trackingState;
else if (item.match(InAppNotification.Field.BODY)) return InAppNotificationEntity.Field._body;
else if (item.match(InAppNotification.Field.EXTRA_DATA)) return InAppNotificationEntity.Field._extraData;
else if (item.match(InAppNotification.Field.PRIORITY)) return InAppNotificationEntity.Field._priority;
else if (item.match(InAppNotification.Field.SUBJECT)) return InAppNotificationEntity.Field._subject;
else if (item.match(InAppNotification.Field.TENANT)) return InAppNotificationEntity._tenantId;
else if (item.match(InAppNotification.Field.TYPE)) return InAppNotificationEntity.Field.TYPE;
else if (item.match(InAppNotification.Field.UPDATED_AT)) return InAppNotificationEntity.Field.UPDATED_AT;
else if (item.match(InAppNotification.Field.TYPE)) return InAppNotificationEntity.Field._type;
else if (item.match(InAppNotification.Field.UPDATED_AT)) return InAppNotificationEntity.Field._updatedAt;
else return null;
}
@Override
protected InAppNotificationEntity convert(Tuple tuple, Set<String> columns) {
InAppNotificationEntity item = new InAppNotificationEntity();
item.setId(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.ID, UUID.class));
item.setType(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.TYPE, UUID.class));
item.setUserId(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.USER_ID, UUID.class));
item.setId(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._id, UUID.class));
item.setType(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._type, UUID.class));
item.setUserId(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._userId, UUID.class));
item.setTenantId(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity._tenantId, UUID.class));
item.setTrackingState(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.TRACKING_STATE, NotificationInAppTracking.class));
item.setCreatedAt(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.CREATED_AT, Instant.class));
item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.UPDATED_AT, Instant.class));
item.setIsActive(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.IS_ACTIVE, IsActive.class));
item.setExtraData(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.EXTRA_DATA, String.class));
item.setBody(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.BODY, String.class));
item.setSubject(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.SUBJECT, String.class));
item.setPriority(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field.PRIORITY, InAppNotificationPriority.class));
item.setTrackingState(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._trackingState, NotificationInAppTracking.class));
item.setCreatedAt(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._createdAt, Instant.class));
item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._updatedAt, Instant.class));
item.setIsActive(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._isActive, IsActive.class));
item.setExtraData(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._extraData, String.class));
item.setBody(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._body, String.class));
item.setSubject(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._subject, String.class));
item.setPriority(QueryBase.convertSafe(tuple, columns, InAppNotificationEntity.Field._priority, InAppNotificationPriority.class));
return item;
}
}

View File

@ -66,9 +66,9 @@ public class InAppNotifier implements Notify{
inApp.setBody(inAppMessage.getBody());
inApp.setExtraData(inAppMessage.getExtraData() != null ? this.jsonHandlingService.toJsonSafe(inAppMessage.getExtraData()) : null);
inApp.setCreatedAt(Instant.now());
inApp.setUpdatedAt(Instant.now());
inApp.setTenantId(tenantScope.getTenant());
inApp = entityManager.merge(inApp);
entityManager.persist(inApp);
InAppTrackingData trackingData = new InAppTrackingData(inApp.getId());