summaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2017-01-12 19:59:37 -0500
committerChristopher Speller <crspeller@gmail.com>2017-01-12 19:59:37 -0500
commit8fb66c2b834ee4e0669de173e5ddfebd56c34d58 (patch)
tree9e8e66772d44c4f9010a48c8e0afed70421238b1 /api
parent4208e42ba9df02b9c4bd7081179922c21206d83d (diff)
parentaafb8be87c79c60df7534b3b69f967c6301b157e (diff)
downloadchat-8fb66c2b834ee4e0669de173e5ddfebd56c34d58.tar.gz
chat-8fb66c2b834ee4e0669de173e5ddfebd56c34d58.tar.bz2
chat-8fb66c2b834ee4e0669de173e5ddfebd56c34d58.zip
Merge branch 'release-3.6'
Diffstat (limited to 'api')
-rw-r--r--api/channel.go47
-rw-r--r--api/command.go19
-rw-r--r--api/command_invite_people.go2
-rw-r--r--api/post.go488
-rw-r--r--api/status.go52
-rw-r--r--api/team.go12
6 files changed, 319 insertions, 301 deletions
diff --git a/api/channel.go b/api/channel.go
index 4c9e514ac..ae92ab618 100644
--- a/api/channel.go
+++ b/api/channel.go
@@ -826,47 +826,42 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
+ post := &model.Post{
+ ChannelId: channel.Id,
+ Message: fmt.Sprintf(c.T("api.channel.delete_channel.archived"), user.Username),
+ Type: model.POST_CHANNEL_DELETED,
+ UserId: c.Session.UserId,
+ }
+
+ if _, err := CreatePost(c, post, false); err != nil {
+ l4g.Error(utils.T("api.channel.delete_channel.failed_post.error"), err)
+ }
+
now := model.GetMillis()
for _, hook := range incomingHooks {
- go func() {
- if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil {
- l4g.Error(utils.T("api.channel.delete_channel.incoming_webhook.error"), hook.Id)
- }
- }()
+ if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil {
+ l4g.Error(utils.T("api.channel.delete_channel.incoming_webhook.error"), hook.Id)
+ }
}
for _, hook := range outgoingHooks {
- go func() {
- if result := <-Srv.Store.Webhook().DeleteOutgoing(hook.Id, now); result.Err != nil {
- l4g.Error(utils.T("api.channel.delete_channel.outgoing_webhook.error"), hook.Id)
- }
- }()
+ if result := <-Srv.Store.Webhook().DeleteOutgoing(hook.Id, now); result.Err != nil {
+ l4g.Error(utils.T("api.channel.delete_channel.outgoing_webhook.error"), hook.Id)
+ }
}
- InvalidateCacheForChannel(channel.Id)
if dresult := <-Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); dresult.Err != nil {
c.Err = dresult.Err
return
}
+ InvalidateCacheForChannel(channel.Id)
c.LogAudit("name=" + channel.Name)
- go func() {
- message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_DELETED, c.TeamId, "", "", nil)
- message.Add("channel_id", channel.Id)
+ message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_DELETED, c.TeamId, "", "", nil)
+ message.Add("channel_id", channel.Id)
- go Publish(message)
-
- post := &model.Post{
- ChannelId: channel.Id,
- Message: fmt.Sprintf(c.T("api.channel.delete_channel.archived"), user.Username),
- Type: model.POST_CHANNEL_DELETED,
- UserId: c.Session.UserId,
- }
- if _, err := CreatePost(c, post, false); err != nil {
- l4g.Error(utils.T("api.channel.delete_channel.failed_post.error"), err)
- }
- }()
+ Publish(message)
result := make(map[string]string)
result["id"] = channel.Id
diff --git a/api/command.go b/api/command.go
index 842d67843..9c8f60be5 100644
--- a/api/command.go
+++ b/api/command.go
@@ -134,7 +134,6 @@ func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) {
return
} else {
team = tr.Data.(*model.Team)
-
}
var user *model.User
@@ -247,23 +246,7 @@ func handleResponse(c *Context, w http.ResponseWriter, response *model.CommandRe
}
}
- if response.ResponseType == model.COMMAND_RESPONSE_TYPE_IN_CHANNEL {
- post.Message = response.Text
- post.UserId = c.Session.UserId
- if _, err := CreatePost(c, post, true); err != nil {
- c.Err = model.NewLocAppError("command", "api.command.execute_command.save.app_error", nil, "")
- }
- } else if response.ResponseType == model.COMMAND_RESPONSE_TYPE_EPHEMERAL && response.Text != "" {
- post.Message = response.Text
- post.CreateAt = model.GetMillis()
- post.UserId = c.Session.UserId
- post.ParentId = ""
- SendEphemeralPost(
- c.TeamId,
- c.Session.UserId,
- post,
- )
- }
+ CreateCommandPost(c, post, response)
w.Write([]byte(response.ToJson()))
}
diff --git a/api/command_invite_people.go b/api/command_invite_people.go
index ca2a2633a..e6ad252f6 100644
--- a/api/command_invite_people.go
+++ b/api/command_invite_people.go
@@ -72,7 +72,7 @@ func (me *InvitePeopleProvider) DoCommand(c *Context, args *model.CommandArgs, m
user = result.Data.(*model.User)
}
- go InviteMembers(team, user.GetDisplayName(), emailList)
+ go InviteMembers(team, user.GetDisplayName(), emailList, c.GetSiteURL())
return &model.CommandResponse{ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, Text: c.T("api.command.invite_people.sent")}
}
diff --git a/api/post.go b/api/post.go
index e8aef2f86..8d255649e 100644
--- a/api/post.go
+++ b/api/post.go
@@ -174,11 +174,9 @@ func CreatePost(c *Context, post *model.Post, triggerWebhooks bool) (*model.Post
return rpost, nil
}
-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})")
+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")
@@ -196,41 +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" {
- 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)
- }
+ parseSlackAttachment(post, val)
} else if key != "override_icon_url" && key != "override_username" && key != "from_webhook" {
post.AddProp(key, val)
}
@@ -244,6 +213,72 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc
return post, nil
}
+func CreateCommandPost(c *Context, post *model.Post, response *model.CommandResponse) {
+ post.Message = parseSlackLinksToMarkdown(response.Text)
+ post.UserId = c.Session.UserId
+ post.CreateAt = model.GetMillis()
+
+ if response.Attachments != nil {
+ parseSlackAttachment(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 parseSlackAttachment(post *model.Post, attachments interface{}) {
+ post.Type = model.POST_SLACK_ATTACHMENT
+
+ 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 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)
@@ -573,190 +608,190 @@ 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
- }
+ pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true)
+ fchan = Srv.Store.FileInfo().GetForPost(post.Id)
- 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]
+ 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)
+
+ // 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 {
- profile := profileMap[threadPost.UserId]
- if profile.NotifyProps["comments"] == "any" || (profile.NotifyProps["comments"] == "root" && threadPost.Id == list.Order[0]) {
- mentionedUserIds[threadPost.UserId] = true
+ 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)
- }
+ // 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)
+ 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)
+ }
}
- }
- // 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)
+ // 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)
+ }
}
}
- }
- 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 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
+ 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)
} else {
- senderName[id] = profile.GetDisplayNameForPreference(result.Data.(model.Preference).Value)
+ //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)
+ }
}
+ sender = profile
}
- 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
- }
+ 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 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 {
- sendNotificationEmail(c, post, profileMap[id], channel, team, senderName[id], sender)
+ if userAllowsEmails && status.Status != model.STATUS_ONLINE {
+ sendNotificationEmail(c, post, profileMap[id], channel, team, senderName[id], sender)
+ }
}
}
- }
- // 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
- } else {
- statuses := result.Data.([]*model.Status)
+ // 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 {
+ statuses := GetAllStatuses()
for _, status := range statuses {
if status.UserId == post.UserId {
continue
@@ -771,43 +806,29 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
}
}
}
- }
-
- // 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
- }
- }
- 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, ""}
+ // 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 {
@@ -815,7 +836,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)
+ }
}
}
}
@@ -829,7 +864,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
@@ -874,15 +909,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}
+ }
}
}
}
diff --git a/api/status.go b/api/status.go
index 99d5bc417..909ab50ec 100644
--- a/api/status.go
+++ b/api/status.go
@@ -42,38 +42,31 @@ func InitStatus() {
}
func getStatusesHttp(c *Context, w http.ResponseWriter, r *http.Request) {
- statusMap, err := GetAllStatuses()
- if err != nil {
- c.Err = err
- return
- }
-
+ statusMap := model.StatusMapToInterfaceMap(GetAllStatuses())
w.Write([]byte(model.StringInterfaceToJson(statusMap)))
}
func getStatusesWebSocket(req *model.WebSocketRequest) (map[string]interface{}, *model.AppError) {
- statusMap, err := GetAllStatuses()
- if err != nil {
- return nil, err
- }
-
- return statusMap, nil
+ statusMap := GetAllStatuses()
+ return model.StatusMapToInterfaceMap(statusMap), nil
}
-// Only returns 300 statuses max
-func GetAllStatuses() (map[string]interface{}, *model.AppError) {
- if result := <-Srv.Store.Status().GetOnlineAway(); result.Err != nil {
- return nil, result.Err
- } else {
- statuses := result.Data.([]*model.Status)
+func GetAllStatuses() map[string]*model.Status {
+ userIds := statusCache.Keys()
+ statusMap := map[string]*model.Status{}
- statusMap := map[string]interface{}{}
- for _, s := range statuses {
- statusMap[s.UserId] = s.Status
+ for _, userId := range userIds {
+ if id, ok := userId.(string); !ok {
+ continue
+ } else {
+ status := GetStatusFromCache(id)
+ if status != nil {
+ statusMap[id] = status
+ }
}
-
- return statusMap, nil
}
+
+ return statusMap
}
func getStatusesByIdsHttp(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -268,12 +261,21 @@ func SetStatusAwayIfNeeded(userId string, manual bool) {
go Publish(event)
}
-func GetStatus(userId string) (*model.Status, *model.AppError) {
+func GetStatusFromCache(userId string) *model.Status {
if result, ok := statusCache.Get(userId); ok {
status := result.(*model.Status)
statusCopy := &model.Status{}
*statusCopy = *status
- return statusCopy, nil
+ return statusCopy
+ }
+
+ return nil
+}
+
+func GetStatus(userId string) (*model.Status, *model.AppError) {
+ status := GetStatusFromCache(userId)
+ if status != nil {
+ return status, nil
}
if result := <-Srv.Store.Status().Get(userId); result.Err != nil {
diff --git a/api/team.go b/api/team.go
index c17bf87af..c855a515d 100644
--- a/api/team.go
+++ b/api/team.go
@@ -48,7 +48,7 @@ func InitTeam() {
// These should be moved to the global admin console
BaseRoutes.NeedTeam.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST")
- BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", ApiUserRequired(addUserToTeamFromInvite)).Methods("POST")
+ BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", ApiUserRequiredMfa(addUserToTeamFromInvite)).Methods("POST")
}
func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -378,7 +378,7 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
emailList = append(emailList, invite["email"])
}
- InviteMembers(team, user.GetDisplayName(), emailList)
+ InviteMembers(team, user.GetDisplayName(), emailList, c.GetSiteURL())
w.Write([]byte(invites.ToJson()))
}
@@ -640,7 +640,7 @@ func getMyTeamsUnread(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
-func InviteMembers(team *model.Team, senderName string, invites []string) {
+func InviteMembers(team *model.Team, senderName string, invites []string, siteURL string) {
for _, invite := range invites {
if len(invite) > 0 {
senderRole := utils.T("api.team.invite_members.member")
@@ -649,13 +649,13 @@ func InviteMembers(team *model.Team, senderName string, invites []string) {
map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName, "SiteName": utils.ClientCfg["SiteName"]})
bodyPage := utils.NewHTMLTemplate("invite_body", model.DEFAULT_LOCALE)
- bodyPage.Props["SiteURL"] = *utils.Cfg.ServiceSettings.SiteURL
+ bodyPage.Props["SiteURL"] = siteURL
bodyPage.Props["Title"] = utils.T("api.templates.invite_body.title")
bodyPage.Html["Info"] = template.HTML(utils.T("api.templates.invite_body.info",
map[string]interface{}{"SenderStatus": senderRole, "SenderName": senderName, "TeamDisplayName": team.DisplayName}))
bodyPage.Props["Button"] = utils.T("api.templates.invite_body.button")
bodyPage.Html["ExtraInfo"] = template.HTML(utils.T("api.templates.invite_body.extra_info",
- map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": *utils.Cfg.ServiceSettings.SiteURL + "/" + team.Name}))
+ map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": siteURL + "/" + team.Name}))
props := make(map[string]string)
props["email"] = invite
@@ -665,7 +665,7 @@ func InviteMembers(team *model.Team, senderName string, invites []string) {
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
- bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", *utils.Cfg.ServiceSettings.SiteURL, url.QueryEscape(data), url.QueryEscape(hash))
+ bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", siteURL, url.QueryEscape(data), url.QueryEscape(hash))
if !utils.Cfg.EmailSettings.SendEmailNotifications {
l4g.Info(utils.T("api.team.invite_members.sending.info"), invite, bodyPage.Props["Link"])