Add notification settings to control what statuses allow push notifications (#3829)

Этот коммит содержится в:
Joram Wilander
2016-08-23 08:47:25 -04:00
коммит произвёл GitHub
родитель c93ce7af3f
Коммит 065d01c121
5 изменённых файлов: 233 добавлений и 74 удалений

Просмотреть файл

@@ -565,7 +565,7 @@ func sendNotifications(teamId string, post *model.Post, team *model.Team, channe
} }
mentionedUserIds := make(map[string]bool) mentionedUserIds := make(map[string]bool)
alwaysNotifyUserIds := []string{} allActivityPushUserIds := []string{}
hereNotification := false hereNotification := false
updateMentionChans := []store.StoreChannel{} updateMentionChans := []store.StoreChannel{}
@@ -629,7 +629,7 @@ func sendNotifications(teamId string, post *model.Post, team *model.Team, channe
if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL && if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL &&
(post.UserId != profile.Id || post.Props["from_webhook"] == "true") && (post.UserId != profile.Id || post.Props["from_webhook"] == "true") &&
!post.IsSystemMessage() { !post.IsSystemMessage() {
alwaysNotifyUserIds = append(alwaysNotifyUserIds, profile.Id) allActivityPushUserIds = append(allActivityPushUserIds, profile.Id)
} }
} }
} }
@@ -705,13 +705,28 @@ func sendNotifications(teamId string, post *model.Post, team *model.Team, channe
if sendPushNotifications { if sendPushNotifications {
for _, id := range mentionedUsersList { for _, id := range mentionedUsersList {
if profileMap[id].NotifyProps["push"] != "none" { var status *model.Status
var err *model.AppError
if status, err = GetStatus(id); err != nil {
status = &model.Status{id, model.STATUS_OFFLINE, 0}
}
if profileMap[id].StatusAllowsPushNotification(status) {
sendPushNotification(post, profileMap[id], channel, senderName, true) sendPushNotification(post, profileMap[id], channel, senderName, true)
} }
} }
for _, id := range alwaysNotifyUserIds {
for _, id := range allActivityPushUserIds {
if _, ok := mentionedUserIds[id]; !ok { if _, ok := mentionedUserIds[id]; !ok {
sendPushNotification(post, profileMap[id], channel, senderName, false) var status *model.Status
var err *model.AppError
if status, err = GetStatus(id); err != nil {
status = &model.Status{id, model.STATUS_OFFLINE, 0}
}
if profileMap[id].StatusAllowsPushNotification(status) {
sendPushNotification(post, profileMap[id], channel, senderName, false)
}
} }
} }
} }

Просмотреть файл

@@ -373,6 +373,24 @@ func (u *User) IsLDAPUser() bool {
return false return false
} }
func (u *User) StatusAllowsPushNotification(status *Status) bool {
props := u.NotifyProps
if props["push"] == "none" {
return false
}
if pushStatus, ok := props["push_status"]; pushStatus == STATUS_ONLINE || !ok {
return true
} else if pushStatus == STATUS_AWAY && (status.Status == STATUS_AWAY || status.Status == STATUS_OFFLINE) {
return true
} else if pushStatus == STATUS_OFFLINE && status.Status == STATUS_OFFLINE {
return true
}
return false
}
// UserFromJson will decode the input and return a User // UserFromJson will decode the input and return a User
func UserFromJson(data io.Reader) *User { func UserFromJson(data io.Reader) *User {
decoder := json.NewDecoder(data) decoder := json.NewDecoder(data)

Просмотреть файл

@@ -33,7 +33,7 @@ export default class SettingItemMin extends React.Component {
> >
<li className='col-sm-9 section-title'>{this.props.title}</li> <li className='col-sm-9 section-title'>{this.props.title}</li>
{editButton} {editButton}
<li className='col-sm-9 section-describe'>{this.props.describe}</li> <li className='col-sm-10 section-describe'>{this.props.describe}</li>
</ul> </ul>
); );
} }

Просмотреть файл

@@ -11,40 +11,48 @@ import Client from 'client/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx';
import * as UserAgent from 'utils/user_agent.jsx'; import * as UserAgent from 'utils/user_agent.jsx';
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
import EmailNotificationSetting from './email_notification_setting.jsx'; import EmailNotificationSetting from './email_notification_setting.jsx';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
function getNotificationsStateFromStores() { function getNotificationsStateFromStores() {
var user = UserStore.getCurrentUser(); const user = UserStore.getCurrentUser();
var soundNeeded = !UserAgent.isFirefox(); const soundNeeded = !UserAgent.isFirefox();
var sound = 'true'; let sound = 'true';
if (user.notify_props && user.notify_props.desktop_sound) { let desktop = 'default';
sound = user.notify_props.desktop_sound; let comments = 'never';
} let enableEmail = 'true';
var desktop = 'default'; let pushActivity = 'mention';
if (user.notify_props && user.notify_props.desktop) { let pushStatus = Constants.UserStatuses.ONLINE;
desktop = user.notify_props.desktop;
} if (user.notify_props) {
var comments = 'never'; if (user.notify_props.desktop_sound) {
if (user.notify_props && user.notify_props.comments) { sound = user.notify_props.desktop_sound;
comments = user.notify_props.comments; }
} if (user.notify_props.desktop) {
var enableEmail = 'true'; desktop = user.notify_props.desktop;
if (user.notify_props && user.notify_props.email) { }
enableEmail = user.notify_props.email; if (user.notify_props.comments) {
} comments = user.notify_props.comments;
var push = 'mention'; }
if (user.notify_props && user.notify_props.push) { if (user.notify_props.email) {
push = user.notify_props.push; enableEmail = user.notify_props.email;
}
if (user.notify_props.push) {
pushActivity = user.notify_props.push;
}
if (user.notify_props.push_status) {
pushStatus = user.notify_props.push_status;
}
} }
var usernameKey = false; let usernameKey = false;
var mentionKey = false; let mentionKey = false;
var customKeys = ''; let customKeys = '';
var firstNameKey = false; let firstNameKey = false;
var channelKey = false; let channelKey = false;
if (user.notify_props) { if (user.notify_props) {
if (user.notify_props.mention_keys) { if (user.notify_props.mention_keys) {
@@ -78,8 +86,9 @@ function getNotificationsStateFromStores() {
return { return {
notifyLevel: desktop, notifyLevel: desktop,
notifyPushLevel: push,
enableEmail, enableEmail,
pushActivity,
pushStatus,
soundNeeded, soundNeeded,
enableSound: sound, enableSound: sound,
usernameKey, usernameKey,
@@ -123,7 +132,8 @@ export default class NotificationsTab extends React.Component {
data.email = this.state.enableEmail; data.email = this.state.enableEmail;
data.desktop_sound = this.state.enableSound; data.desktop_sound = this.state.enableSound;
data.desktop = this.state.notifyLevel; data.desktop = this.state.notifyLevel;
data.push = this.state.notifyPushLevel; data.push = this.state.pushActivity;
data.push_status = this.state.pushStatus;
data.comments = this.state.notifyCommentsLevel; data.comments = this.state.notifyCommentsLevel;
var mentionKeys = []; var mentionKeys = [];
@@ -147,6 +157,7 @@ export default class NotificationsTab extends React.Component {
() => { () => {
this.props.updateSection(''); this.props.updateSection('');
AsyncClient.getMe(); AsyncClient.getMe();
$('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
}, },
(err) => { (err) => {
this.setState({serverError: err.message}); this.setState({serverError: err.message});
@@ -195,8 +206,13 @@ export default class NotificationsTab extends React.Component {
this.refs.wrapper.focus(); this.refs.wrapper.focus();
} }
handlePushRadio(notifyPushLevel) { handlePushRadio(pushActivity) {
this.setState({notifyPushLevel}); this.setState({pushActivity});
this.refs.wrapper.focus();
}
handlePushStatusRadio(pushStatus) {
this.setState({pushStatus});
this.refs.wrapper.focus(); this.refs.wrapper.focus();
} }
@@ -245,22 +261,93 @@ export default class NotificationsTab extends React.Component {
} }
createPushNotificationSection() { createPushNotificationSection() {
var handleUpdateDesktopSection; let handleUpdateDesktopSection;
if (this.props.activeSection === 'push') { if (this.props.activeSection === 'push') {
var notifyActive = [false, false, false];
if (this.state.notifyPushLevel === 'all') {
notifyActive[0] = true;
} else if (this.state.notifyPushLevel === 'none') {
notifyActive[2] = true;
} else {
notifyActive[1] = true;
}
let inputs = []; let inputs = [];
let extraInfo = null; let extraInfo = null;
let submit = null; let submit = null;
if (global.window.mm_config.SendPushNotifications === 'true') { if (global.window.mm_config.SendPushNotifications === 'true') {
const pushActivityRadio = [false, false, false];
if (this.state.pushActivity === 'all') {
pushActivityRadio[0] = true;
} else if (this.state.pushActivity === 'none') {
pushActivityRadio[2] = true;
} else {
pushActivityRadio[1] = true;
}
const pushStatusRadio = [false, false, false];
if (this.state.pushStatus === Constants.UserStatuses.ONLINE) {
pushStatusRadio[0] = true;
} else if (this.state.pushStatus === Constants.UserStatuses.AWAY) {
pushStatusRadio[1] = true;
} else {
pushStatusRadio[2] = true;
}
let pushStatusSettings;
if (this.state.pushActivity !== 'none') {
pushStatusSettings = (
<div>
<hr/>
<div className='radio'>
<label>
<input
type='radio'
name='pushNotificationStatus'
checked={pushStatusRadio[0]}
onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.ONLINE)}
/>
<FormattedMessage
id='user.settings.push_notification.online'
defaultMessage='Online, away or offline'
/>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
type='radio'
name='pushNotificationStatus'
checked={pushStatusRadio[1]}
onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.AWAY)}
/>
<FormattedMessage
id='user.settings.push_notification.away'
defaultMessage='Away or offline'
/>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
type='radio'
name='pushNotificationStatus'
checked={pushStatusRadio[2]}
onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.OFFLINE)}
/>
<FormattedMessage
id='user.settings.push_notification.offline'
defaultMessage='Offline'
/>
</label>
</div>
</div>
);
extraInfo = (
<span>
<FormattedMessage
id='user.settings.push_notification.status_info'
defaultMessage='Notification alerts are pushed to your mobile device depending on your online status.'
/>
</span>
);
}
inputs.push( inputs.push(
<div key='userNotificationLevelOption'> <div key='userNotificationLevelOption'>
<div className='radio'> <div className='radio'>
@@ -268,7 +355,7 @@ export default class NotificationsTab extends React.Component {
<input <input
type='radio' type='radio'
name='pushNotificationLevel' name='pushNotificationLevel'
checked={notifyActive[0]} checked={pushActivityRadio[0]}
onChange={this.handlePushRadio.bind(this, 'all')} onChange={this.handlePushRadio.bind(this, 'all')}
/> />
<FormattedMessage <FormattedMessage
@@ -283,7 +370,7 @@ export default class NotificationsTab extends React.Component {
<input <input
type='radio' type='radio'
name='pushNotificationLevel' name='pushNotificationLevel'
checked={notifyActive[1]} checked={pushActivityRadio[1]}
onChange={this.handlePushRadio.bind(this, 'mention')} onChange={this.handlePushRadio.bind(this, 'mention')}
/> />
<FormattedMessage <FormattedMessage
@@ -298,7 +385,7 @@ export default class NotificationsTab extends React.Component {
<input <input
type='radio' type='radio'
name='pushNotificationLevel' name='pushNotificationLevel'
checked={notifyActive[2]} checked={pushActivityRadio[2]}
onChange={this.handlePushRadio.bind(this, 'none')} onChange={this.handlePushRadio.bind(this, 'none')}
/> />
<FormattedMessage <FormattedMessage
@@ -307,18 +394,17 @@ export default class NotificationsTab extends React.Component {
/> />
</label> </label>
</div> </div>
<br/>
<span>
<FormattedMessage
id='user.settings.push_notification.info'
defaultMessage='Notification alerts are pushed to your mobile device when there is activity in Mattermost.'
/>
</span>
{pushStatusSettings}
</div> </div>
); );
extraInfo = (
<span>
<FormattedMessage
id='user.settings.push_notification.info'
defaultMessage='Notification alerts are pushed to your mobile device when there is activity in Mattermost.'
/>
</span>
);
submit = this.handleSubmit; submit = this.handleSubmit;
} else { } else {
inputs.push( inputs.push(
@@ -347,14 +433,30 @@ export default class NotificationsTab extends React.Component {
} }
let describe = ''; let describe = '';
if (this.state.notifyPushLevel === 'all') { if (this.state.pushActivity === 'all') {
describe = ( if (this.state.pushStatus === Constants.UserStatuses.AWAY) {
<FormattedMessage describe = (
id='user.settings.push_notification.allActivity' <FormattedMessage
defaultMessage='For all activity' id='user.settings.push_notification.allActivityAway'
/> defaultMessage='For all activity when away or offline'
); />
} else if (this.state.notifyPushLevel === 'none') { );
} else if (this.state.pushStatus === Constants.UserStatuses.OFFLINE) {
describe = (
<FormattedMessage
id='user.settings.push_notification.allActivityOffline'
defaultMessage='For all activity when offline'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.push_notification.allActivityOnline'
defaultMessage='For all activity when online, away or offline'
/>
);
}
} else if (this.state.pushActivity === 'none') {
describe = ( describe = (
<FormattedMessage <FormattedMessage
id='user.settings.notifications.never' id='user.settings.notifications.never'
@@ -369,12 +471,28 @@ export default class NotificationsTab extends React.Component {
/> />
); );
} else { } else {
describe = ( if (this.state.pushStatus === Constants.UserStatuses.AWAY) { //eslint-disable-line no-lonely-if
<FormattedMessage describe = (
id='user.settings.push_notification.onlyMentions' <FormattedMessage
defaultMessage='For mentions and direct messages' id='user.settings.push_notification.onlyMentionsAway'
/> defaultMessage='For mentions and direct messages when away or offline'
); />
);
} else if (this.state.pushStatus === Constants.UserStatuses.OFFLINE) {
describe = (
<FormattedMessage
id='user.settings.push_notification.onlyMentionsOffline'
defaultMessage='For mentions and direct messages when offline'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.push_notification.onlyMentionsOnline'
defaultMessage='For mentions and direct messages when online, away or offline'
/>
);
}
} }
handleUpdateDesktopSection = function updateDesktopSection() { handleUpdateDesktopSection = function updateDesktopSection() {

Просмотреть файл

@@ -1890,12 +1890,20 @@
"user.settings.notifications.title": "Notification Settings", "user.settings.notifications.title": "Notification Settings",
"user.settings.notifications.usernameMention": "Your username mentioned \"@{username}\"", "user.settings.notifications.usernameMention": "Your username mentioned \"@{username}\"",
"user.settings.notifications.wordsTrigger": "Words that trigger mentions", "user.settings.notifications.wordsTrigger": "Words that trigger mentions",
"user.settings.push_notification.allActivity": "For all activity", "user.settings.push_notification.online": "Online, away or offline",
"user.settings.push_notification.away": "Away or offline",
"user.settings.push_notification.offline": "Offline",
"user.settings.push_notification.status_info": "Notification alerts are pushed to your mobile device depending on your online status.",
"user.settings.push_notification.allActivityOnline": "For all activity when online, away or offline",
"user.settings.push_notification.allActivityAway": "For all activity when away or offline",
"user.settings.push_notification.allActivityOffline": "For all activity when offline",
"user.settings.push_notification.disabled": "Disabled by System Administrator", "user.settings.push_notification.disabled": "Disabled by System Administrator",
"user.settings.push_notification.disabled_long": "Push notifications for mobile devices have been disabled by your System Administrator.", "user.settings.push_notification.disabled_long": "Push notifications for mobile devices have been disabled by your System Administrator.",
"user.settings.push_notification.info": "Notification alerts are pushed to your mobile device when there is activity in Mattermost.", "user.settings.push_notification.info": "Notification alerts are pushed to your mobile device when there is activity in Mattermost.",
"user.settings.push_notification.off": "Off", "user.settings.push_notification.off": "Off",
"user.settings.push_notification.onlyMentions": "For mentions and direct messages", "user.settings.push_notification.onlyMentionsOnline": "For mentions and direct messages when online, away or offline",
"user.settings.push_notification.onlyMentionsAway": "For mentions and direct messages when away or offline",
"user.settings.push_notification.onlyMentionsOffline": "For mentions and direct messages when offline",
"user.settings.security.close": "Close", "user.settings.security.close": "Close",
"user.settings.security.currentPassword": "Current Password", "user.settings.security.currentPassword": "Current Password",
"user.settings.security.currentPasswordError": "Please enter your current password.", "user.settings.security.currentPasswordError": "Please enter your current password.",