1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2// See LICENSE.txt for license information. 3 4package slashcommands 5 6import ( 7 "fmt" 8 "strings" 9 10 "github.com/mattermost/mattermost-server/v6/app" 11 "github.com/mattermost/mattermost-server/v6/app/request" 12 "github.com/mattermost/mattermost-server/v6/model" 13 "github.com/mattermost/mattermost-server/v6/shared/i18n" 14 "github.com/mattermost/mattermost-server/v6/shared/mlog" 15) 16 17type groupmsgProvider struct { 18} 19 20const ( 21 CmdGroupMsg = "groupmsg" 22) 23 24func init() { 25 app.RegisterCommandProvider(&groupmsgProvider{}) 26} 27 28func (*groupmsgProvider) GetTrigger() string { 29 return CmdGroupMsg 30} 31 32func (*groupmsgProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { 33 return &model.Command{ 34 Trigger: CmdGroupMsg, 35 AutoComplete: true, 36 AutoCompleteDesc: T("api.command_groupmsg.desc"), 37 AutoCompleteHint: T("api.command_groupmsg.hint"), 38 DisplayName: T("api.command_groupmsg.name"), 39 } 40} 41 42func (*groupmsgProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { 43 targetUsers := map[string]*model.User{} 44 targetUsersSlice := []string{args.UserId} 45 invalidUsernames := []string{} 46 47 users, parsedMessage := groupMsgUsernames(message) 48 49 for _, username := range users { 50 username = strings.TrimSpace(username) 51 username = strings.TrimPrefix(username, "@") 52 targetUser, nErr := a.Srv().Store.User().GetByUsername(username) 53 if nErr != nil { 54 invalidUsernames = append(invalidUsernames, username) 55 continue 56 } 57 58 canSee, err := a.UserCanSeeOtherUser(args.UserId, targetUser.Id) 59 if err != nil { 60 return &model.CommandResponse{Text: args.T("api.command_groupmsg.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral} 61 } 62 63 if !canSee { 64 invalidUsernames = append(invalidUsernames, username) 65 continue 66 } 67 68 _, exists := targetUsers[targetUser.Id] 69 if !exists && targetUser.Id != args.UserId { 70 targetUsers[targetUser.Id] = targetUser 71 targetUsersSlice = append(targetUsersSlice, targetUser.Id) 72 } 73 } 74 75 if len(invalidUsernames) > 0 { 76 invalidUsersString := map[string]interface{}{ 77 "Users": "@" + strings.Join(invalidUsernames, ", @"), 78 } 79 return &model.CommandResponse{ 80 Text: args.T("api.command_groupmsg.invalid_user.app_error", len(invalidUsernames), invalidUsersString), 81 ResponseType: model.CommandResponseTypeEphemeral, 82 } 83 } 84 85 if len(targetUsersSlice) == 2 { 86 return app.GetCommandProvider("msg").DoCommand(a, c, args, fmt.Sprintf("%s %s", targetUsers[targetUsersSlice[1]].Username, parsedMessage)) 87 } 88 89 if len(targetUsersSlice) < model.ChannelGroupMinUsers { 90 minUsers := map[string]interface{}{ 91 "MinUsers": model.ChannelGroupMinUsers - 1, 92 } 93 return &model.CommandResponse{ 94 Text: args.T("api.command_groupmsg.min_users.app_error", minUsers), 95 ResponseType: model.CommandResponseTypeEphemeral, 96 } 97 } 98 99 if len(targetUsersSlice) > model.ChannelGroupMaxUsers { 100 maxUsers := map[string]interface{}{ 101 "MaxUsers": model.ChannelGroupMaxUsers - 1, 102 } 103 return &model.CommandResponse{ 104 Text: args.T("api.command_groupmsg.max_users.app_error", maxUsers), 105 ResponseType: model.CommandResponseTypeEphemeral, 106 } 107 } 108 109 var groupChannel *model.Channel 110 var channelErr *model.AppError 111 112 if a.HasPermissionTo(args.UserId, model.PermissionCreateGroupChannel) { 113 groupChannel, channelErr = a.CreateGroupChannel(targetUsersSlice, args.UserId) 114 if channelErr != nil { 115 mlog.Error(channelErr.Error()) 116 return &model.CommandResponse{Text: args.T("api.command_groupmsg.group_fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral} 117 } 118 } else { 119 groupChannel, channelErr = a.GetGroupChannel(targetUsersSlice) 120 if channelErr != nil { 121 return &model.CommandResponse{Text: args.T("api.command_groupmsg.permission.app_error"), ResponseType: model.CommandResponseTypeEphemeral} 122 } 123 } 124 125 if parsedMessage != "" { 126 post := &model.Post{} 127 post.Message = parsedMessage 128 post.ChannelId = groupChannel.Id 129 post.UserId = args.UserId 130 if _, err := a.CreatePostMissingChannel(c, post, true); err != nil { 131 return &model.CommandResponse{Text: args.T("api.command_groupmsg.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral} 132 } 133 } 134 135 team, err := a.GetTeam(args.TeamId) 136 if err != nil { 137 return &model.CommandResponse{Text: args.T("api.command_groupmsg.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral} 138 } 139 140 return &model.CommandResponse{GotoLocation: args.SiteURL + "/" + team.Name + "/channels/" + groupChannel.Name, Text: "", ResponseType: model.CommandResponseTypeEphemeral} 141} 142 143func groupMsgUsernames(message string) ([]string, string) { 144 result := []string{} 145 resultMessage := "" 146 for idx, part := range strings.Split(message, ",") { 147 clean := strings.TrimPrefix(strings.TrimSpace(part), "@") 148 split := strings.Fields(clean) 149 if len(split) > 0 { 150 result = append(result, split[0]) 151 } 152 if len(split) > 1 { 153 splitted := strings.SplitN(message, ",", idx+1) 154 resultMessage = strings.TrimPrefix(strings.TrimSpace(splitted[len(splitted)-1]), "@") 155 resultMessage = strings.TrimSpace(strings.TrimPrefix(resultMessage, split[0])) 156 break 157 } 158 } 159 return result, resultMessage 160} 161