From 162e3766eae56b89204a57d1248adf23fdc15994 Mon Sep 17 00:00:00 2001 From: Hrvoje Vucic Date: Tue, 15 Jun 2021 14:37:40 +0200 Subject: [PATCH 1/5] Add notifications field in user model --- ...0210614092852-alter-user-add-notifications.js | 16 ++++++++++++++++ server/user/user.model.js | 8 ++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 server/shared/database/migrations/20210614092852-alter-user-add-notifications.js diff --git a/server/shared/database/migrations/20210614092852-alter-user-add-notifications.js b/server/shared/database/migrations/20210614092852-alter-user-add-notifications.js new file mode 100644 index 000000000..61d689acf --- /dev/null +++ b/server/shared/database/migrations/20210614092852-alter-user-add-notifications.js @@ -0,0 +1,16 @@ +'use strict'; + +const TABLE_NAME = 'user'; +const COLUMN_NAME = 'notifications'; + +module.exports = { + up: (queryInterface, { JSONB }) => { + return queryInterface.addColumn(TABLE_NAME, COLUMN_NAME, { + type: JSONB, + defaultValue: { comment: true, assignment: true } + }); + }, + down: queryInterface => { + return queryInterface.removeColumn(TABLE_NAME, COLUMN_NAME); + } +}; diff --git a/server/user/user.model.js b/server/user/user.model.js index 3e36ce8fa..9bc608cd6 100644 --- a/server/user/user.model.js +++ b/server/user/user.model.js @@ -18,7 +18,7 @@ const { user: { ADMIN, USER, INTEGRATION } } = roles; const gravatarConfig = { size: 130, default: 'identicon' }; class User extends Model { - static fields({ DATE, ENUM, STRING, TEXT, UUID, UUIDV4, VIRTUAL }) { + static fields({ DATE, ENUM, JSONB, STRING, TEXT, UUID, UUIDV4, VIRTUAL }) { return { uid: { type: UUID, @@ -73,12 +73,16 @@ class User extends Model { return imgUrl || gravatar.url(this.email, gravatarConfig, true /* https */); } }, + notifications: { + type: JSONB, + defaultValue: { assignment: true, comment: true } + }, profile: { type: VIRTUAL, get() { return pick(this, [ 'id', 'email', 'role', 'firstName', 'lastName', 'fullName', 'label', - 'imgUrl', 'createdAt', 'updatedAt', 'deletedAt' + 'imgUrl', 'notifications', 'createdAt', 'updatedAt', 'deletedAt' ]); } }, From 42cfcfac47b3372db2e3f706b02403912d5017a9 Mon Sep 17 00:00:00 2001 From: Hrvoje Vucic Date: Tue, 15 Jun 2021 15:05:21 +0200 Subject: [PATCH 2/5] Update user settings form to update user notification settings --- client/components/user-settings/Info.vue | 34 +++++++++++++++++++++--- server/user/user.controller.js | 4 +-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/client/components/user-settings/Info.vue b/client/components/user-settings/Info.vue index e2ac03840..68a8f0ca1 100644 --- a/client/components/user-settings/Info.vue +++ b/client/components/user-settings/Info.vue @@ -41,6 +41,21 @@ outlined class="required" /> + + + + + +
Cancel @@ -58,14 +73,17 @@ + + diff --git a/server/user/user.controller.js b/server/user/user.controller.js index c42a9c3a6..aa83292b3 100644 --- a/server/user/user.controller.js +++ b/server/user/user.controller.js @@ -48,8 +48,8 @@ function getProfile({ user, authData }, res) { } function updateProfile({ user, body }, res) { - const { email, firstName, lastName, imgUrl } = body; - return user.update({ email, firstName, lastName, imgUrl }) + const { email, firstName, lastName, imgUrl, notifications } = body; + return user.update({ email, firstName, lastName, imgUrl, notifications }) .then(({ profile }) => res.json({ user: profile })) .catch(() => validationError(CONFLICT)); } From 36edc15ef3ad3ba3d43ddc69d3a0e27b272be409 Mon Sep 17 00:00:00 2001 From: Hrvoje Vucic Date: Tue, 15 Jun 2021 15:06:08 +0200 Subject: [PATCH 3/5] Check user notification settings before sending comment notification --- server/comment/hooks.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/comment/hooks.js b/server/comment/hooks.js index fb6145301..e38386da6 100644 --- a/server/comment/hooks.js +++ b/server/comment/hooks.js @@ -1,7 +1,6 @@ 'use strict'; const mail = require('../shared/mail'); -const map = require('lodash/map'); const pick = require('lodash/pick'); const { schema } = require('@tailor-cms/config'); const sse = require('../shared/sse'); @@ -80,7 +79,10 @@ exports.add = (Comment, Hooks, db) => { action: isCreate ? 'left' : 'updated', ...pick(comment, ['id', 'content', 'createdAt']) }; - const collaborators = map(repository.repositoryUsers, 'user.email'); + const collaborators = repository.repositoryUsers.reduce((acc, { user }) => { + if (user.notifications.comment) acc.push(user.email); + return acc; + }, []); const recipients = without(collaborators, author.email); if (recipients.length) mail.sendCommentNotification(recipients, data); } From 8a9b6626801b2185ff17764dee3a64e6c8638523 Mon Sep 17 00:00:00 2001 From: Hrvoje Vucic Date: Wed, 16 Jun 2021 12:03:40 +0200 Subject: [PATCH 4/5] Check user notification settings before sending assignee notification --- server/activity/status.hooks.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/activity/status.hooks.js b/server/activity/status.hooks.js index ed6d6aa6b..06d23591f 100644 --- a/server/activity/status.hooks.js +++ b/server/activity/status.hooks.js @@ -37,7 +37,8 @@ exports.add = (ActivityStatus, Hooks, { Activity }) => { }); const isUnchanged = previousStatus.assigneeId === status.assigneeId; const isSelfAssign = status.assigneeId === userId; - if (isUnchanged || isSelfAssign) return; + const isDisabled = !status.assignee.notifications.assignment; + if (isUnchanged || isSelfAssign || isDisabled) return; sendEmailNotification(activity); } From 4274cf9b39e03b8c3cb895f188958c1f180ae743 Mon Sep 17 00:00:00 2001 From: Hrvoje Vucic Date: Wed, 16 Jun 2021 14:23:39 +0200 Subject: [PATCH 5/5] Include unsubscribe link in the email templates --- server/shared/mail/index.js | 3 +++ server/shared/mail/templates/assignee.mjml | 11 +++++++++++ server/shared/mail/templates/assignee.txt | 4 ++++ server/shared/mail/templates/comment.mjml | 11 +++++++++++ server/shared/mail/templates/comment.txt | 4 ++++ 5 files changed, 33 insertions(+) diff --git a/server/shared/mail/index.js b/server/shared/mail/index.js index db1a2b749..2f08bbeb1 100644 --- a/server/shared/mail/index.js +++ b/server/shared/mail/index.js @@ -30,6 +30,7 @@ const elementUrl = ({ repositoryId, activityId, elementUid }) => { const query = `${activityId}?elementId=${elementUid}`; return urlJoin(origin, '/#/repository', `${repositoryId}/editor`, query); }; +const settingsUrl = () => urlJoin(origin, '/#/settings'); module.exports = { send, @@ -81,6 +82,7 @@ function sendCommentNotification(users, comment) { const data = { href, origin, + unsubscribeLink: settingsUrl(), getInitials: () => (text, render) => render(text).substr(0, 2).toUpperCase(), ...comment }; @@ -101,6 +103,7 @@ function sendAssigneeNotification(assignee, activity) { const data = { ...activity, origin, + unsubscribeLink: settingsUrl(), href: activityStatusUrl(activity.repositoryId, activity.id) }; const html = renderHtml(path.join(templatesDir, 'assignee.mjml'), data); diff --git a/server/shared/mail/templates/assignee.mjml b/server/shared/mail/templates/assignee.mjml index 343f9e40e..b9a24d5cd 100644 --- a/server/shared/mail/templates/assignee.mjml +++ b/server/shared/mail/templates/assignee.mjml @@ -27,5 +27,16 @@ + + + + You can + + Unsubscribe + + from assignment notifications in the profile page. + + + diff --git a/server/shared/mail/templates/assignee.txt b/server/shared/mail/templates/assignee.txt index 1b62daf45..61101ff31 100644 --- a/server/shared/mail/templates/assignee.txt +++ b/server/shared/mail/templates/assignee.txt @@ -9,5 +9,9 @@ View the {{label}} status by visiting the link: Or copy and paste this URL into your browser. +You can unsubscribe from assignment notifications in the profile page by visiting the link: + +{{unsubscribeLink}} + ------------------------------------------------- diff --git a/server/shared/mail/templates/comment.mjml b/server/shared/mail/templates/comment.mjml index dcb88c2ad..cd25a1a11 100644 --- a/server/shared/mail/templates/comment.mjml +++ b/server/shared/mail/templates/comment.mjml @@ -62,5 +62,16 @@ + + + + You can + + Unsubscribe + + from comment notifications in the profile page. + + + diff --git a/server/shared/mail/templates/comment.txt b/server/shared/mail/templates/comment.txt index cd20817c2..73807bd00 100644 --- a/server/shared/mail/templates/comment.txt +++ b/server/shared/mail/templates/comment.txt @@ -11,4 +11,8 @@ View {{activityLabel}} by clicking the URL below: Or copy and paste this URL into your browser. +You can unsubscribe from comment notifications in the profile page by visiting the link: + +{{unsubscribeLink}} + -------------------------------------------------