summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/post.go383
-rw-r--r--i18n/en.json8
-rw-r--r--model/user.go1
-rw-r--r--utils/config.go1
-rw-r--r--webapp/components/user_settings/user_settings_notifications.jsx164
-rw-r--r--webapp/i18n/en.json5
6 files changed, 375 insertions, 187 deletions
diff --git a/api/post.go b/api/post.go
index 2676bcd20..92cbaf390 100644
--- a/api/post.go
+++ b/api/post.go
@@ -465,39 +465,28 @@ func handleWebhookEvents(c *Context, post *model.Post, team *model.Team, channel
}
func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *model.Channel, profileMap map[string]*model.User, members []model.ChannelMember) {
- var channelName string
- var bodyText string
- var subjectText string
-
- var mentionedUsers []string
+ if post.IsSystemMessage() {
+ return
+ }
if _, ok := profileMap[post.UserId]; !ok {
l4g.Error(utils.T("api.post.send_notifications_and_forget.user_id.error"), post.UserId)
return
}
- senderName := profileMap[post.UserId].Username
- toEmailMap := make(map[string]bool)
+ mentionedUserIds := make(map[string]bool)
+ alwaysNotifyUserIds := []string{}
if channel.Type == model.CHANNEL_DIRECT {
var otherUserId string
if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId {
otherUserId = userIds[1]
- channelName = profileMap[userIds[1]].Username
} else {
otherUserId = userIds[0]
- channelName = profileMap[userIds[0]].Username
}
- otherUser := profileMap[otherUserId]
- sendEmail := true
- if _, ok := otherUser.NotifyProps["email"]; ok && otherUser.NotifyProps["email"] == "false" {
- sendEmail = false
- }
- if sendEmail && (otherUser.IsOffline() || otherUser.IsAway()) {
- toEmailMap[otherUserId] = true
- }
+ mentionedUserIds[otherUserId] = true
} else {
// Find out who is a member of the channel, only keep those profiles
@@ -534,6 +523,10 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
if profile.NotifyProps["channel"] == "true" {
keywordMap["@channel"] = append(keywordMap["@channel"], profile.Id)
}
+
+ if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL && (post.UserId != profile.Id || post.Props["from_webhook"] == "true") {
+ alwaysNotifyUserIds = append(alwaysNotifyUserIds, profile.Id)
+ }
}
// Build a map as a list of unique user_ids that are mentioned in this post
@@ -576,179 +569,54 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
if post.UserId == userId && post.Props["from_webhook"] != "true" {
continue
}
- sendEmail := true
- if _, ok := profileMap[userId].NotifyProps["email"]; ok && profileMap[userId].NotifyProps["email"] == "false" {
- sendEmail = false
- }
- if sendEmail && (profileMap[userId].IsAway() || profileMap[userId].IsOffline()) {
- toEmailMap[userId] = true
- } else {
- toEmailMap[userId] = false
- }
+
+ mentionedUserIds[userId] = true
}
}
- for id := range toEmailMap {
+ for id := range mentionedUserIds {
go updateMentionCount(post.ChannelId, id)
}
}
- if len(toEmailMap) != 0 {
- mentionedUsers = make([]string, 0, len(toEmailMap))
- for k := range toEmailMap {
- mentionedUsers = append(mentionedUsers, k)
- }
-
- teamURL := c.GetSiteURL() + "/" + team.Name
-
- // Build and send the emails
- tm := time.Unix(post.CreateAt/1000, 0)
-
- for id, doSend := range toEmailMap {
+ mentionedUsersList := make([]string, 0, len(mentionedUserIds))
- if !doSend {
- continue
- }
+ senderName := profileMap[post.UserId].Username
- // skip if inactive
- if profileMap[id].DeleteAt > 0 {
- continue
- }
+ for id := range mentionedUserIds {
+ mentionedUsersList = append(mentionedUsersList, id)
+ }
- userLocale := utils.GetUserTranslations(profileMap[id].Locale)
+ if utils.Cfg.EmailSettings.SendEmailNotifications {
+ for _, id := range mentionedUsersList {
+ userAllowsEmails := profileMap[id].NotifyProps["email"] != "false"
- if channel.Type == model.CHANNEL_DIRECT {
- bodyText = userLocale("api.post.send_notifications_and_forget.message_body")
- subjectText = userLocale("api.post.send_notifications_and_forget.message_subject")
- } else {
- bodyText = userLocale("api.post.send_notifications_and_forget.mention_body")
- subjectText = userLocale("api.post.send_notifications_and_forget.mention_subject")
- channelName = channel.DisplayName
+ if userAllowsEmails && (profileMap[id].IsAway() || profileMap[id].IsOffline()) {
+ sendNotificationEmail(c, post, profileMap[id], channel, team, senderName)
}
+ }
+ }
- month := userLocale(tm.Month().String())
- day := fmt.Sprintf("%d", tm.Day())
- year := fmt.Sprintf("%d", tm.Year())
- zone, _ := tm.Zone()
-
- subjectPage := utils.NewHTMLTemplate("post_subject", profileMap[id].Locale)
- subjectPage.Props["Subject"] = userLocale("api.templates.post_subject",
- map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName,
- "Month": month[:3], "Day": day, "Year": year})
- subjectPage.Props["SiteName"] = utils.Cfg.TeamSettings.SiteName
-
- bodyPage := utils.NewHTMLTemplate("post_body", profileMap[id].Locale)
- bodyPage.Props["SiteURL"] = c.GetSiteURL()
- bodyPage.Props["PostMessage"] = model.ClearMentionTags(post.Message)
- bodyPage.Props["TeamLink"] = teamURL + "/channels/" + channel.Name
- bodyPage.Props["BodyText"] = bodyText
- bodyPage.Props["Button"] = userLocale("api.templates.post_body.button")
- bodyPage.Html["Info"] = template.HTML(userLocale("api.templates.post_body.info",
- map[string]interface{}{"ChannelName": channelName, "SenderName": senderName,
- "Hour": fmt.Sprintf("%02d", tm.Hour()), "Minute": fmt.Sprintf("%02d", tm.Minute()),
- "TimeZone": zone, "Month": month, "Day": day}))
-
- // attempt to fill in a message body if the post doesn't have any text
- if len(strings.TrimSpace(bodyPage.Props["PostMessage"])) == 0 && len(post.Filenames) > 0 {
- // extract the filenames from their paths and determine what type of files are attached
- filenames := make([]string, len(post.Filenames))
- onlyImages := true
- for i, filename := range post.Filenames {
- var err error
- if filenames[i], err = url.QueryUnescape(filepath.Base(filename)); err != nil {
- // this should never error since filepath was escaped using url.QueryEscape
- filenames[i] = filepath.Base(filename)
- }
-
- ext := filepath.Ext(filename)
- onlyImages = onlyImages && model.IsFileExtImage(ext)
- }
- filenamesString := strings.Join(filenames, ", ")
-
- var attachmentPrefix string
- if onlyImages {
- attachmentPrefix = "Image"
- } else {
- attachmentPrefix = "File"
- }
- if len(post.Filenames) > 1 {
- attachmentPrefix += "s"
- }
-
- bodyPage.Props["PostMessage"] = userLocale("api.post.send_notifications_and_forget.sent",
- map[string]interface{}{"Prefix": attachmentPrefix, "Filenames": filenamesString})
- }
+ sendPushNotifications := false
+ if *utils.Cfg.EmailSettings.SendPushNotifications {
+ pushServer := *utils.Cfg.EmailSettings.PushNotificationServer
+ if pushServer == model.MHPNS && (!utils.IsLicensed || !*utils.License.Features.MHPNS) {
+ l4g.Warn(utils.T("api.post.send_notifications_and_forget.push_notification.mhpnsWarn"))
+ sendPushNotifications = false
+ } else {
+ sendPushNotifications = true
+ }
+ }
- if err := utils.SendMail(profileMap[id].Email, subjectPage.Render(), bodyPage.Render()); err != nil {
- l4g.Error(utils.T("api.post.send_notifications_and_forget.send.error"), profileMap[id].Email, err)
+ if sendPushNotifications {
+ for _, id := range mentionedUsersList {
+ if profileMap[id].NotifyProps["push"] != "none" {
+ sendPushNotification(post, profileMap[id], channel, senderName, true)
}
-
- if *utils.Cfg.EmailSettings.SendPushNotifications {
- sessionChan := Srv.Store.Session().GetSessions(id)
- if result := <-sessionChan; result.Err != nil {
- l4g.Error(utils.T("api.post.send_notifications_and_forget.sessions.error"), id, result.Err)
- } else {
- sessions := result.Data.([]*model.Session)
- alreadySeen := make(map[string]string)
-
- pushServer := *utils.Cfg.EmailSettings.PushNotificationServer
- if pushServer == model.MHPNS && (!utils.IsLicensed || !*utils.License.Features.MHPNS) {
- l4g.Warn(utils.T("api.post.send_notifications_and_forget.push_notification.mhpnsWarn"))
- } else {
- for _, session := range sessions {
- if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" &&
- (strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")) {
- alreadySeen[session.DeviceId] = session.DeviceId
-
- msg := model.PushNotification{}
- if badge := <-Srv.Store.User().GetUnreadCount(id); badge.Err != nil {
- msg.Badge = 1
- l4g.Error(utils.T("store.sql_user.get_unread_count.app_error"), id, badge.Err)
- } else {
- msg.Badge = int(badge.Data.(int64))
- }
- msg.ServerId = utils.CfgDiagnosticId
- msg.ChannelId = channel.Id
- msg.ChannelName = channel.Name
-
- if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") {
- msg.Platform = model.PUSH_NOTIFY_APPLE
- msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":")
- } else if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":") {
- msg.Platform = model.PUSH_NOTIFY_ANDROID
- msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")
- }
-
- if *utils.Cfg.EmailSettings.PushNotificationContents == model.FULL_NOTIFICATION {
- if channel.Type == model.CHANNEL_DIRECT {
- msg.Category = model.CATEGORY_DM
- msg.Message = "@" + senderName + ": " + model.ClearMentionTags(post.Message)
- } else {
- msg.Message = "@" + senderName + " @ " + channelName + ": " + model.ClearMentionTags(post.Message)
- }
- } else {
- if channel.Type == model.CHANNEL_DIRECT {
- msg.Category = model.CATEGORY_DM
- msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message")
- } else {
- msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention") + channelName
- }
- }
-
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
- }
- httpClient := &http.Client{Transport: tr}
- request, _ := http.NewRequest("POST", pushServer+model.API_URL_SUFFIX_V1+"/send_push", strings.NewReader(msg.ToJson()))
-
- l4g.Debug(utils.T("api.post.send_notifications_and_forget.push_notification.debug"), msg.DeviceId, msg.Message)
- if _, err := httpClient.Do(request); err != nil {
- l4g.Error(utils.T("api.post.send_notifications_and_forget.push_notification.error"), id, err)
- }
- }
- }
- }
- }
+ }
+ for _, id := range alwaysNotifyUserIds {
+ if _, ok := mentionedUserIds[id]; !ok {
+ sendPushNotification(post, profileMap[id], channel, senderName, false)
}
}
}
@@ -756,6 +624,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
message := model.NewMessage(c.TeamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
message.Add("post", post.ToJson())
message.Add("channel_type", channel.Type)
+ message.Add("sender_name", senderName)
if len(post.Filenames) != 0 {
message.Add("otherFile", "true")
@@ -769,13 +638,173 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
}
}
- if len(mentionedUsers) != 0 {
- message.Add("mentions", model.ArrayToJson(mentionedUsers))
+ if len(mentionedUsersList) != 0 {
+ message.Add("mentions", model.ArrayToJson(mentionedUsersList))
}
go Publish(message)
}
+func sendNotificationEmail(c *Context, post *model.Post, user *model.User, channel *model.Channel, team *model.Team, senderName string) {
+ // skip if inactive
+ if user.DeleteAt > 0 {
+ return
+ }
+
+ var channelName string
+ var bodyText string
+ var subjectText string
+
+ teamURL := c.GetSiteURL() + "/" + team.Name
+ tm := time.Unix(post.CreateAt/1000, 0)
+
+ userLocale := utils.GetUserTranslations(user.Locale)
+
+ if channel.Type == model.CHANNEL_DIRECT {
+ bodyText = userLocale("api.post.send_notifications_and_forget.message_body")
+ subjectText = userLocale("api.post.send_notifications_and_forget.message_subject")
+ channelName = senderName
+ } else {
+ bodyText = userLocale("api.post.send_notifications_and_forget.mention_body")
+ subjectText = userLocale("api.post.send_notifications_and_forget.mention_subject")
+ channelName = channel.DisplayName
+ }
+
+ month := userLocale(tm.Month().String())
+ day := fmt.Sprintf("%d", tm.Day())
+ year := fmt.Sprintf("%d", tm.Year())
+ zone, _ := tm.Zone()
+
+ subjectPage := utils.NewHTMLTemplate("post_subject", user.Locale)
+ subjectPage.Props["Subject"] = userLocale("api.templates.post_subject",
+ map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName,
+ "Month": month[:3], "Day": day, "Year": year})
+ subjectPage.Props["SiteName"] = utils.Cfg.TeamSettings.SiteName
+
+ bodyPage := utils.NewHTMLTemplate("post_body", user.Locale)
+ bodyPage.Props["SiteURL"] = c.GetSiteURL()
+ bodyPage.Props["PostMessage"] = model.ClearMentionTags(post.Message)
+ bodyPage.Props["TeamLink"] = teamURL + "/channels/" + channel.Name
+ bodyPage.Props["BodyText"] = bodyText
+ bodyPage.Props["Button"] = userLocale("api.templates.post_body.button")
+ bodyPage.Html["Info"] = template.HTML(userLocale("api.templates.post_body.info",
+ map[string]interface{}{"ChannelName": channelName, "SenderName": senderName,
+ "Hour": fmt.Sprintf("%02d", tm.Hour()), "Minute": fmt.Sprintf("%02d", tm.Minute()),
+ "TimeZone": zone, "Month": month, "Day": day}))
+
+ // attempt to fill in a message body if the post doesn't have any text
+ if len(strings.TrimSpace(bodyPage.Props["PostMessage"])) == 0 && len(post.Filenames) > 0 {
+ // extract the filenames from their paths and determine what type of files are attached
+ filenames := make([]string, len(post.Filenames))
+ onlyImages := true
+ for i, filename := range post.Filenames {
+ var err error
+ if filenames[i], err = url.QueryUnescape(filepath.Base(filename)); err != nil {
+ // this should never error since filepath was escaped using url.QueryEscape
+ filenames[i] = filepath.Base(filename)
+ }
+
+ ext := filepath.Ext(filename)
+ onlyImages = onlyImages && model.IsFileExtImage(ext)
+ }
+ filenamesString := strings.Join(filenames, ", ")
+
+ var attachmentPrefix string
+ if onlyImages {
+ attachmentPrefix = "Image"
+ } else {
+ attachmentPrefix = "File"
+ }
+ if len(post.Filenames) > 1 {
+ attachmentPrefix += "s"
+ }
+
+ bodyPage.Props["PostMessage"] = userLocale("api.post.send_notifications_and_forget.sent",
+ map[string]interface{}{"Prefix": attachmentPrefix, "Filenames": filenamesString})
+ }
+
+ if err := utils.SendMail(user.Email, subjectPage.Render(), bodyPage.Render()); err != nil {
+ l4g.Error(utils.T("api.post.send_notifications_and_forget.send.error"), user.Email, err)
+ }
+}
+
+func sendPushNotification(post *model.Post, user *model.User, channel *model.Channel, senderName string, wasMentioned bool) {
+ var sessions []*model.Session
+ if result := <-Srv.Store.Session().GetSessions(user.Id); result.Err != nil {
+ l4g.Error(utils.T("api.post.send_notifications_and_forget.sessions.error"), user.Id, result.Err)
+ return
+ } else {
+ sessions = result.Data.([]*model.Session)
+ }
+
+ var channelName string
+
+ if channel.Type == model.CHANNEL_DIRECT {
+ channelName = senderName
+ } else {
+ channelName = channel.DisplayName
+ }
+
+ userLocale := utils.GetUserTranslations(user.Locale)
+
+ for _, session := range sessions {
+ if len(session.DeviceId) > 0 &&
+ (strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")) {
+
+ msg := model.PushNotification{}
+ if badge := <-Srv.Store.User().GetUnreadCount(user.Id); badge.Err != nil {
+ msg.Badge = 1
+ l4g.Error(utils.T("store.sql_user.get_unread_count.app_error"), user.Id, badge.Err)
+ } else {
+ msg.Badge = int(badge.Data.(int64))
+ }
+ msg.ServerId = utils.CfgDiagnosticId
+ msg.ChannelId = channel.Id
+ msg.ChannelName = channel.Name
+
+ if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") {
+ msg.Platform = model.PUSH_NOTIFY_APPLE
+ msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":")
+ } else if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":") {
+ msg.Platform = model.PUSH_NOTIFY_ANDROID
+ msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")
+ }
+
+ if *utils.Cfg.EmailSettings.PushNotificationContents == model.FULL_NOTIFICATION {
+ if channel.Type == model.CHANNEL_DIRECT {
+ msg.Category = model.CATEGORY_DM
+ msg.Message = "@" + senderName + ": " + model.ClearMentionTags(post.Message)
+ } else {
+ msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_in") + channelName + ": " + model.ClearMentionTags(post.Message)
+ }
+ } else {
+ if channel.Type == model.CHANNEL_DIRECT {
+ msg.Category = model.CATEGORY_DM
+ msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message")
+ } else if wasMentioned {
+ msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention") + channelName
+ } else {
+ msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_non_mention") + channelName
+ }
+ }
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
+ }
+ httpClient := &http.Client{Transport: tr}
+ request, _ := http.NewRequest("POST", *utils.Cfg.EmailSettings.PushNotificationServer+model.API_URL_SUFFIX_V1+"/send_push", strings.NewReader(msg.ToJson()))
+
+ l4g.Debug(utils.T("api.post.send_notifications_and_forget.push_notification.debug"), msg.DeviceId, msg.Message)
+ if _, err := httpClient.Do(request); err != nil {
+ l4g.Error(utils.T("api.post.send_notifications_and_forget.push_notification.error"), user.Id, err)
+ }
+
+ // notification sent, don't need to check other sessions
+ break
+ }
+ }
+}
+
func updateMentionCount(channelId, userId string) {
if result := <-Srv.Store.Channel().IncrementMentionCount(channelId, userId); result.Err != nil {
l4g.Error(utils.T("api.post.update_mention_count_and_forget.update_error"), userId, channelId, result.Err)
diff --git a/i18n/en.json b/i18n/en.json
index 84d6692bb..99ca3ed72 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -904,6 +904,14 @@
"translation": " mentioned you in "
},
{
+ "id": "api.post.send_notifications_and_forget.push_in",
+ "translation": " in "
+ },
+ {
+ "id": "api.post.send_notifications_and_forget.push_non_mention",
+ "translation": " posted in "
+ },
+ {
"id": "api.post.send_notifications_and_forget.push_message",
"translation": " sent you a direct message"
},
diff --git a/model/user.go b/model/user.go
index 15c281401..7dee67381 100644
--- a/model/user.go
+++ b/model/user.go
@@ -191,6 +191,7 @@ func (u *User) PreUpdate() {
func (u *User) SetDefaultNotifications() {
u.NotifyProps = make(map[string]string)
u.NotifyProps["email"] = "true"
+ u.NotifyProps["push"] = USER_NOTIFY_MENTION
u.NotifyProps["desktop"] = USER_NOTIFY_ALL
u.NotifyProps["desktop_sound"] = "true"
u.NotifyProps["mention_keys"] = u.Username + ",@" + u.Username
diff --git a/utils/config.go b/utils/config.go
index 35629718c..9ac1617cd 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -219,6 +219,7 @@ func getClientConfig(c *model.Config) map[string]string {
props["EnableDeveloper"] = strconv.FormatBool(*c.ServiceSettings.EnableDeveloper)
props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications)
+ props["SendPushNotifications"] = strconv.FormatBool(*c.EmailSettings.SendPushNotifications)
props["EnableSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.EnableSignUpWithEmail)
props["EnableSignInWithEmail"] = strconv.FormatBool(*c.EmailSettings.EnableSignInWithEmail)
props["EnableSignInWithUsername"] = strconv.FormatBool(*c.EmailSettings.EnableSignInWithUsername)
diff --git a/webapp/components/user_settings/user_settings_notifications.jsx b/webapp/components/user_settings/user_settings_notifications.jsx
index 6a3f598e2..9d60f27fa 100644
--- a/webapp/components/user_settings/user_settings_notifications.jsx
+++ b/webapp/components/user_settings/user_settings_notifications.jsx
@@ -30,6 +30,10 @@ function getNotificationsStateFromStores() {
if (user.notify_props && user.notify_props.email) {
email = user.notify_props.email;
}
+ var push = 'mention';
+ if (user.notify_props && user.notify_props.push) {
+ push = user.notify_props.push;
+ }
var usernameKey = false;
var mentionKey = false;
@@ -72,9 +76,20 @@ function getNotificationsStateFromStores() {
}
}
- return {notifyLevel: desktop, enableEmail: email, soundNeeded: soundNeeded, enableSound: sound,
- usernameKey: usernameKey, mentionKey: mentionKey, customKeys: customKeys, customKeysChecked: customKeys.length > 0,
- firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey};
+ return {
+ notifyLevel: desktop,
+ notifyPushLevel: push,
+ enableEmail: email,
+ soundNeeded,
+ enableSound: sound,
+ usernameKey,
+ mentionKey,
+ customKeys,
+ customKeysChecked: customKeys.length > 0,
+ firstNameKey,
+ allKey,
+ channelKey
+ };
}
const holders = defineMessages({
@@ -121,6 +136,7 @@ class NotificationsTab extends React.Component {
this.updateChannelKey = this.updateChannelKey.bind(this);
this.updateCustomMentionKeys = this.updateCustomMentionKeys.bind(this);
this.onCustomChange = this.onCustomChange.bind(this);
+ this.createPushNotificationSection = this.createPushNotificationSection.bind(this);
this.state = getNotificationsStateFromStores();
}
@@ -130,6 +146,7 @@ class NotificationsTab extends React.Component {
data.email = this.state.enableEmail;
data.desktop_sound = this.state.enableSound;
data.desktop = this.state.notifyLevel;
+ data.push = this.state.notifyPushLevel;
var mentionKeys = [];
if (this.state.usernameKey) {
@@ -185,15 +202,21 @@ class NotificationsTab extends React.Component {
this.updateState();
}
handleNotifyRadio(notifyLevel) {
- this.setState({notifyLevel: notifyLevel});
+ this.setState({notifyLevel});
+ ReactDOM.findDOMNode(this.refs.wrapper).focus();
+ }
+
+ handlePushRadio(notifyPushLevel) {
+ this.setState({notifyPushLevel});
ReactDOM.findDOMNode(this.refs.wrapper).focus();
}
+
handleEmailRadio(enableEmail) {
- this.setState({enableEmail: enableEmail});
+ this.setState({enableEmail});
ReactDOM.findDOMNode(this.refs.wrapper).focus();
}
handleSoundRadio(enableSound) {
- this.setState({enableSound: enableSound});
+ this.setState({enableSound});
ReactDOM.findDOMNode(this.refs.wrapper).focus();
}
updateUsernameKey(val) {
@@ -227,12 +250,126 @@ class NotificationsTab extends React.Component {
ReactDOM.findDOMNode(this.refs.customcheck).checked = true;
this.updateCustomMentionKeys();
}
+ createPushNotificationSection() {
+ var handleUpdateDesktopSection;
+ 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 = [];
+
+ inputs.push(
+ <div key='userNotificationLevelOption'>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={notifyActive[0]}
+ onChange={this.handlePushRadio.bind(this, 'all')}
+ />
+ <FormattedMessage
+ id='user.settings.push_notification.allActivity'
+ defaultMessage='For all activity'
+ />
+ </label>
+ <br/>
+ </div>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={notifyActive[1]}
+ onChange={this.handlePushRadio.bind(this, 'mention')}
+ />
+ <FormattedMessage
+ id='user.settings.push_notifications.onlyMentions'
+ defaultMessage='For mentions and direct messages'
+ />
+ </label>
+ <br/>
+ </div>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={notifyActive[2]}
+ onChange={this.handlePushRadio.bind(this, 'none')}
+ />
+ <FormattedMessage
+ id='user.settings.push_notifications.off'
+ defaultMessage='Off'
+ />
+ </label>
+ </div>
+ </div>
+ );
+
+ const extraInfo = (
+ <span>
+ <FormattedMessage
+ id='user.settings.push_notifications.info'
+ defaultMessage='Notification alerts are pushed to your mobile device when there is activity in Mattermost.'
+ />
+ </span>
+ );
+
+ return (
+ <SettingItemMax
+ title={Utils.localizeMessage('user.settings.notifications.push', 'Mobile push notifications')}
+ extraInfo={extraInfo}
+ inputs={inputs}
+ submit={this.handleSubmit}
+ server_error={this.state.serverError}
+ updateSection={this.handleCancel}
+ />
+ );
+ }
+
+ let describe = '';
+ if (this.state.notifyPushLevel === 'all') {
+ describe = (
+ <FormattedMessage
+ id='user.settings.push_notification.allActivity'
+ defaultMessage='For all activity'
+ />
+ );
+ } else if (this.state.notifyPushLevel === 'none') {
+ describe = (
+ <FormattedMessage
+ id='user.settings.push_notifications.off'
+ defaultMessage='Off'
+ />
+ );
+ } else {
+ describe = (
+ <FormattedMessage
+ id='user.settings.push_notifications.onlyMentions'
+ defaultMessage='For mentions and direct messages'
+ />
+ );
+ }
+
+ handleUpdateDesktopSection = function updateDesktopSection() {
+ this.props.updateSection('push');
+ }.bind(this);
+
+ return (
+ <SettingItemMin
+ title={Utils.localizeMessage('user.settings.notifications.push', 'Mobile push notifications')}
+ describe={describe}
+ updateSection={handleUpdateDesktopSection}
+ />
+ );
+ }
render() {
const {formatMessage} = this.props.intl;
- var serverError = null;
- if (this.state.serverError) {
- serverError = this.state.serverError;
- }
+ const serverError = this.state.serverError;
var user = this.props.user;
@@ -764,6 +901,11 @@ class NotificationsTab extends React.Component {
);
}
+ let pushNotificationSection;
+ if (global.window.mm_config.SendPushNotifications === 'true') {
+ pushNotificationSection = this.createPushNotificationSection();
+ }
+
return (
<div>
<div className='modal-header'>
@@ -809,6 +951,8 @@ class NotificationsTab extends React.Component {
<div className='divider-light'/>
{emailSection}
<div className='divider-light'/>
+ {pushNotificationSection}
+ <div className='divider-light'/>
{keysSection}
<div className='divider-dark'/>
</div>
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index e75691663..164d57ae2 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -1390,6 +1390,11 @@
"user.settings.modal.notifications": "Notifications",
"user.settings.modal.security": "Security",
"user.settings.modal.title": "Account Settings",
+ "user.settings.push_notification.off": "Off",
+ "user.settings.push_notification.onlyMentions": "For mentions and direct messages",
+ "user.settings.push_notification.allActivity": "For all activity",
+ "user.settings.push_notification.info": "Notification alerts are pushed to your mobile device when there is activity in Mattermost.",
+ "user.settings.notification.push": "Mobile push notifications",
"user.settings.notification.allActivity": "For all activity",
"user.settings.notification.soundConfig": "Please configure notification sounds in your browser settings",
"user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\"",