Skip to content
Snippets Groups Projects
Commit cee841b9 authored by Gabriel Engel's avatar Gabriel Engel
Browse files

Merge pull request #2155 from RocketChat/improve-notifications

Improve notifications
parents 96eb5bb2 eb8b0bc8
No related branches found
No related tags found
No related merge requests found
Showing
with 415 additions and 51 deletions
......@@ -64,6 +64,7 @@ rocketchat:message-pin
rocketchat:message-star
rocketchat:migrations
rocketchat:oembed
rocketchat:push-notifications
rocketchat:slashcommands-invite
rocketchat:slashcommands-join
rocketchat:slashcommands-kick
......
......@@ -151,6 +151,7 @@ rocketchat:migrations@0.0.1
rocketchat:oauth2-server@1.4.0
rocketchat:oauth2-server-config@1.0.0
rocketchat:oembed@0.0.1
rocketchat:push-notifications@0.0.1
rocketchat:slashcommands-invite@0.0.1
rocketchat:slashcommands-join@0.0.1
rocketchat:slashcommands-kick@0.0.1
......
......@@ -42,6 +42,13 @@ RocketChat.sendMessage = (user, message, room, options) ->
Increment unread couter if direct messages
###
Meteor.defer ->
alwaysNotifyDesktopUsers = _.compact(_.map(RocketChat.models.Subscriptions.findAlwaysNotifyDesktopUsersByRoomId(room._id).fetch(), (subscription) -> return subscription?.u?._id));
dontNotifyDesktopUsers = _.compact(_.map(RocketChat.models.Subscriptions.findDontNotifyDesktopUsersByRoomId(room._id).fetch(), (subscription) -> return subscription?.u?._id));
alwaysNotifyMobileUsers = _.compact(_.map(RocketChat.models.Subscriptions.findAlwaysNotifyMobileUsersByRoomId(room._id).fetch(), (subscription) -> return subscription?.u?._id));
dontNotifyMobileUsers = _.compact(_.map(RocketChat.models.Subscriptions.findDontNotifyMobileUsersByRoomId(room._id).fetch(), (subscription) -> return subscription?.u?._id));
userIdsToNotify = []
userIdsToPushNotify = []
if not room.t? or room.t is 'd'
......@@ -50,8 +57,10 @@ RocketChat.sendMessage = (user, message, room, options) ->
###
RocketChat.models.Subscriptions.incUnreadOfDirectForRoomIdExcludingUserId message.rid, message.u._id, 1
userOfMention = RocketChat.models.Users.findOne({_id: message.rid.replace(message.u._id, '')}, {fields: {username: 1, statusConnection: 1}})
if userOfMention?
userOfMentionId = message.rid.replace(message.u._id, '')
userOfMention = RocketChat.models.Users.findOne({_id: userOfMentionId}, {fields: {username: 1, statusConnection: 1}})
if userOfMention? and (dontNotifyDesktopUsers.indexOf(userOfMentionId) is -1 || alwaysNotifyDesktopUsers.indexOf(userOfMentionId) isnt -1)
RocketChat.Notifications.notifyUser userOfMention._id, 'notification',
title: "@#{user.username}"
text: message.msg
......@@ -61,6 +70,7 @@ RocketChat.sendMessage = (user, message, room, options) ->
type: room.t
name: room.name
if userOfMention? and (dontNotifyMobileUsers.indexOf(userOfMentionId) is -1 || alwaysNotifyMobileUsers.indexOf(userOfMentionId) isnt -1)
if Push.enabled is true and userOfMention.statusConnection isnt 'online'
Push.send
from: 'push'
......@@ -87,15 +97,76 @@ RocketChat.sendMessage = (user, message, room, options) ->
# @all?
toAll = mentionIds.indexOf('all') > -1
if mentionIds.length > 0
usersOfMention = RocketChat.models.Users.find({_id: {$in: mentionIds}}, {fields: {_id: 1, username: 1}}).fetch()
if mentionIds.length > 0 || alwaysNotifyDesktopUsers.length > 0
desktopMentionIds = _.union mentionIds, alwaysNotifyDesktopUsers
desktopMentionIds = _.difference desktopMentionIds, dontNotifyDesktopUsers
usersOfDesktopMentions = RocketChat.models.Users.find({_id: {$in: desktopMentionIds}}, {fields: {_id: 1, username: 1}}).fetch()
# when a user is mentioned on a channel, make the user join that channel
if room.t is 'c' and !toAll
for usersOfMentionItem in usersOfMention
for usersOfMentionItem in usersOfDesktopMentions
if room.usernames.indexOf(usersOfMentionItem.username) is -1
Meteor.runAsUser usersOfMentionItem._id, ->
Meteor.call 'joinRoom', room._id
# Get ids of all mentioned users and users with notifications set to always.
userIdsToNotify = _.pluck(usersOfDesktopMentions, '_id')
if mentionIds.length > 0 || alwaysNotifyMobileUsers.length > 0
mobileMentionIds = _.union mentionIds, alwaysNotifyMobileUsers
mobileMentionIds = _.difference mobileMentionIds, dontNotifyMobileUsers
usersOfMobileMentions = RocketChat.models.Users.find({_id: {$in: mobileMentionIds}}, {fields: {_id: 1, username: 1, statusConnection: 1}}).fetch()
# Get ids of all mentioned users and users with notifications set to always.
userIdsToPushNotify = _.pluck(_.filter(usersOfMobileMentions, (user) -> return user.statusConnection isnt 'online'), '_id')
# If the message is @all, notify all room users except for the sender.
if toAll and room.usernames?.length > 0
usersOfRoom = RocketChat.models.Users.find({
username: {$in: room.usernames},
_id: {$ne: user._id}},
{fields: {_id: 1, username: 1, status: 1, statusConnection: 1}})
.forEach (user) ->
if user.status in ['online', 'away', 'busy'] and user._id not in dontNotifyDesktopUsers
userIdsToNotify.push user._id
if user.statusConnection isnt 'online' and user._id not in dontNotifyMobileUsers
userIdsToPushNotify.push user._id
userIdsToNotify = _.unique userIdsToNotify
userIdsToPushNotify = _.unique userIdsToPushNotify
if userIdsToNotify.length > 0
for usersOfMentionId in userIdsToNotify
RocketChat.Notifications.notifyUser usersOfMentionId, 'notification',
title: "@#{user.username} @ ##{room.name}"
text: message.msg
payload:
rid: message.rid
sender: message.u
type: room.t
name: room.name
if userIdsToPushNotify.length > 0
if Push.enabled is true
Push.send
from: 'push'
title: "@#{user.username} @ ##{room.name}"
text: message.msg
apn:
text: "@#{user.username} @ ##{room.name}:\n#{message.msg}"
badge: 1
sound: 'chime'
payload:
host: Meteor.absoluteUrl()
rid: message.rid
sender: message.u
type: room.t
name: room.name
query:
userId: $in: userIdsToPushNotify
if mentionIds > 0
###
Update all other subscriptions of mentioned users to alert their owners and incrementing
the unread counter for mentions and direct messages
......@@ -107,51 +178,6 @@ RocketChat.sendMessage = (user, message, room, options) ->
# the mentioned user if mention isn't for all
RocketChat.models.Subscriptions.incUnreadForRoomIdAndUserIds message.rid, mentionIds, 1
# Get ids of all mentioned users.
userIdsToNotify = _.pluck(usersOfMention, '_id')
userIdsToPushNotify = userIdsToNotify
# If the message is @all, notify all room users except for the sender.
if toAll and room.usernames?.length > 0
usersOfRoom = RocketChat.models.Users.find({
username: {$in: room.usernames},
_id: {$ne: user._id}},
{fields: {_id: 1, username: 1, status: 1}})
.fetch()
onlineUsersOfRoom = _.filter usersOfRoom, (user) ->
user.status in ['online', 'away', 'busy']
userIdsToNotify = _.union userIdsToNotify, _.pluck(onlineUsersOfRoom, '_id')
userIdsToPushNotify = _.union userIdsToPushNotify, _.pluck(usersOfRoom, '_id')
if userIdsToNotify.length > 0
for usersOfMentionId in userIdsToNotify
RocketChat.Notifications.notifyUser usersOfMentionId, 'notification',
title: "@#{user.username} @ ##{room.name}"
text: message.msg
payload:
rid: message.rid
sender: message.u
type: room.t
name: room.name
if userIdsToPushNotify.length > 0
if Push.enabled is true
Push.send
from: 'push'
title: "@#{user.username} @ ##{room.name}"
text: message.msg
apn:
text: "@#{user.username} @ ##{room.name}:\n#{message.msg}"
badge: 1
sound: 'chime'
payload:
host: Meteor.absoluteUrl()
rid: message.rid
sender: message.u
type: room.t
name: room.name
query:
userId: $in: userIdsToPushNotify
###
Update all other subscriptions to alert their owners but witout incrementing
......
.flex-tab {
.push-notifications {
ul {
li {
margin-bottom: 20px;
}
}
form {
label {
display: block;
font-weight: bold;
margin-bottom: 5px;
}
div span {
font-size: 14px;
i.octicon {
font-size: 12px;
vertical-align: middle;
margin-left: 3px;
}
}
}
.submit {
margin-top: 30px;
text-align: center;
}
[data-edit] {
cursor: pointer;
}
}
}
Meteor.startup(function() {
RocketChat.TabBar.addButton({
groups: ['channel', 'privategroup', 'directmessage'],
id: 'push-notifications',
i18nTitle: 'Push_notifications',
icon: 'icon-bell',
template: 'pushNotificationsFlexTab',
order: 2
})
});
\ No newline at end of file
<template name="pushNotificationsFlexTab">
<div class="content">
<div class="list-view push-notifications">
<div class="status">
<h2>{{_ "Push_notifications"}}</h2>
</div>
<form>
<ul class="list clearfix">
<li>
<label>{{_ "Desktop_notifications"}}</label>
<div>
{{#if editing 'desktopNotifications'}}
<label><input type="radio" name="desktopNotifications" value="all" checked="{{$eq desktopNotifications 'all'}}" /> {{_ "All_messages"}}</label>
<label><input type="radio" name="desktopNotifications" value="mentions" checked="{{$eq desktopNotifications 'mentions'}}" /> {{_ "Mentions_default"}}</label>
<label><input type="radio" name="desktopNotifications" value="nothing" checked="{{$eq desktopNotifications 'nothing'}}" /> {{_ "Nothing"}}</label>
<button type="button" class="button secondary cancel">{{_ "Cancel"}}</button>
<button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
<span>{{desktopNotificationsValue}} <i class="octicon octicon-pencil" data-edit="desktopNotifications"></i></span>
{{/if}}
</div>
</li>
<li>
<label>{{_ "Mobile_push_notifications"}}</label>
<div>
{{#if editing 'mobilePushNotifications'}}
<label><input type="radio" name="mobilePushNotifications" value="all" checked="{{$eq mobilePushNotifications 'all'}}" /> {{_ "All_messages"}}</label>
<label><input type="radio" name="mobilePushNotifications" value="mentions" checked="{{$eq mobilePushNotifications 'mentions'}}" /> {{_ "Mentions_default"}}</label>
<label><input type="radio" name="mobilePushNotifications" value="nothing" checked="{{$eq mobilePushNotifications 'nothing'}}" /> {{_ "Nothing"}}</label>
<button type="button" class="button secondary cancel">{{_ "Cancel"}}</button>
<button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
<span>{{mobilePushNotificationsValue}} <i class="octicon octicon-pencil" data-edit="mobilePushNotifications"></i></span>
{{/if}}
</div>
</li>
</ul>
</form>
</div>
</div>
</template>
Template.pushNotificationsFlexTab.helpers({
"desktopNotifications"() {
const sub = ChatSubscription.findOne({ rid: Session.get('openedRoom') });
return sub ? sub.desktopNotifications : '';
},
"desktopNotificationsValue"() {
sub = ChatSubscription.findOne({ rid: Session.get('openedRoom') });
if (sub) {
switch (sub.desktopNotifications) {
case 'all':
return TAPi18n.__('All_messages');
break;
case 'nothing':
return TAPi18n.__('Nothing');
break;
default:
return TAPi18n.__('Mentions');
break;
}
}
},
"mobilePushNotifications"() {
const sub = ChatSubscription.findOne({ rid: Session.get('openedRoom') });
return sub ? sub.mobilePushNotifications : '';
},
"mobilePushNotificationsValue"() {
sub = ChatSubscription.findOne({ rid: Session.get('openedRoom') });
if (sub) {
switch (sub.mobilePushNotifications) {
case 'all':
return TAPi18n.__('All_messages');
break;
case 'nothing':
return TAPi18n.__('Nothing');
break;
default:
return TAPi18n.__('Mentions');
break;
}
}
},
"editing"(field) {
return Template.instance().editing.get() === field;
}
});
Template.pushNotificationsFlexTab.onCreated(function() {
this.editing = new ReactiveVar();
this.validateSetting = (field) => {
const value = this.$('input[name='+ field +']:checked').val();
if (['all', 'mentions', 'nothing'].indexOf(value) === -1) {
toastr.error(TAPi18n.__('Invalid_notification_setting_s', value || ''));
return false;
}
return true;
};
this.saveSetting = () => {
const field = this.editing.get();
const value = this.$('input[name='+ field +']:checked').val();
if (this.validateSetting(field)) {
Meteor.call('saveNotificationSettings', Session.get('openedRoom'), field, value, (err, result) => {
if (err) {
return toastr.error(TAPi18n.__(err.reason || err.message));
}
});
}
this.editing.set();
};
});
Template.pushNotificationsFlexTab.events({
'keydown input[type=text]'(e, instance) {
if (e.keyCode === 13) {
e.preventDefault();
instance.saveSetting();
}
},
'click [data-edit]'(e, instance) {
e.preventDefault();
instance.editing.set($(e.currentTarget).data('edit'));
setTimeout(function() { instance.$('input.editing').focus().select(); }, 100);
},
'click .cancel'(e, instance) {
e.preventDefault();
instance.editing.set();
},
'click .save'(e, instance) {
e.preventDefault();
instance.saveSetting();
}
});
\ No newline at end of file
{
"All_messages" : "All messages",
"Desktop_notifications" : "Desktop notifications",
"Invalid_notification_setting_s" : "Invalid notification setting: %s",
"Mentions" : "Mentions",
"Mentions_default" : "Mentions (default)",
"Mobile_push_notifications" : "Mobile push notifications",
"Nothing" : "Nothing",
"Push_notifications" : "Push notifications"
}
Package.describe({
name: 'rocketchat:push-notifications',
version: '0.0.1',
summary: 'Push Notifications Settings',
git: ''
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use([
'ecmascript',
'underscore',
'less@2.5.0',
'rocketchat:lib'
]);
api.addFiles([
'client/stylesheets/pushNotifications.less',
'client/views/pushNotificationsFlexTab.html',
'client/views/pushNotificationsFlexTab.js',
'client/tabBar.js'
], 'client');
api.addFiles([
'server/methods/saveNotificationSettings.js',
'server/models/Subscriptions.js'
], 'server');
// TAPi18n
api.use('templating', 'client');
var _ = Npm.require('underscore');
var fs = Npm.require('fs');
tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-push-notifications/i18n'), function(filename) {
if (fs.statSync('packages/rocketchat-push-notifications/i18n/' + filename).size > 16) {
return 'i18n/' + filename;
}
}));
api.use('tap:i18n');
api.addFiles(tapi18nFiles);
});
Package.onTest(function(api) {
});
Meteor.methods({
saveNotificationSettings: function(rid, field, value) {
if (!Meteor.userId()) {
throw new Meteor.Error('invalid-user', 'Invalid user');
}
check(rid, String);
check(field, String);
check(value, String);
if (['desktopNotifications', 'mobilePushNotifications'].indexOf(field) === -1) {
throw new Meteor.Error('invalid-settings', 'Invalid settings field');
}
if (['all', 'mentions', 'nothing'].indexOf(value) === -1) {
throw new Meteor.Error('invalid-settings', 'Invalid settings value');
}
subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(rid, Meteor.userId());
if (!subscription) {
throw new Meteor.Error('invalid-subscription', 'Invalid subscription');
}
if (field === 'desktopNotifications') {
RocketChat.models.Subscriptions.updateDesktopNotificationsById(subscription._id, value);
} else if (field === 'mobilePushNotifications') {
RocketChat.models.Subscriptions.updateMobilePushNotificationsById(subscription._id, value);
}
return true;
}
})
\ No newline at end of file
RocketChat.models.Subscriptions.updateDesktopNotificationsById = function(_id, desktopNotifications) {
query = {
_id: _id
}
update = {
$set: {
desktopNotifications: desktopNotifications
}
}
return this.update(query, update);
}
RocketChat.models.Subscriptions.updateMobilePushNotificationsById = function(_id, mobilePushNotifications) {
query = {
_id: _id
}
update = {
$set: {
mobilePushNotifications: mobilePushNotifications
}
}
return this.update(query, update);
}
RocketChat.models.Subscriptions.findAlwaysNotifyDesktopUsersByRoomId = function(roomId) {
query = {
rid: roomId,
desktopNotifications: 'all'
}
return this.find(query);
}
RocketChat.models.Subscriptions.findDontNotifyDesktopUsersByRoomId = function(roomId) {
query = {
rid: roomId,
desktopNotifications: 'nothing'
}
return this.find(query);
}
RocketChat.models.Subscriptions.findAlwaysNotifyMobileUsersByRoomId = function(roomId) {
query = {
rid: roomId,
mobilePushNotifications: 'all'
}
return this.find(query);
}
RocketChat.models.Subscriptions.findDontNotifyMobileUsersByRoomId = function(roomId) {
query = {
rid: roomId,
mobilePushNotifications: 'nothing'
}
return this.find(query);
}
\ No newline at end of file
if Meteor.isCordova
document.addEventListener 'pause', ->
UserPresence.setAway()
readMessage.disable()
document.addEventListener 'resume', ->
UserPresence.setOnline()
\ No newline at end of file
UserPresence.setOnline()
readMessage.enable()
\ No newline at end of file
......@@ -14,3 +14,5 @@ Meteor.publish 'subscription', ->
alert: 1
unread: 1
archived: 1
desktopNotifications: 1
mobilePushNotifications: 1
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment