diff --git a/package-lock.json b/package-lock.json index fb028582..adf56796 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "alkemio-notifications", - "version": "0.4.3", + "version": "0.4.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "alkemio-notifications", - "version": "0.4.3", + "version": "0.4.4", "license": "EUPL-1.2", "dependencies": { - "@alkemio/client-lib": "^0.10.2", + "@alkemio/client-lib": "^0.10.4", "@nestjs/axios": "^0.0.1", "@nestjs/common": "^8.0.5", "@nestjs/config": "^1.0.1", @@ -74,9 +74,9 @@ } }, "node_modules/@alkemio/client-lib": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@alkemio/client-lib/-/client-lib-0.10.2.tgz", - "integrity": "sha512-JZNslgaGIIc2FlsIvET5x/JHGtq05y8MpVhUJj8U3ivjentCaHEApSGwl1i4/2yHwbvY7TbHYDga/dzDcc6hzA==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@alkemio/client-lib/-/client-lib-0.10.4.tgz", + "integrity": "sha512-XWVIgcBMDRtR4n955rs/trdw+kZE2Zs4yhXcaVdr2o1l78lqyccDdlKhGcf4L3OLDDdVm9aQOpUUckkeX+fiSQ==", "dependencies": { "axios": "^0.21.1", "dotenv": "^8.2.0", @@ -17355,9 +17355,9 @@ }, "dependencies": { "@alkemio/client-lib": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@alkemio/client-lib/-/client-lib-0.10.2.tgz", - "integrity": "sha512-JZNslgaGIIc2FlsIvET5x/JHGtq05y8MpVhUJj8U3ivjentCaHEApSGwl1i4/2yHwbvY7TbHYDga/dzDcc6hzA==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@alkemio/client-lib/-/client-lib-0.10.4.tgz", + "integrity": "sha512-XWVIgcBMDRtR4n955rs/trdw+kZE2Zs4yhXcaVdr2o1l78lqyccDdlKhGcf4L3OLDDdVm9aQOpUUckkeX+fiSQ==", "requires": { "axios": "^0.21.1", "dotenv": "^8.2.0", diff --git a/package.json b/package.json index 5cd04617..6e11d622 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "alkemio-notifications", - "version": "0.4.3", + "version": "0.4.4", "description": "Alkemio notifications service", "author": "Cherrytwist Foundation", "private": false, @@ -34,7 +34,7 @@ "validate-connection": "ts-node src/utils/validate-connection.ts" }, "dependencies": { - "@alkemio/client-lib": "^0.10.2", + "@alkemio/client-lib": "^0.10.4", "@nestjs/axios": "^0.0.1", "@nestjs/common": "^8.0.5", "@nestjs/config": "^1.0.1", diff --git a/src/app.controller.ts b/src/app.controller.ts index 4779e8a8..87d5186a 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -125,7 +125,8 @@ export class AppController { this.logger.verbose?.('All messages failed to be sent!'); // if all messages failed to be sent, we reject the message but we make sure the message is // not discarded so we provide 'true' to requeue parameter - channel.reject(originalMsg, true); + channel.nack(originalMsg, false, false); + // channel.reject(originalMsg, true); } else { this.logger.verbose?.( `${nacked.length} messages out of total ${x.length} messages failed to be sent!` diff --git a/src/services/application/alkemio-client-adapter/alkemio.client.adapter.ts b/src/services/application/alkemio-client-adapter/alkemio.client.adapter.ts index 9d40b4b7..4ed88c9a 100644 --- a/src/services/application/alkemio-client-adapter/alkemio.client.adapter.ts +++ b/src/services/application/alkemio-client-adapter/alkemio.client.adapter.ts @@ -64,12 +64,24 @@ export class AlkemioClientAdapter implements IFeatureFlagProvider { uniqueUser => uniqueUser.id === user.id ); if (!alreadyFound) { - uniqueUsers.push(user); + if (this.isEmailFormat(user.email)) uniqueUsers.push(user); + else { + this.logger.error( + `Unable to obtain a valid email address for "${user.displayName}": "${user.email}" is not a valid email address! + Please check the service account running the notifications service, it must have sufficient permissions to see the user email.`, + LogContext.NOTIFICATIONS + ); + } } } return uniqueUsers; } + private isEmailFormat(value: string): boolean { + const emailRegex = /^\S+@\S+$/; + return emailRegex.test(value); + } + private async tryGetUser( userID: string, retry: number diff --git a/src/services/application/alkemio-url-generator/alkemio.url.generator.ts b/src/services/application/alkemio-url-generator/alkemio.url.generator.ts index 303e99bb..3d53460b 100644 --- a/src/services/application/alkemio-url-generator/alkemio.url.generator.ts +++ b/src/services/application/alkemio-url-generator/alkemio.url.generator.ts @@ -16,6 +16,10 @@ export class AlkemioUrlGenerator { )?.webclient_endpoint; } + createHubURL(): string { + return this.webclientEndpoint; + } + createCommunityURL( hubNameID: string, challengeNameID?: string, @@ -23,10 +27,10 @@ export class AlkemioUrlGenerator { ): string { const baseURL = `${this.webclientEndpoint}/${hubNameID}`; if (opportunityNameID) { - return `${baseURL}/${challengeNameID}/${opportunityNameID}`; + return `${baseURL}/challenges/${challengeNameID}/opportunities/${opportunityNameID}`; } if (challengeNameID) { - return `${baseURL}/${challengeNameID}`; + return `${baseURL}/challenges/${challengeNameID}`; } return baseURL; } @@ -38,4 +42,8 @@ export class AlkemioUrlGenerator { createOrganizationURL(orgNameID: string): string { return `${this.webclientEndpoint}/organization/${orgNameID}`; } + + createUserNotificationPreferencesURL(userNameID: string): string { + return `${this.webclientEndpoint}/user/${userNameID}/settings/notifications`; + } } diff --git a/src/services/domain/builders/application-created/application.created.notification.builder.ts b/src/services/domain/builders/application-created/application.created.notification.builder.ts index 84ce241e..fdb958ee 100644 --- a/src/services/domain/builders/application-created/application.created.notification.builder.ts +++ b/src/services/domain/builders/application-created/application.created.notification.builder.ts @@ -163,6 +163,11 @@ export class ApplicationCreatedNotificationBuilder { eventPayload.hub.challenge?.nameID, eventPayload.hub.challenge?.opportunity?.nameID ); + const notificationPreferenceURL = + this.alkemioUrlGenerator.createUserNotificationPreferencesURL( + recipient.nameID + ); + const hubURL = this.alkemioUrlGenerator.createHubURL(); return { emailFrom: 'info@alkem.io', applicant: { @@ -173,12 +178,16 @@ export class ApplicationCreatedNotificationBuilder { recipient: { name: recipient.displayName, email: recipient.email, + notificationPreferences: notificationPreferenceURL, }, community: { name: eventPayload.community.name, type: eventPayload.community.type, url: communityURL, }, + hub: { + url: hubURL, + }, event: eventPayload, }; } diff --git a/src/services/domain/builders/communication-discussion-created/communication.discussion.created.notification.builder.ts b/src/services/domain/builders/communication-discussion-created/communication.discussion.created.notification.builder.ts index 22007349..ea69d79c 100644 --- a/src/services/domain/builders/communication-discussion-created/communication.discussion.created.notification.builder.ts +++ b/src/services/domain/builders/communication-discussion-created/communication.discussion.created.notification.builder.ts @@ -57,7 +57,8 @@ export class CommunicationDiscussionCreatedNotificationBuilder { eventPayload, 'admin', EmailTemplate.COMMUNICATION_DISCUSSION_CREATED_ADMIN, - sender + sender, + UserPreferenceType.NotificationCommunicationDiscussionCreatedAdmin ); const memberNotificationPromises = await this.buildNotificationsForRole( @@ -178,6 +179,11 @@ export class CommunicationDiscussionCreatedNotificationBuilder { eventPayload.hub.challenge?.opportunity?.nameID ); const senderProfile = this.alkemioUrlGenerator.createUserURL(sender.nameID); + const notificationPreferenceURL = + this.alkemioUrlGenerator.createUserNotificationPreferencesURL( + recipient.nameID + ); + const hubURL = this.alkemioUrlGenerator.createHubURL(); return { emailFrom: 'info@alkem.io', createdBy: { @@ -195,12 +201,16 @@ export class CommunicationDiscussionCreatedNotificationBuilder { name: recipient.displayName, firstname: recipient.firstName, email: recipient.email, + notificationPreferences: notificationPreferenceURL, }, community: { name: eventPayload.community.name, type: eventPayload.community.type, url: communityURL, }, + hub: { + url: hubURL, + }, event: eventPayload, }; } diff --git a/src/services/domain/builders/communication-updated/communication.updated.notification.builder.ts b/src/services/domain/builders/communication-updated/communication.updated.notification.builder.ts index ddfa3a89..6a8a54d6 100644 --- a/src/services/domain/builders/communication-updated/communication.updated.notification.builder.ts +++ b/src/services/domain/builders/communication-updated/communication.updated.notification.builder.ts @@ -53,7 +53,8 @@ export class CommunicationUpdateNotificationBuilder { eventPayload, 'admin', EmailTemplate.COMMUNICATION_UPDATE_ADMIN, - sender + sender, + UserPreferenceType.NotificationCommunicationUpdateSentAdmin ); const memberNotificationPromises = await this.buildNotificationsForRole( @@ -176,6 +177,11 @@ export class CommunicationUpdateNotificationBuilder { eventPayload.hub.challenge?.opportunity?.nameID ); const senderProfile = this.alkemioUrlGenerator.createUserURL(sender.nameID); + const notificationPreferenceURL = + this.alkemioUrlGenerator.createUserNotificationPreferencesURL( + recipient.nameID + ); + const hubURL = this.alkemioUrlGenerator.createHubURL(); return { emailFrom: 'info@alkem.io', sender: { @@ -191,12 +197,16 @@ export class CommunicationUpdateNotificationBuilder { name: recipient.displayName, firstname: recipient.firstName, email: recipient.email, + notificationPreferences: notificationPreferenceURL, }, community: { name: eventPayload.community.name, type: eventPayload.community.type, url: communityURL, }, + hub: { + url: hubURL, + }, event: eventPayload, }; } diff --git a/src/services/domain/builders/user-registered/user.registered.notification.builder.ts b/src/services/domain/builders/user-registered/user.registered.notification.builder.ts index 3bc20f1a..1fa815e2 100644 --- a/src/services/domain/builders/user-registered/user.registered.notification.builder.ts +++ b/src/services/domain/builders/user-registered/user.registered.notification.builder.ts @@ -153,6 +153,11 @@ export class UserRegisteredNotificationBuilder { const registrantProfileURL = this.alkemioUrlGenerator.createUserURL( registrant.nameID ); + const notificationPreferenceURL = + this.alkemioUrlGenerator.createUserNotificationPreferencesURL( + recipient.nameID + ); + const hubURL = this.alkemioUrlGenerator.createHubURL(); return { emailFrom: 'info@alkem.io', registrant: { @@ -165,6 +170,10 @@ export class UserRegisteredNotificationBuilder { name: recipient.displayName, firstname: recipient.firstName, email: recipient.email, + notificationPreferences: notificationPreferenceURL, + }, + hub: { + url: hubURL, }, event: eventPayload, }; diff --git a/src/templates/_layouts/email-transactional.html b/src/templates/_layouts/email-transactional.html index 7b6fc973..b0a19ee8 100644 --- a/src/templates/_layouts/email-transactional.html +++ b/src/templates/_layouts/email-transactional.html @@ -1,10 +1,19 @@ +
- ![]() |
+