summaryrefslogtreecommitdiffstats
path: root/app/notification.go
diff options
context:
space:
mode:
authorJoram Wilander <jwawilander@gmail.com>2017-01-13 15:17:50 -0500
committerHarrison Healey <harrisonmhealey@gmail.com>2017-01-13 15:17:50 -0500
commit0e2b321e6f5ab5983bc3428aa455dac7012c36ee (patch)
treec3919a284cf13ddcb66a6f482b1c9bbd9f34fc9b /app/notification.go
parent97558f6a6ec4c53fa69035fb430ead209d9c222d (diff)
downloadchat-0e2b321e6f5ab5983bc3428aa455dac7012c36ee.tar.gz
chat-0e2b321e6f5ab5983bc3428aa455dac7012c36ee.tar.bz2
chat-0e2b321e6f5ab5983bc3428aa455dac7012c36ee.zip
Refactor and migrate more functions out of api into app package (#5063)
Diffstat (limited to 'app/notification.go')
-rw-r--r--app/notification.go394
1 files changed, 193 insertions, 201 deletions
diff --git a/app/notification.go b/app/notification.go
index d5e3c7b13..fc1d44f06 100644
--- a/app/notification.go
+++ b/app/notification.go
@@ -25,192 +25,189 @@ import (
)
func SendNotifications(post *model.Post, team *model.Team, channel *model.Channel) ([]string, *model.AppError) {
- mentionedUsersList := make([]string, 0)
- var fchan store.StoreChannel
- var senderUsername string
+ pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true)
+ fchan := Srv.Store.FileInfo().GetForPost(post.Id)
- if post.IsSystemMessage() {
- senderUsername = utils.T("system.message.name")
+ var profileMap map[string]*model.User
+ if result := <-pchan; result.Err != nil {
+ return nil, result.Err
} else {
- pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true)
- fchan = Srv.Store.FileInfo().GetForPost(post.Id)
+ profileMap = result.Data.(map[string]*model.User)
+ }
- var profileMap map[string]*model.User
- if result := <-pchan; result.Err != nil {
- return nil, result.Err
+ // If the user who made the post isn't in the channel, don't send a notification
+ if _, ok := profileMap[post.UserId]; !ok {
+ l4g.Debug(utils.T("api.post.send_notifications.user_id.debug"), post.Id, channel.Id, post.UserId)
+ return []string{}, nil
+ }
+
+ mentionedUserIds := make(map[string]bool)
+ allActivityPushUserIds := []string{}
+ hereNotification := false
+ channelNotification := false
+ allNotification := false
+ updateMentionChans := []store.StoreChannel{}
+
+ if channel.Type == model.CHANNEL_DIRECT {
+ var otherUserId string
+ if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId {
+ otherUserId = userIds[1]
} else {
- profileMap = result.Data.(map[string]*model.User)
+ otherUserId = userIds[0]
}
- // If the user who made the post isn't in the channel don't send a notification
- if _, ok := profileMap[post.UserId]; !ok {
- l4g.Debug(utils.T("api.post.send_notifications.user_id.debug"), post.Id, channel.Id, post.UserId)
- return []string{}, nil
+ mentionedUserIds[otherUserId] = true
+ if post.Props["from_webhook"] == "true" {
+ mentionedUserIds[post.UserId] = true
}
+ } else {
+ keywords := GetMentionKeywordsInChannel(profileMap)
- mentionedUserIds := make(map[string]bool)
- allActivityPushUserIds := []string{}
- hereNotification := false
- channelNotification := false
- allNotification := false
- updateMentionChans := []store.StoreChannel{}
+ var potentialOtherMentions []string
+ mentionedUserIds, potentialOtherMentions, hereNotification, channelNotification, allNotification = GetExplicitMentions(post.Message, keywords)
- if channel.Type == model.CHANNEL_DIRECT {
- var otherUserId string
- if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId {
- otherUserId = userIds[1]
+ // get users that have comment thread mentions enabled
+ if len(post.RootId) > 0 {
+ if result := <-Srv.Store.Post().Get(post.RootId); result.Err != nil {
+ return nil, result.Err
} else {
- otherUserId = userIds[0]
- }
-
- mentionedUserIds[otherUserId] = true
- if post.Props["from_webhook"] == "true" {
- mentionedUserIds[post.UserId] = true
- }
- } else {
- keywords := GetMentionKeywordsInChannel(profileMap)
-
- var potentialOtherMentions []string
- mentionedUserIds, potentialOtherMentions, hereNotification, channelNotification, allNotification = GetExplicitMentions(post.Message, keywords)
+ list := result.Data.(*model.PostList)
- // get users that have comment thread mentions enabled
- if len(post.RootId) > 0 {
- if result := <-Srv.Store.Post().Get(post.RootId); result.Err != nil {
- return nil, result.Err
- } else {
- list := result.Data.(*model.PostList)
-
- for _, threadPost := range list.Posts {
- if profile, ok := profileMap[threadPost.UserId]; ok {
- if profile.NotifyProps["comments"] == "any" || (profile.NotifyProps["comments"] == "root" && threadPost.Id == list.Order[0]) {
- mentionedUserIds[threadPost.UserId] = true
- }
- }
+ for _, threadPost := range list.Posts {
+ profile := profileMap[threadPost.UserId]
+ if profile.NotifyProps["comments"] == "any" || (profile.NotifyProps["comments"] == "root" && threadPost.Id == list.Order[0]) {
+ mentionedUserIds[threadPost.UserId] = true
}
}
}
+ }
- // prevent the user from mentioning themselves
- if post.Props["from_webhook"] != "true" {
- delete(mentionedUserIds, post.UserId)
- }
+ // prevent the user from mentioning themselves
+ if post.Props["from_webhook"] != "true" {
+ delete(mentionedUserIds, post.UserId)
+ }
- if len(potentialOtherMentions) > 0 {
- if result := <-Srv.Store.User().GetProfilesByUsernames(potentialOtherMentions, team.Id); result.Err == nil {
- outOfChannelMentions := result.Data.(map[string]*model.User)
- go sendOutOfChannelMentions(post, team.Id, outOfChannelMentions)
- }
+ if len(potentialOtherMentions) > 0 {
+ if result := <-Srv.Store.User().GetProfilesByUsernames(potentialOtherMentions, team.Id); result.Err == nil {
+ outOfChannelMentions := result.Data.(map[string]*model.User)
+ go sendOutOfChannelMentions(post, team.Id, outOfChannelMentions)
}
+ }
- // find which users in the channel are set up to always receive mobile notifications
- for _, profile := range profileMap {
- if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL &&
- (post.UserId != profile.Id || post.Props["from_webhook"] == "true") {
- allActivityPushUserIds = append(allActivityPushUserIds, profile.Id)
- }
+ // find which users in the channel are set up to always receive mobile notifications
+ for _, profile := range profileMap {
+ if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL &&
+ (post.UserId != profile.Id || post.Props["from_webhook"] == "true") &&
+ !post.IsSystemMessage() {
+ allActivityPushUserIds = append(allActivityPushUserIds, profile.Id)
}
}
+ }
- mentionedUsersList = make([]string, 0, len(mentionedUserIds))
- for id := range mentionedUserIds {
- mentionedUsersList = append(mentionedUsersList, id)
- updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, id))
- }
+ mentionedUsersList := make([]string, 0, len(mentionedUserIds))
+ for id := range mentionedUserIds {
+ mentionedUsersList = append(mentionedUsersList, id)
+ updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, id))
+ }
- var sender *model.User
- senderName := make(map[string]string)
- for _, id := range mentionedUsersList {
- senderName[id] = ""
- if profile, ok := profileMap[post.UserId]; ok {
- if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" {
- senderName[id] = value.(string)
+ var sender *model.User
+ senderName := make(map[string]string)
+ for _, id := range mentionedUsersList {
+ senderName[id] = ""
+ if post.IsSystemMessage() {
+ senderName[id] = utils.T("system.message.name")
+ } else if profile, ok := profileMap[post.UserId]; ok {
+ if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" {
+ senderName[id] = value.(string)
+ } else {
+ // Get the Display name preference from the receiver
+ if result := <-Srv.Store.Preference().Get(id, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, "name_format"); result.Err != nil {
+ // Show default sender's name if user doesn't set display settings.
+ senderName[id] = profile.Username
} else {
- //Get the Display name preference from the receiver
- if result := <-Srv.Store.Preference().Get(id, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, "name_format"); result.Err != nil {
- // Show default sender's name if user doesn't set display settings.
- senderName[id] = profile.Username
- } else {
- senderName[id] = profile.GetDisplayNameForPreference(result.Data.(model.Preference).Value)
- }
+ senderName[id] = profile.GetDisplayNameForPreference(result.Data.(model.Preference).Value)
}
- sender = profile
}
+ sender = profile
}
+ }
- if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" {
- senderUsername = value.(string)
- } else {
- senderUsername = profileMap[post.UserId].Username
- }
-
- if utils.Cfg.EmailSettings.SendEmailNotifications {
- for _, id := range mentionedUsersList {
- userAllowsEmails := profileMap[id].NotifyProps["email"] != "false"
+ var senderUsername string
+ if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" {
+ senderUsername = value.(string)
+ } else {
+ senderUsername = profileMap[post.UserId].Username
+ }
- var status *model.Status
- var err *model.AppError
- if status, err = GetStatus(id); err != nil {
- status = &model.Status{
- UserId: id,
- Status: model.STATUS_OFFLINE,
- Manual: false,
- LastActivityAt: 0,
- ActiveChannel: "",
- }
+ if utils.Cfg.EmailSettings.SendEmailNotifications {
+ for _, id := range mentionedUsersList {
+ userAllowsEmails := profileMap[id].NotifyProps["email"] != "false"
+
+ var status *model.Status
+ var err *model.AppError
+ if status, err = GetStatus(id); err != nil {
+ status = &model.Status{
+ UserId: id,
+ Status: model.STATUS_OFFLINE,
+ Manual: false,
+ LastActivityAt: 0,
+ ActiveChannel: "",
}
+ }
- if userAllowsEmails && status.Status != model.STATUS_ONLINE && profileMap[id].DeleteAt == 0 {
- if err := sendNotificationEmail(post, profileMap[id], channel, team, senderName[id], sender); err != nil {
- l4g.Error(err.Error())
- }
- }
+ if userAllowsEmails && status.Status != model.STATUS_ONLINE && profileMap[id].DeleteAt == 0 {
+ sendNotificationEmail(post, profileMap[id], channel, team, senderName[id], sender)
}
}
+ }
- T := utils.GetUserTranslations(profileMap[post.UserId].Locale)
-
- // If the channel has more than 1K users then @here is disabled
- if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
- hereNotification = false
- SendEphemeralPost(
- team.Id,
- post.UserId,
- &model.Post{
- ChannelId: post.ChannelId,
- Message: T("api.post.disabled_here", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}),
- CreateAt: post.CreateAt + 1,
- },
- )
- }
-
- // If the channel has more than 1K users then @channel is disabled
- if channelNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
- SendEphemeralPost(
- team.Id,
- post.UserId,
- &model.Post{
- ChannelId: post.ChannelId,
- Message: T("api.post.disabled_channel", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}),
- CreateAt: post.CreateAt + 1,
- },
- )
- }
-
- // If the channel has more than 1K users then @all is disabled
- if allNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
- SendEphemeralPost(
- team.Id,
- post.UserId,
- &model.Post{
- ChannelId: post.ChannelId,
- Message: T("api.post.disabled_all", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}),
- CreateAt: post.CreateAt + 1,
- },
- )
- }
-
- if hereNotification {
- statuses := GetAllStatuses()
+ T := utils.GetUserTranslations(profileMap[post.UserId].Locale)
+
+ // If the channel has more than 1K users then @here is disabled
+ if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
+ hereNotification = false
+ SendEphemeralPost(
+ team.Id,
+ post.UserId,
+ &model.Post{
+ ChannelId: post.ChannelId,
+ Message: T("api.post.disabled_here", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}),
+ CreateAt: post.CreateAt + 1,
+ },
+ )
+ }
+
+ // If the channel has more than 1K users then @channel is disabled
+ if channelNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
+ SendEphemeralPost(
+ team.Id,
+ post.UserId,
+ &model.Post{
+ ChannelId: post.ChannelId,
+ Message: T("api.post.disabled_channel", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}),
+ CreateAt: post.CreateAt + 1,
+ },
+ )
+ }
+
+ // If the channel has more than 1K users then @all is disabled
+ if allNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
+ SendEphemeralPost(
+ team.Id,
+ post.UserId,
+ &model.Post{
+ ChannelId: post.ChannelId,
+ Message: T("api.post.disabled_all", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}),
+ CreateAt: post.CreateAt + 1,
+ },
+ )
+ }
+
+ if hereNotification {
+ if result := <-Srv.Store.Status().GetOnline(); result.Err != nil {
+ return nil, result.Err
+ } else {
+ statuses := result.Data.([]*model.Status)
for _, status := range statuses {
if status.UserId == post.UserId {
continue
@@ -225,29 +222,43 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
}
}
}
+ }
- // Make sure all mention updates are complete to prevent race
- // Probably better to batch these DB updates in the future
- // MUST be completed before push notifications send
- for _, uchan := range updateMentionChans {
- if result := <-uchan; result.Err != nil {
- l4g.Warn(utils.T("api.post.update_mention_count_and_forget.update_error"), post.Id, post.ChannelId, result.Err)
- }
+ // Make sure all mention updates are complete to prevent race
+ // Probably better to batch these DB updates in the future
+ // MUST be completed before push notifications send
+ for _, uchan := range updateMentionChans {
+ if result := <-uchan; result.Err != nil {
+ l4g.Warn(utils.T("api.post.update_mention_count_and_forget.update_error"), post.Id, post.ChannelId, result.Err)
}
+ }
- 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
+ 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 sendPushNotifications {
+ for _, id := range mentionedUsersList {
+ var status *model.Status
+ var err *model.AppError
+ if status, err = GetStatus(id); err != nil {
+ status = &model.Status{id, model.STATUS_OFFLINE, false, 0, ""}
+ }
+
+ if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) {
+ sendPushNotification(post, profileMap[id], channel, senderName[id], true)
}
}
- if sendPushNotifications {
- for _, id := range mentionedUsersList {
+ for _, id := range allActivityPushUserIds {
+ if _, ok := mentionedUserIds[id]; !ok {
var status *model.Status
var err *model.AppError
if status, err = GetStatus(id); err != nil {
@@ -255,25 +266,7 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
}
if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) {
- if err := sendPushNotification(post, profileMap[id], channel, senderName[id], true); err != nil {
- l4g.Error(err.Error())
- }
- }
- }
-
- for _, id := range allActivityPushUserIds {
- if _, ok := mentionedUserIds[id]; !ok {
- var status *model.Status
- var err *model.AppError
- if status, err = GetStatus(id); err != nil {
- status = &model.Status{id, model.STATUS_OFFLINE, false, 0, ""}
- }
-
- if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) {
- if err := sendPushNotification(post, profileMap[id], channel, senderName[id], false); err != nil {
- l4g.Error(err.Error())
- }
- }
+ sendPushNotification(post, profileMap[id], channel, senderName[id], false)
}
}
}
@@ -287,7 +280,7 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
message.Add("sender_name", senderUsername)
message.Add("team_id", team.Id)
- if len(post.FileIds) != 0 && fchan != nil {
+ if len(post.FileIds) != 0 {
message.Add("otherFile", "true")
var infos []*model.FileInfo
@@ -314,7 +307,6 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
}
func sendNotificationEmail(post *model.Post, user *model.User, channel *model.Channel, team *model.Team, senderName string, sender *model.User) *model.AppError {
-
if channel.Type == model.CHANNEL_DIRECT && channel.TeamId != team.Id {
// this message is a cross-team DM so it we need to find a team that the recipient is on to use in the link
if result := <-Srv.Store.Team().GetTeamsByUserId(user.Id); result.Err != nil {
@@ -327,18 +319,15 @@ func sendNotificationEmail(post *model.Post, user *model.User, channel *model.Ch
for i := range teams {
if teams[i].Id == team.Id {
found = true
- team = teams[i]
break
}
}
- if !found {
- if len(teams) > 0 {
- team = teams[0]
- } else {
- // in case the user hasn't joined any teams we send them to the select_team page
- team = &model.Team{Name: "select_team", DisplayName: utils.Cfg.TeamSettings.SiteName}
- }
+ if !found && len(teams) > 0 {
+ team = teams[0]
+ } else {
+ // in case the user hasn't joined any teams we send them to the select_team page
+ team = &model.Team{Name: "select_team", DisplayName: utils.Cfg.TeamSettings.SiteName}
}
}
}
@@ -511,8 +500,9 @@ func sendPushNotification(post *model.Post, user *model.User, channel *model.Cha
tmpMessage := *model.PushNotificationFromJson(strings.NewReader(msg.ToJson()))
tmpMessage.SetDeviceIdAndPlatform(session.DeviceId)
if err := sendToPushProxy(tmpMessage); err != nil {
- l4g.Error(err.Error)
+ return err
}
+
if einterfaces.GetMetricsInterface() != nil {
einterfaces.GetMetricsInterface().IncrementPostSentPush()
}
@@ -539,11 +529,12 @@ func ClearPushNotification(userId string, channelId string) *model.AppError {
}
l4g.Debug(utils.T("api.post.send_notifications_and_forget.clear_push_notification.debug"), msg.DeviceId, msg.ChannelId)
+
for _, session := range sessions {
tmpMessage := *model.PushNotificationFromJson(strings.NewReader(msg.ToJson()))
tmpMessage.SetDeviceIdAndPlatform(session.DeviceId)
if err := sendToPushProxy(tmpMessage); err != nil {
- l4g.Error(err.Error)
+ return err
}
}
@@ -551,6 +542,7 @@ func ClearPushNotification(userId string, channelId string) *model.AppError {
}
func sendToPushProxy(msg model.PushNotification) *model.AppError {
+
msg.ServerId = utils.CfgDiagnosticId
tr := &http.Transport{