mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Merge branch 'release-3.6'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
@@ -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")}
|
||||
}
|
||||
|
||||
502
api/post.go
502
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)
|
||||
}
|
||||
pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true)
|
||||
fchan = Srv.Store.FileInfo().GetForPost(post.Id)
|
||||
|
||||
// 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{}
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
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
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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") {
|
||||
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)
|
||||
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 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 {
|
||||
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, ""}
|
||||
}
|
||||
|
||||
if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) {
|
||||
sendPushNotification(post, profileMap[id], channel, senderName[id], true)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
for _, id := range allActivityPushUserIds {
|
||||
if _, ok := mentionedUserIds[id]; !ok {
|
||||
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 {
|
||||
@@ -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}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
12
api/team.go
12
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"])
|
||||
|
||||
Reference in New Issue
Block a user