More improvements on send notifications logic (#10736)

* Denormalize the User’s Highlights

* Find subscriptions for each type of notification

* Change email preference values

* General improvements

* Use just one query to get all subscriptions to notify

* Get hightlights from subscriptions on method notifyUsersOnMessage

* Keep compatibility of emailNotifications preference in subscription save

* Prevent group mentions on large rooms
pull/10760/head
Diego Sampaio 8 years ago committed by Rodrigo Nascimento
parent b995ed69f4
commit 1b8e8a5bf9
  1. 7
      packages/rocketchat-api/server/v1/users.js
  2. 2
      packages/rocketchat-emoji-emojione/server/callbacks.js
  3. 3
      packages/rocketchat-i18n/i18n/en.i18n.json
  4. 44
      packages/rocketchat-lib/server/functions/notifications/desktop.js
  5. 2
      packages/rocketchat-lib/server/functions/notifications/email.js
  6. 32
      packages/rocketchat-lib/server/functions/notifications/index.js
  7. 6
      packages/rocketchat-lib/server/functions/notifications/mobile.js
  8. 14
      packages/rocketchat-lib/server/lib/notifyUsersOnMessage.js
  9. 88
      packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js
  10. 34
      packages/rocketchat-lib/server/models/Subscriptions.js
  11. 6
      packages/rocketchat-lib/server/startup/settings.js
  12. 15
      packages/rocketchat-mentions/server/Mentions.js
  13. 26
      packages/rocketchat-mentions/server/server.js
  14. 38
      packages/rocketchat-mentions/tests/server.tests.js
  15. 7
      packages/rocketchat-push-notifications/server/methods/saveNotificationSettings.js
  16. 14
      packages/rocketchat-push-notifications/server/models/Subscriptions.js
  17. 4
      packages/rocketchat-ui-account/client/accountPreferences.html
  18. 4
      packages/rocketchat-ui-account/client/accountPreferences.js
  19. 13
      server/methods/saveUserPreferences.js
  20. 2
      server/startup/migrations/v116.js
  21. 72
      server/startup/migrations/v118.js
  22. 2
      tests/data/user.js
  23. 2
      tests/end-to-end/ui/11-admin.js

@ -363,6 +363,13 @@ RocketChat.API.v1.addRoute('users.setPreferences', { authRequired: true }, {
preferences = _.extend({ _id: userId, settings: { preferences: this.bodyParams.data } });
}
// Keep compatibility with old values
if (preferences.emailNotificationMode === 'all') {
preferences.emailNotificationMode = 'mentions';
} else if (preferences.emailNotificationMode === 'disabled') {
preferences.emailNotificationMode = 'nothing';
}
Meteor.runAsUser(this.userId, () => RocketChat.saveUser(this.userId, preferences));
return RocketChat.API.v1.success({ user: RocketChat.models.Users.findOneById(this.bodyParams.userId, { fields: preferences }) });

@ -1,6 +1,6 @@
/* globals emojione */
Meteor.startup(function() {
RocketChat.callbacks.add('beforeNotifyUser', (message) => {
RocketChat.callbacks.add('beforeSendMessageNotifications', (message) => {
return emojione.shortnameToUnicode(message);
});
});

@ -918,6 +918,7 @@
"Government": "Government",
"Group_by_Type": "Group by Type",
"Group_favorites": "Group favorites",
"Group_mentions_disabled_x_members": "Group mentions `@all` and `@here` have been disabled for rooms with more than __total__ members.",
"Group_mentions_only": "Group mentions only",
"Guest_Pool": "Guest Pool",
"Hash": "Hash",
@ -1406,7 +1407,7 @@
"Message_Ignored": "This message was ignored",
"Message_info": "Message info",
"Message_KeepHistory": "Keep Per Message Editing History",
"Message_MaxAll": "Maximum Channel Size for ALL Message",
"Message_MaxAll": "Maximum Channel Size for Group Mentions (@all and @here)",
"Message_MaxAllowedSize": "Maximum Allowed Characters Per Message",
"Message_pinning": "Message pinning",
"Message_QuoteChainLimit": "Maximum Number of Chained Quotes",

@ -1,51 +1,31 @@
import { parseMessageText } from './index';
/**
* Replaces @username with full name
*
* @param {string} message The message to replace
* @param {object[]} mentions Array of mentions used to make replacements
*
* @returns {string}
*/
function replaceMentionedUsernamesWithFullNames(message, mentions) {
if (!mentions || !mentions.length) {
return message;
}
mentions.forEach((mention) => {
const user = RocketChat.models.Users.findOneById(mention._id);
if (user && user.name) {
message = message.replace(`@${ mention.username }`, user.name);
}
});
return message;
}
/**
* Send notification to user
*
* @param {string} userId The user to notify
* @param {object} user The sender
* @param {object} room The room send from
* @param {object} message The message object
* @param {number} duration Duration of notification
* @param {string} notificationMessage The message text to send on notification body
*/
export function notifyDesktopUser(userId, user, message, room, duration) {
export function notifyDesktopUser({
userId,
user,
message,
room,
duration,
notificationMessage
}) {
const UI_Use_Real_Name = RocketChat.settings.get('UI_Use_Real_Name') === true;
message.msg = parseMessageText(message, userId);
if (UI_Use_Real_Name) {
message.msg = replaceMentionedUsernamesWithFullNames(message.msg, message.mentions);
}
let title = '';
let text = '';
if (room.t === 'd') {
title = UI_Use_Real_Name ? user.name : `@${ user.username }`;
text = message.msg;
text = notificationMessage;
} else if (room.name) {
title = `#${ room.name }`;
text = `${ UI_Use_Real_Name ? user.name : user.username }: ${ message.msg }`;
text = `${ UI_Use_Real_Name ? user.name : user.username }: ${ notificationMessage }`;
} else {
return;
}

@ -167,7 +167,7 @@ export function shouldNotifyEmail({
}
// default server preference is disabled
if (RocketChat.settings.get('Accounts_Default_User_Preferences_emailNotificationMode') === 'disabled') {
if (RocketChat.settings.get('Accounts_Default_User_Preferences_emailNotificationMode') === 'nothing') {
return false;
}
}

@ -5,16 +5,34 @@ import s from 'underscore.string';
*
* @param {object} message the message to be parsed
*/
export function parseMessageText(message, userId) {
const user = RocketChat.models.Users.findOneById(userId);
const lng = user && user.language || RocketChat.settings.get('language') || 'en';
export function parseMessageTextPerUser(message, receiver) {
if (!message.msg && message.attachments && message.attachments[0]) {
message.msg = message.attachments[0].image_type ? TAPi18n.__('User_uploaded_image', {lng}) : TAPi18n.__('User_uploaded_file', {lng});
const lng = receiver.language || RocketChat.settings.get('language') || 'en';
return message.attachments[0].image_type ? TAPi18n.__('User_uploaded_image', {lng}) : TAPi18n.__('User_uploaded_file', {lng});
}
message.msg = RocketChat.callbacks.run('beforeNotifyUser', message.msg);
return message.msg;
return message;
}
/**
* Replaces @username with full name
*
* @param {string} message The message to replace
* @param {object[]} mentions Array of mentions used to make replacements
*
* @returns {string}
*/
export function replaceMentionedUsernamesWithFullNames(message, mentions) {
if (!mentions || !mentions.length) {
return message;
}
mentions.forEach((mention) => {
if (mention.name) {
message = message.replace(new RegExp(s.escapeRegExp(`@${ mention.username }`), 'g'), mention.name);
}
});
return message;
}
/**

@ -1,5 +1,3 @@
import { parseMessageText } from './index';
const CATEGORY_MESSAGE = 'MESSAGE';
const CATEGORY_MESSAGE_NOREPLY = 'MESSAGE_NOREPLY';
@ -20,7 +18,7 @@ function canSendMessageToRoom(room, username) {
return !((room.muted || []).includes(username));
}
export function sendSinglePush({ room, message, userId, receiverUsername, senderUsername }) {
export function sendSinglePush({ room, message, userId, receiverUsername, senderUsername, notificationMessage }) {
RocketChat.PushNotification.send({
roomId: message.rid,
payload: {
@ -32,7 +30,7 @@ export function sendSinglePush({ room, message, userId, receiverUsername, sender
},
roomName: RocketChat.settings.get('Push_show_username_room') ? `#${ RocketChat.roomTypes.getRoomName(room.t, room) }` : '',
username: RocketChat.settings.get('Push_show_username_room') ? senderUsername : '',
message: RocketChat.settings.get('Push_show_message') ? parseMessageText(message, userId) : ' ',
message: RocketChat.settings.get('Push_show_message') ? notificationMessage : ' ',
// badge: getBadgeCount(userIdToNotify),
usersTo: {
userId

@ -45,8 +45,7 @@ function notifyUsersOnMessage(message, room) {
let toHere = false;
const mentionIds = [];
const highlightsIds = [];
const highlights = RocketChat.models.Users.findUsersByUsernamesWithHighlights(room.usernames, { fields: { '_id': 1, 'settings.preferences.highlights': 1 }}).fetch();
const highlights = RocketChat.models.Subscriptions.findByRoomWithUserHighlights(room._id, { fields: {'userHighlights': 1, 'u._id': 1 }}).fetch();
if (message.mentions != null) {
message.mentions.forEach(function(mention) {
if (!toAll && mention._id === 'all') {
@ -61,11 +60,10 @@ function notifyUsersOnMessage(message, room) {
});
}
highlights.forEach(function(user) {
const userHighlights = RocketChat.getUserPreference(user, 'highlights');
if (userHighlights && messageContainsHighlight(message, userHighlights)) {
if (user._id !== message.u._id) {
highlightsIds.push(user._id);
highlights.forEach(function(subscription) {
if (subscription.userHighlights && messageContainsHighlight(message, subscription.userHighlights)) {
if (subscription.u._id !== message.u._id) {
highlightsIds.push(subscription.u._id);
}
}
});
@ -103,8 +101,8 @@ function notifyUsersOnMessage(message, room) {
}
// Update all the room activity tracker fields
// This method take so long to execute on gient rooms cuz it will trugger the cache rebuild for the releations of that room
RocketChat.models.Rooms.incMsgCountAndSetLastMessageById(message.rid, 1, message.ts, RocketChat.settings.get('Store_Last_Message') && message);
// Update all other subscriptions to alert their owners but witout incrementing
// the unread counter, as it is only for mentions and direct messages
// We now set alert and open properties in two separate update commands. This proved to be more efficient on MongoDB - because it uses a more efficient index.

@ -1,6 +1,6 @@
import moment from 'moment';
import { callJoinRoom, messageContainsHighlight } from '../functions/notifications/';
import { callJoinRoom, messageContainsHighlight, parseMessageTextPerUser, replaceMentionedUsernamesWithFullNames } from '../functions/notifications/';
import { sendEmail, shouldNotifyEmail } from '../functions/notifications/email';
import { sendSinglePush, shouldNotifyMobile } from '../functions/notifications/mobile';
import { notifyDesktopUser, shouldNotifyDesktop } from '../functions/notifications/desktop';
@ -12,6 +12,7 @@ const sendNotification = ({
hasMentionToAll,
hasMentionToHere,
message,
notificationMessage,
room,
mentionIds,
disableAllMessageNotifications
@ -45,7 +46,9 @@ const sendNotification = ({
return;
}
const isHighlighted = messageContainsHighlight(message, receiver.settings && receiver.settings.preferences && receiver.settings.preferences.highlights);
notificationMessage = parseMessageTextPerUser(notificationMessage, receiver);
const isHighlighted = messageContainsHighlight(message, subscription.userHighlights);
const {
audioNotifications,
@ -80,7 +83,14 @@ const sendNotification = ({
hasMentionToUser
})) {
notificationSent = true;
notifyDesktopUser(subscription.u._id, sender, message, room, subscription.desktopNotificationDuration);
notifyDesktopUser({
notificationMessage,
userId: subscription.u._id,
user: sender,
message,
room,
duration: subscription.desktopNotificationDuration
});
}
if (shouldNotifyMobile({
@ -94,6 +104,7 @@ const sendNotification = ({
notificationSent = true;
sendSinglePush({
notificationMessage,
room,
message,
userId: subscription.u._id,
@ -144,38 +155,67 @@ function sendAllNotifications(message, room) {
return message;
}
const mentionIds = (message.mentions || []).map(({_id}) => _id);
const mentionIdsWithoutGroups = mentionIds.filter((_id) => _id !== 'all' && _id !== 'here');
const hasMentionToAll = mentionIds.includes('all');
const hasMentionToHere = mentionIds.includes('here');
let notificationMessage = RocketChat.callbacks.run('beforeSendMessageNotifications', message.msg);
if (mentionIds.length > 0 && RocketChat.settings.get('UI_Use_Real_Name')) {
notificationMessage = replaceMentionedUsernamesWithFullNames(message.msg, message.mentions);
}
// Don't fetch all users if room exceeds max members
const maxMembersForNotification = RocketChat.settings.get('Notifications_Max_Room_Members');
const disableAllMessageNotifications = room.usernames.length > maxMembersForNotification && maxMembersForNotification !== 0;
// the find bellow is crucial. all subscription records returned will receive at least one kind of notification.
// the query is defined by the server's default values and Notifications_Max_Room_Members setting.
let subscriptions;
if (disableAllMessageNotifications) {
subscriptions = RocketChat.models.Subscriptions.findAllMessagesNotificationPreferencesByRoom(room._id);
} else {
const mentionsFilter = { $in: ['all', 'mentions'] };
const excludesNothingFilter = { $ne: 'nothing' };
// evaluate if doing three specific finds is better than evaluting all results
subscriptions = RocketChat.models.Subscriptions.findNotificationPreferencesByRoom({
roomId: room._id,
desktopFilter: RocketChat.settings.get('Accounts_Default_User_Preferences_desktopNotifications') === 'nothing' ? mentionsFilter : excludesNothingFilter,
emailFilter: RocketChat.settings.get('Accounts_Default_User_Preferences_emailNotificationMode') === 'disabled' ? mentionsFilter : excludesNothingFilter,
mobileFilter: RocketChat.settings.get('Accounts_Default_User_Preferences_mobileNotifications') === 'nothing' ? mentionsFilter : excludesNothingFilter
});
}
const query = {
rid: room._id,
$or: [{
'userHighlights.0': { $exists: 1 }
}]
};
const mentionIds = (message.mentions || []).map(({_id}) => _id);
const hasMentionToAll = mentionIds.includes('all');
const hasMentionToHere = mentionIds.includes('here');
['audio', 'desktop', 'mobile', 'email'].map((kind) => {
const notificationField = `${ kind === 'mobile' ? 'mobilePush' : kind }Notifications`;
const filter = { [notificationField]: 'all' };
if (disableAllMessageNotifications) {
filter[`${ kind }PrefOrigin`] = { $ne: 'user' };
}
query.$or.push(filter);
if (mentionIdsWithoutGroups.length > 0) {
query.$or.push({
[notificationField]: 'mentions',
'u._id': { $in: mentionIdsWithoutGroups }
});
}
if (RocketChat.settings.get(`Accounts_Default_User_Preferences_${ notificationField }`) === 'all' && !disableAllMessageNotifications) {
query.$or.push({
[notificationField]: { $exists: false }
});
} else if (RocketChat.settings.get(`Accounts_Default_User_Preferences_${ notificationField }`) === 'mentions' && mentionIdsWithoutGroups.length) {
query.$or.push({
[notificationField]: { $exists: false },
'u._id': { $in: mentionIdsWithoutGroups }
});
}
});
// the find bellow is crucial. all subscription records returned will receive at least one kind of notification.
// the query is defined by the server's default values and Notifications_Max_Room_Members setting.
const subscriptions = RocketChat.models.Subscriptions.findNotificationPreferencesByRoom(query);
subscriptions.forEach((subscription) => sendNotification({
subscription,
sender,
hasMentionToAll,
hasMentionToHere,
message,
notificationMessage,
room,
mentionIds,
disableAllMessageNotifications
@ -200,6 +240,7 @@ function sendAllNotifications(message, room) {
hasMentionToAll,
hasMentionToHere,
message,
notificationMessage,
room,
mentionIds
});
@ -211,4 +252,3 @@ function sendAllNotifications(message, room) {
}
RocketChat.callbacks.add('afterSaveMessage', sendAllNotifications, RocketChat.callbacks.priority.LOW, 'sendNotificationsOnMessage');

@ -22,6 +22,7 @@ class ModelSubscriptions extends RocketChat.models._Base {
this.tryEnsureIndex({ 'emailNotifications': 1 }, { sparse: 1 });
this.tryEnsureIndex({ 'autoTranslate': 1 }, { sparse: 1 });
this.tryEnsureIndex({ 'autoTranslateLanguage': 1 }, { sparse: 1 });
this.tryEnsureIndex({ 'userHighlights.0': 1 }, { sparse: 1 });
this.cache.ensureIndex('rid', 'array');
this.cache.ensureIndex('u._id', 'array');
@ -79,7 +80,6 @@ class ModelSubscriptions extends RocketChat.models._Base {
return this.find(query, options);
}
// FIND
findByRoomIdAndRoles(roomId, roles, options) {
roles = [].concat(roles);
const query = {
@ -141,6 +141,15 @@ class ModelSubscriptions extends RocketChat.models._Base {
return this.find(query, options);
}
findByRoomWithUserHighlights(roomId, options) {
const query = {
rid: roomId,
'userHighlights.0': { $exists: true }
};
return this.find(query, options);
}
getLastSeen(options) {
if (options == null) {
options = {};
@ -713,6 +722,20 @@ class ModelSubscriptions extends RocketChat.models._Base {
return this.update(query, update, { multi: true });
}
updateUserHighlights(userId, userHighlights) {
const query = {
'u._id': userId
};
const update = {
$set: {
userHighlights
}
};
return this.update(query, update, { multi: true });
}
// INSERT
createWithRoomAndUser(room, user, extraData) {
const subscription = {
@ -737,7 +760,8 @@ class ModelSubscriptions extends RocketChat.models._Base {
const {
desktopNotifications,
mobileNotifications,
emailNotificationMode
emailNotificationMode,
highlights
} = (user.settings && user.settings.preferences) || {};
if (desktopNotifications && desktopNotifications !== 'default') {
@ -751,10 +775,14 @@ class ModelSubscriptions extends RocketChat.models._Base {
}
if (emailNotificationMode && emailNotificationMode !== 'default') {
subscription.emailNotifications = emailNotificationMode === 'disabled' ? 'nothing' : user.settings.preferences.emailNotificationMode;
subscription.emailNotifications = emailNotificationMode;
subscription.emailPrefOrigin = 'user';
}
if (Array.isArray(highlights) && highlights.length) {
subscription.userHighlights = highlights;
}
_.extend(subscription, extraData);
return this.insert(subscription);

@ -390,15 +390,15 @@ RocketChat.settings.addGroup('Accounts', function() {
'public': true,
i18nLabel: 'MessageBox_view_mode'
});
this.add('Accounts_Default_User_Preferences_emailNotificationMode', 'all', {
this.add('Accounts_Default_User_Preferences_emailNotificationMode', 'mentions', {
type: 'select',
values: [
{
key: 'disabled',
key: 'nothing',
i18nLabel: 'Email_Notification_Mode_Disabled'
},
{
key: 'all',
key: 'mentions',
i18nLabel: 'Email_Notification_Mode_All'
}
],

@ -10,6 +10,9 @@ export default class MentionsServer extends Mentions {
this.getChannel = args.getChannel;
this.getChannels = args.getChannels;
this.getUsers = args.getUsers;
this.getUser = args.getUser;
this.getTotalChannelMembers = args.getTotalChannelMembers;
this.onMaxRoomMembersExceeded = args.onMaxRoomMembersExceeded || (() => {});
}
set getUsers(m) {
this._getUsers = m;
@ -35,7 +38,7 @@ export default class MentionsServer extends Mentions {
get messageMaxAll() {
return typeof this._messageMaxAll === 'function' ? this._messageMaxAll() : this._messageMaxAll;
}
getUsersByMentions({msg, rid}) {
getUsersByMentions({msg, rid, u: sender}) {
let mentions = this.getUserMentions(msg);
const mentionsAll = [];
const userMentions = [];
@ -45,12 +48,8 @@ export default class MentionsServer extends Mentions {
if (mention !== 'all' && mention !== 'here') {
return userMentions.push(mention);
}
if (mention === 'all') {
const messageMaxAll = this.messageMaxAll;
const allChannel = this.getChannel(rid);
if (messageMaxAll !== 0 && allChannel.usernames.length >= messageMaxAll) {
return;
}
if (this.messageMaxAll > 0 && this.getTotalChannelMembers(rid) > this.messageMaxAll) {
return this.onMaxRoomMembersExceeded({ sender, rid });
}
mentionsAll.push({
_id: mention,
@ -69,8 +68,8 @@ export default class MentionsServer extends Mentions {
const channels = this.getChannelbyMentions(message);
message.mentions = mentionsAll;
message.channels = channels;
return message;
}
}

@ -4,8 +4,28 @@ import MentionsServer from './Mentions';
const mention = new MentionsServer({
pattern: () => RocketChat.settings.get('UTF8_Names_Validation'),
messageMaxAll: () => RocketChat.settings.get('Message_MaxAll'),
getUsers: (usernames) => Meteor.users.find({ username: {$in: _.unique(usernames)}}, { fields: {_id: true, username: true }}).fetch(),
getChannel: (rid) => RocketChat.models.Rooms.findOneById(rid),
getChannels: (channels) => RocketChat.models.Rooms.find({ name: {$in: _.unique(channels)}, t: 'c' }, { fields: {_id: 1, name: 1 }}).fetch()
getUsers: (usernames) => Meteor.users.find({ username: {$in: _.unique(usernames)}}, { fields: {_id: true, username: true, name: 1 }}).fetch(),
getUser: (userId) => RocketChat.models.Users.findOneById(userId),
getTotalChannelMembers: (rid) => RocketChat.models.Subscriptions.findByRoomId(rid).count(),
getChannels: (channels) => RocketChat.models.Rooms.find({ name: {$in: _.unique(channels)}, t: 'c' }, { fields: {_id: 1, name: 1 }}).fetch(),
onMaxRoomMembersExceeded({ sender, rid }) {
// Get the language of the user for the error notification.
const language = this.getUser(sender._id).language;
const msg = TAPi18n.__('Group_mentions_disabled_x_members', { total: this.messageMaxAll }, language);
RocketChat.Notifications.notifyUser(sender._id, 'message', {
_id: Random.id(),
rid,
ts: new Date,
msg,
groupable: false
});
// Also throw to stop propagation of 'sendMessage'.
throw new Meteor.Error('error-action-not-allowed', msg, {
method: 'filterATAllTag',
action: msg
});
}
});
RocketChat.callbacks.add('beforeSaveMessage', (message) => mention.execute(message), RocketChat.callbacks.priority.HIGH, 'mentions');

@ -20,25 +20,15 @@ beforeEach(function() {
username: 'jon'
}].filter(user => usernames.includes(user.username));//Meteor.users.find({ username: {$in: _.unique(usernames)}}, { fields: {_id: true, username: true }}).fetch();
},
getChannel: () => {
return {
usernames: [{
_id: 1,
username: 'rocket.cat'
}, {
_id: 2,
username: 'jon'
}]
};
// RocketChat.models.Rooms.findOneById(message.rid);,
},
getChannels(channels) {
return [{
_id: 1,
name: 'general'
}].filter(channel => channels.includes(channel.name));
// return RocketChat.models.Rooms.find({ name: {$in: _.unique(channels)}, t: 'c' }, { fields: {_id: 1, name: 1 }}).fetch();
}
},
getUser: (userId) => ({ _id: userId, language: 'en' }),
getTotalChannelMembers: (/*rid*/) => 2
});
});
@ -46,27 +36,7 @@ describe('Mention Server', () => {
describe('getUsersByMentions', () => {
describe('for @all but the number of users is greater than messageMaxAll', () => {
beforeEach(() => {
mention.getChannel = () => {
return {
usernames:[{
_id: 1,
username: 'rocket.cat'
}, {
_id: 2,
username: 'jon'
}, {
_id: 3,
username: 'jon1'
}, {
_id: 4,
username: 'jon2'
}, {
_id: 5,
username: 'jon3'
}]
};
//Meteor.users.find({ username: {$in: _.unique(usernames)}}, { fields: {_id: true, username: true }}).fetch();
};
mention.getTotalChannelMembers = () => 5;
});
it('should return nothing', () => {
const message = {

@ -35,9 +35,14 @@ Meteor.methods({
updateMethod: (subscription, value) => {
if (value === 'default') {
const userPref = RocketChat.getUserNotificationPreference(Meteor.userId(), 'email');
userPref.value = userPref.value === 'disabled' ? 'nothing' : userPref.value;
RocketChat.models.Subscriptions.updateEmailNotificationsById(subscription._id, userPref.origin === 'server' ? null : userPref);
} else {
// Keep compatibility with old values
if (value === 'all') {
value = 'mentions';
} else if (value === 'disabled') {
value = 'nothing';
}
RocketChat.models.Subscriptions.updateEmailNotificationsById(subscription._id, { value, origin: 'subscription' });
}
}

@ -221,16 +221,7 @@ RocketChat.models.Subscriptions.findWithSendEmailByRoomId = function(roomId) {
};
RocketChat.models.Subscriptions.findNotificationPreferencesByRoom = function({ roomId: rid, desktopFilter: desktopNotifications, mobileFilter: mobilePushNotifications, emailFilter: emailNotifications }) {
const query = {
rid,
'u._id': {$exists: true},
$or: [
{ desktopNotifications },
{ mobilePushNotifications },
{ emailNotifications }
]
};
RocketChat.models.Subscriptions.findNotificationPreferencesByRoom = function(query/*{ roomId: rid, desktopFilter: desktopNotifications, mobileFilter: mobilePushNotifications, emailFilter: emailNotifications }*/) {
return this._db.find(query, {
fields: {
@ -242,7 +233,8 @@ RocketChat.models.Subscriptions.findNotificationPreferencesByRoom = function({ r
mobilePushNotifications: 1,
emailNotifications: 1,
disableNotifications: 1,
muteGroupMentions: 1
muteGroupMentions: 1,
userHighlights: 1
}
});
};

@ -108,8 +108,8 @@
<div class="rc-select">
<select class="input-monitor rc-select__element" name="emailNotificationMode">
<option value="default" selected="{{selected 'emailNotificationMode' 'default' 'default'}}">{{_ "Default"}} ({{_ defaultEmailNotification}})</option>
<option value="disabled" selected="{{selected 'emailNotificationMode' 'disabled'}}">{{_ "Email_Notification_Mode_Disabled"}}</option>
<option value="all" selected="{{selected 'emailNotificationMode' 'all'}}">{{_ "Email_Notification_Mode_All"}}</option>
<option value="nothing" selected="{{selected 'emailNotificationMode' 'disabled'}}">{{_ "Email_Notification_Mode_Disabled"}}</option>
<option value="mentions" selected="{{selected 'emailNotificationMode' 'mentions'}}">{{_ "Email_Notification_Mode_All"}}</option>
</select>
{{> icon block="rc-select__arrow" icon="arrow-down" }}
</div>

@ -10,8 +10,8 @@ const notificationLabels = {
};
const emailLabels = {
disabled: 'Email_Notification_Mode_Disabled',
all: 'Email_Notification_Mode_All'
nothing: 'Email_Notification_Mode_Disabled',
mentions: 'Email_Notification_Mode_All'
};
function checkedSelected(property, value, defaultValue=undefined) {

@ -67,6 +67,13 @@ Meteor.methods({
settings.roomsListExhibitionMode = ['category', 'unread', 'activity'].includes(settings.roomsListExhibitionMode) ? settings.roomsListExhibitionMode : 'category';
}
// Keep compatibility with old values
if (settings.emailNotificationMode === 'all') {
settings.emailNotificationMode = 'mentions';
} else if (settings.emailNotificationMode === 'disabled') {
settings.emailNotificationMode = 'nothing';
}
RocketChat.models.Users.setPreferences(user._id, settings);
// propagate changed notification preferences
@ -91,9 +98,13 @@ Meteor.methods({
if (settings.emailNotificationMode === 'default') {
RocketChat.models.Subscriptions.clearEmailNotificationUserPreferences(user._id);
} else {
RocketChat.models.Subscriptions.updateEmailNotificationUserPreferences(user._id, settings.emailNotificationMode === 'disabled' ? 'nothing' : settings.emailNotificationMode);
RocketChat.models.Subscriptions.updateEmailNotificationUserPreferences(user._id, settings.emailNotificationMode);
}
}
if (Array.isArray(settings.highlights)) {
RocketChat.models.Subscriptions.updateUserHighlights(user._id, settings.highlights);
}
});
return true;

@ -76,7 +76,7 @@ RocketChat.Migrations.add({
emailPrefOrigin: { $exists: false }
}, {
$set: {
emailNotifications: user.settings.preferences.emailNotificationMode === 'disabled' ? 'nothing' : user.settings.preferences.emailNotificationMode,
emailNotifications: user.settings.preferences.emailNotificationMode === 'disabled' || user.settings.preferences.emailNotificationMode === 'nothing' ? 'nothing' : 'mentions',
emailPrefOrigin: 'user'
}
}, {

@ -0,0 +1,72 @@
RocketChat.Migrations.add({
version: 118,
up() {
RocketChat.models.Subscriptions.update({
emailNotifications: 'all',
emailPrefOrigin: 'user'
}, {
$set: {
emailNotifications: 'mentions'
}
}, {
multi:true
});
RocketChat.models.Users.update({
'settings.preferences.emailNotificationMode': 'disabled'
}, {
$set: {
'settings.preferences.emailNotificationMode': 'nothing'
}
}, {
multi:true
});
RocketChat.models.Users.update({
'settings.preferences.emailNotificationMode': 'all'
}, {
$set: {
'settings.preferences.emailNotificationMode': 'mentions'
}
}, {
multi:true
});
RocketChat.models.Settings.update({
_id: 'Accounts_Default_User_Preferences_emailNotificationMode',
value: 'disabled'
}, {
$set: {
value: 'nothing'
}
});
RocketChat.models.Settings.update({
_id: 'Accounts_Default_User_Preferences_emailNotificationMode',
value: 'all'
}, {
$set: {
value: 'mentions'
}
});
// set user highlights on subscriptions
RocketChat.models.Users.find({
'settings.preferences.highlights.0': {$exists: true}
}, {
fields: {
'settings.preferences.highlights': 1
}
}).forEach(user => {
RocketChat.models.Subscriptions.update({
'u._id': user._id
}, {
$set: {
userHighlights: user.settings.preferences.highlights
}
}, {
multi: true
});
});
}
});

@ -15,7 +15,7 @@ export const preferences = {
saveMobileBandwidth: true,
collapseMediaByDefault: false,
autoImageLoad: true,
emailNotificationMode: 'all',
emailNotificationMode: 'mentions',
roomsListExhibitionMode: 'category',
unreadAlert: true,
notificationsSoundVolume: 100,

@ -904,7 +904,7 @@ describe('[Administration]', () => {
admin.accountsEmailNotificationMode.isVisible().should.be.true;
});
it('the offline email notification field value should be all', () => {
admin.accountsEmailNotificationMode.getValue().should.equal('all');
admin.accountsEmailNotificationMode.getValue().should.equal('mentions');
});
it('it should show the room counter sidebar field', () => {

Loading…
Cancel
Save