From bc08cc0ca5638957371aa6184ec0d11c9df16264 Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Fri, 6 Jan 2017 14:02:37 +0000 Subject: PLT-4096 fix error/panic on replying to integrations. (#4968) --- api/post.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'api/post.go') diff --git a/api/post.go b/api/post.go index 354fe35db..e66a51295 100644 --- a/api/post.go +++ b/api/post.go @@ -624,9 +624,10 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * list := result.Data.(*model.PostList) 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 + 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 + } } } } -- cgit v1.2.3-1-g7c22 From 4fb9787feec2d4baccac6fb87de6f6fb88583d67 Mon Sep 17 00:00:00 2001 From: Corey Hulen Date: Fri, 6 Jan 2017 10:03:31 -0500 Subject: Fixing bulk loading perf issue (#4974) --- api/post.go | 388 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 196 insertions(+), 192 deletions(-) (limited to 'api/post.go') diff --git a/api/post.go b/api/post.go index e66a51295..2052636bb 100644 --- a/api/post.go +++ b/api/post.go @@ -573,242 +573,232 @@ func getExplicitMentions(message string, keywords map[string][]string) (map[stri } func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *model.Channel) []string { - pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true) - fchan := Srv.Store.FileInfo().GetForPost(post.Id) + mentionedUsersList := make([]string, 0) + var fchan store.StoreChannel + var senderUsername string - var profileMap map[string]*model.User - if result := <-pchan; result.Err != nil { - l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err) - return nil + if post.IsSystemMessage() { + senderUsername = c.T("system.message.name") } else { - profileMap = result.Data.(map[string]*model.User) - } - - // If the user who made the post is mention don't send a notification - if _, ok := profileMap[post.UserId]; !ok { - l4g.Error(utils.T("api.post.send_notifications_and_forget.user_id.error"), post.UserId) - return nil - } - - mentionedUserIds := make(map[string]bool) - allActivityPushUserIds := []string{} - hereNotification := false - channelNotification := false - allNotification := false - updateMentionChans := []store.StoreChannel{} + pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true) + fchan = Srv.Store.FileInfo().GetForPost(post.Id) - if channel.Type == model.CHANNEL_DIRECT { - var otherUserId string - if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId { - otherUserId = userIds[1] + var profileMap map[string]*model.User + if result := <-pchan; result.Err != nil { + l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err) + return nil } else { - otherUserId = userIds[0] + profileMap = result.Data.(map[string]*model.User) } - mentionedUserIds[otherUserId] = true - if post.Props["from_webhook"] == "true" { - mentionedUserIds[post.UserId] = true + // If the user who made the post is mention don't send a notification + if _, ok := profileMap[post.UserId]; !ok { + l4g.Error(utils.T("api.post.send_notifications_and_forget.user_id.error"), post.UserId) + return nil } - } else { - keywords := getMentionKeywordsInChannel(profileMap) - var potentialOtherMentions []string - mentionedUserIds, potentialOtherMentions, hereNotification, channelNotification, allNotification = getExplicitMentions(post.Message, keywords) + mentionedUserIds := make(map[string]bool) + allActivityPushUserIds := []string{} + hereNotification := false + channelNotification := false + allNotification := false + updateMentionChans := []store.StoreChannel{} - // get users that have comment thread mentions enabled - if len(post.RootId) > 0 { - if result := <-Srv.Store.Post().Get(post.RootId); result.Err != nil { - l4g.Error(utils.T("api.post.send_notifications_and_forget.comment_thread.error"), post.RootId, result.Err) - return nil + if channel.Type == model.CHANNEL_DIRECT { + var otherUserId string + if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId { + otherUserId = userIds[1] } else { - list := result.Data.(*model.PostList) + 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) - 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 + // get users that have comment thread mentions enabled + if len(post.RootId) > 0 { + if result := <-Srv.Store.Post().Get(post.RootId); result.Err != nil { + l4g.Error(utils.T("api.post.send_notifications_and_forget.comment_thread.error"), post.RootId, result.Err) + return nil + } 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 + } } } } } - } - - // 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(c, post, outOfChannelMentions) + // prevent the user from mentioning themselves + if post.Props["from_webhook"] != "true" { + delete(mentionedUserIds, post.UserId) } - } - // 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) + 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(c, post, outOfChannelMentions) + } } - } - } - 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 post.IsSystemMessage() { - senderName[id] = c.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 { - senderName[id] = profile.GetDisplayNameForPreference(result.Data.(model.Preference).Value) + // 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) } } - sender = profile } - } - 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 - } + mentionedUsersList = make([]string, 0, len(mentionedUserIds)) + for id := range mentionedUserIds { + mentionedUsersList = append(mentionedUsersList, id) + updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, id)) + } - if utils.Cfg.EmailSettings.SendEmailNotifications { + var sender *model.User + senderName := make(map[string]string) 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: "", + 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) + } 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) + } } - } - - if userAllowsEmails && status.Status != model.STATUS_ONLINE { - sendNotificationEmail(c, post, profileMap[id], channel, team, senderName[id], sender) + sender = profile } } - } - // If the channel has more than 1K users then @here is disabled - if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { - hereNotification = false - SendEphemeralPost( - c.TeamId, - post.UserId, - &model.Post{ - ChannelId: post.ChannelId, - Message: c.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( - c.TeamId, - post.UserId, - &model.Post{ - ChannelId: post.ChannelId, - Message: c.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( - c.TeamId, - post.UserId, - &model.Post{ - ChannelId: post.ChannelId, - Message: c.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 { - l4g.Warn(utils.T("api.post.notification.here.warn"), result.Err) - return nil + if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" { + senderUsername = value.(string) } else { - statuses := result.Data.([]*model.Status) - for _, status := range statuses { - if status.UserId == post.UserId { - continue - } + senderUsername = profileMap[post.UserId].Username + } - _, profileFound := profileMap[status.UserId] - _, alreadyMentioned := mentionedUserIds[status.UserId] + 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 status.Status == model.STATUS_ONLINE && profileFound && !alreadyMentioned { - mentionedUsersList = append(mentionedUsersList, status.UserId) - updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, status.UserId)) + if userAllowsEmails && status.Status != model.STATUS_ONLINE { + sendNotificationEmail(c, post, profileMap[id], channel, team, senderName[id], sender) } } } - } - // 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) + // If the channel has more than 1K users then @here is disabled + if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { + hereNotification = false + SendEphemeralPost( + c.TeamId, + post.UserId, + &model.Post{ + ChannelId: post.ChannelId, + Message: c.T("api.post.disabled_here", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), + CreateAt: post.CreateAt + 1, + }, + ) } - } - 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 the channel has more than 1K users then @channel is disabled + if channelNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { + SendEphemeralPost( + c.TeamId, + post.UserId, + &model.Post{ + ChannelId: post.ChannelId, + Message: c.T("api.post.disabled_channel", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), + CreateAt: post.CreateAt + 1, + }, + ) } - } - 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 the channel has more than 1K users then @all is disabled + if allNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { + SendEphemeralPost( + c.TeamId, + post.UserId, + &model.Post{ + ChannelId: post.ChannelId, + Message: c.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 { + l4g.Warn(utils.T("api.post.notification.here.warn"), result.Err) + return nil + } else { + statuses := result.Data.([]*model.Status) + for _, status := range statuses { + if status.UserId == post.UserId { + continue + } + + _, profileFound := profileMap[status.UserId] + _, alreadyMentioned := mentionedUserIds[status.UserId] + + if status.Status == model.STATUS_ONLINE && profileFound && !alreadyMentioned { + mentionedUsersList = append(mentionedUsersList, status.UserId) + updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, status.UserId)) + } + } + } + } + + // 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) } + } - if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) { - sendPushNotification(post, profileMap[id], channel, senderName[id], 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 } } - for _, id := range allActivityPushUserIds { - if _, ok := mentionedUserIds[id]; !ok { + if sendPushNotifications { + for _, id := range mentionedUsersList { var status *model.Status var err *model.AppError if status, err = GetStatus(id); err != nil { @@ -816,7 +806,21 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * } if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) { - sendPushNotification(post, profileMap[id], channel, senderName[id], false) + sendPushNotification(post, profileMap[id], channel, senderName[id], true) + } + } + + 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) { + sendPushNotification(post, profileMap[id], channel, senderName[id], false) + } } } } @@ -830,7 +834,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * message.Add("sender_name", senderUsername) message.Add("team_id", team.Id) - if len(post.FileIds) != 0 { + if len(post.FileIds) != 0 && fchan != nil { message.Add("otherFile", "true") var infos []*model.FileInfo -- cgit v1.2.3-1-g7c22 From 12662d0c877b585c96d35b91fea4b6e99fcba749 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 9 Jan 2017 15:25:02 +0100 Subject: Slack format for Slash command messages (#4999) * Slash commands accept Slack format Until this commit the slash commands only accepted 'text' properties. For better styling however, Slack formatting support was added. However, ephemeral messages are not supported, and only text will be displayed. * Allow emphemeral Slack messages --- api/post.go | 103 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 36 deletions(-) (limited to 'api/post.go') diff --git a/api/post.go b/api/post.go index 2052636bb..8d6fa0b02 100644 --- a/api/post.go +++ b/api/post.go @@ -175,10 +175,6 @@ func CreatePost(c *Context, post *model.Post, triggerWebhooks bool) (*model.Post } func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIconUrl string, props model.StringInterface, postType string) (*model.Post, *model.AppError) { - // parse links into Markdown format - linkWithTextRegex := regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) - text = linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})") - post := &model.Post{UserId: c.Session.UserId, ChannelId: channelId, Message: text, Type: postType} post.AddProp("from_webhook", "true") @@ -199,38 +195,7 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc if len(props) > 0 { for key, val := range props { if key == "attachments" { - if list, success := val.([]interface{}); success { - // parse attachment links into Markdown format - for i, aInt := range list { - attachment := aInt.(map[string]interface{}) - if aText, ok := attachment["text"].(string); ok { - aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") - attachment["text"] = aText - list[i] = attachment - } - if aText, ok := attachment["pretext"].(string); ok { - aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") - attachment["pretext"] = aText - list[i] = attachment - } - if fVal, ok := attachment["fields"]; ok { - if fields, ok := fVal.([]interface{}); ok { - // parse attachment field links into Markdown format - for j, fInt := range fields { - field := fInt.(map[string]interface{}) - if fValue, ok := field["value"].(string); ok { - fValue = linkWithTextRegex.ReplaceAllString(fValue, "[${2}](${1})") - field["value"] = fValue - fields[j] = field - } - } - attachment["fields"] = fields - list[i] = attachment - } - } - } - post.AddProp(key, list) - } + createSlackPost(post, val) } else if key != "override_icon_url" && key != "override_username" && key != "from_webhook" { post.AddProp(key, val) } @@ -244,6 +209,72 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc return post, nil } +func CreateCommandPost(c *Context, post *model.Post, response *model.CommandResponse) { + post.Message = response.Text + post.UserId = c.Session.UserId + post.CreateAt = model.GetMillis() + + if response.Attachments != nil { + createSlackPost(post, response.Attachments) + } + + switch response.ResponseType { + case model.COMMAND_RESPONSE_TYPE_IN_CHANNEL: + if _, err := CreatePost(c, post, true); err != nil { + c.Err = model.NewLocAppError("command", "api.command.execute_command.save.app_error", nil, "") + } + case model.COMMAND_RESPONSE_TYPE_EPHEMERAL: + if response.Text == "" { + return + } + + post.ParentId = "" + SendEphemeralPost(c.TeamId, c.Session.UserId, post) + } +} + +// This method only parses and processes the attachments, +// all else should be set in the post which is passed +func createSlackPost(post *model.Post, attachments interface{}) { + post.Type = model.POST_SLACK_ATTACHMENT + + // parse links into Markdown format + linkWithTextRegex := regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) + post.Message = linkWithTextRegex.ReplaceAllString(post.Message, "[${2}](${1})") + + if list, success := attachments.([]interface{}); success { + for i, aInt := range list { + attachment := aInt.(map[string]interface{}) + if aText, ok := attachment["text"].(string); ok { + aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") + attachment["text"] = aText + list[i] = attachment + } + if aText, ok := attachment["pretext"].(string); ok { + aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") + attachment["pretext"] = aText + list[i] = attachment + } + if fVal, ok := attachment["fields"]; ok { + if fields, ok := fVal.([]interface{}); ok { + // parse attachment field links into Markdown format + for j, fInt := range fields { + field := fInt.(map[string]interface{}) + if fValue, ok := field["value"].(string); ok { + fValue = linkWithTextRegex.ReplaceAllString(fValue, "[${2}](${1})") + field["value"] = fValue + fields[j] = field + } + } + attachment["fields"] = fields + list[i] = attachment + } + } + } + post.AddProp("attachments", list) + } +} + func handlePostEvents(c *Context, post *model.Post, triggerWebhooks bool) { tchan := Srv.Store.Team().Get(c.TeamId) cchan := Srv.Store.Channel().Get(post.ChannelId, true) -- cgit v1.2.3-1-g7c22 From 4101b28de58ab8c2e821cda5f8e7bc8e836d7bb8 Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Tue, 10 Jan 2017 11:38:03 -0500 Subject: Use status cache for checking @here notifications (#5035) --- api/post.go | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'api/post.go') diff --git a/api/post.go b/api/post.go index 8d6fa0b02..45ead08e0 100644 --- a/api/post.go +++ b/api/post.go @@ -787,23 +787,18 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * } if hereNotification { - if result := <-Srv.Store.Status().GetOnline(); result.Err != nil { - l4g.Warn(utils.T("api.post.notification.here.warn"), result.Err) - return nil - } else { - statuses := result.Data.([]*model.Status) - for _, status := range statuses { - if status.UserId == post.UserId { - continue - } + statuses := GetAllStatuses() + for _, status := range statuses { + if status.UserId == post.UserId { + continue + } - _, profileFound := profileMap[status.UserId] - _, alreadyMentioned := mentionedUserIds[status.UserId] + _, profileFound := profileMap[status.UserId] + _, alreadyMentioned := mentionedUserIds[status.UserId] - if status.Status == model.STATUS_ONLINE && profileFound && !alreadyMentioned { - mentionedUsersList = append(mentionedUsersList, status.UserId) - updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, status.UserId)) - } + if status.Status == model.STATUS_ONLINE && profileFound && !alreadyMentioned { + mentionedUsersList = append(mentionedUsersList, status.UserId) + updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, status.UserId)) } } } -- cgit v1.2.3-1-g7c22 From 5be99e1f85fff344485b6750be43a3506d8f8341 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Tue, 10 Jan 2017 16:17:08 -0500 Subject: Fixing DM channel emails (#5038) --- api/post.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'api/post.go') diff --git a/api/post.go b/api/post.go index 45ead08e0..8b5a33224 100644 --- a/api/post.go +++ b/api/post.go @@ -905,15 +905,18 @@ func sendNotificationEmail(c *Context, post *model.Post, user *model.User, chann for i := range teams { if teams[i].Id == team.Id { found = true + team = teams[i] break } } - 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} + 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} + } } } } -- cgit v1.2.3-1-g7c22 From 046d2c61a5fb88742ba232f7d541d9ba9ed42891 Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Thu, 12 Jan 2017 15:08:48 -0500 Subject: Fix slack link parsing for integrations without attachments (#5050) --- api/post.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'api/post.go') diff --git a/api/post.go b/api/post.go index 8b5a33224..27a610199 100644 --- a/api/post.go +++ b/api/post.go @@ -174,6 +174,8 @@ func CreatePost(c *Context, post *model.Post, triggerWebhooks bool) (*model.Post return rpost, nil } +var linkWithTextRegex *regexp.Regexp = regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) + func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIconUrl string, props model.StringInterface, postType string) (*model.Post, *model.AppError) { post := &model.Post{UserId: c.Session.UserId, ChannelId: channelId, Message: text, Type: postType} post.AddProp("from_webhook", "true") @@ -192,10 +194,12 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc } } + post.Message = parseSlackLinksToMarkdown(post.Message) + if len(props) > 0 { for key, val := range props { if key == "attachments" { - createSlackPost(post, val) + parseSlackAttachment(post, val) } else if key != "override_icon_url" && key != "override_username" && key != "from_webhook" { post.AddProp(key, val) } @@ -210,12 +214,12 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc } func CreateCommandPost(c *Context, post *model.Post, response *model.CommandResponse) { - post.Message = response.Text + post.Message = parseSlackLinksToMarkdown(response.Text) post.UserId = c.Session.UserId post.CreateAt = model.GetMillis() if response.Attachments != nil { - createSlackPost(post, response.Attachments) + parseSlackAttachment(post, response.Attachments) } switch response.ResponseType { @@ -235,13 +239,9 @@ func CreateCommandPost(c *Context, post *model.Post, response *model.CommandResp // This method only parses and processes the attachments, // all else should be set in the post which is passed -func createSlackPost(post *model.Post, attachments interface{}) { +func parseSlackAttachment(post *model.Post, attachments interface{}) { post.Type = model.POST_SLACK_ATTACHMENT - // parse links into Markdown format - linkWithTextRegex := regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) - post.Message = linkWithTextRegex.ReplaceAllString(post.Message, "[${2}](${1})") - if list, success := attachments.([]interface{}); success { for i, aInt := range list { attachment := aInt.(map[string]interface{}) @@ -275,6 +275,10 @@ func createSlackPost(post *model.Post, attachments interface{}) { } } +func parseSlackLinksToMarkdown(text string) string { + return linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})") +} + func handlePostEvents(c *Context, post *model.Post, triggerWebhooks bool) { tchan := Srv.Store.Team().Get(c.TeamId) cchan := Srv.Store.Channel().Get(post.ChannelId, true) -- cgit v1.2.3-1-g7c22