diff options
-rw-r--r-- | api/command_groupmsg_test.go | 58 | ||||
-rw-r--r-- | app/command_groupmsg.go | 137 | ||||
-rw-r--r-- | app/command_groupmsg_test.go | 37 | ||||
-rw-r--r-- | i18n/en.json | 51 |
4 files changed, 283 insertions, 0 deletions
diff --git a/api/command_groupmsg_test.go b/api/command_groupmsg_test.go new file mode 100644 index 000000000..fcb9953ad --- /dev/null +++ b/api/command_groupmsg_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package api + +import ( + "strings" + "testing" + + "github.com/mattermost/mattermost-server/model" +) + +func TestGroupmsgCommands(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + Client := th.BasicClient + team := th.BasicTeam + user1 := th.BasicUser + user2 := th.BasicUser2 + user3 := th.CreateUser(th.BasicClient) + user4 := th.CreateUser(th.BasicClient) + user5 := th.CreateUser(th.BasicClient) + user6 := th.CreateUser(th.BasicClient) + user7 := th.CreateUser(th.BasicClient) + user8 := th.CreateUser(th.BasicClient) + user9 := th.CreateUser(th.BasicClient) + th.LinkUserToTeam(user3, team) + th.LinkUserToTeam(user4, team) + + rs1 := Client.Must(Client.Command("", "/groupmsg "+user2.Username+","+user3.Username)).Data.(*model.CommandResponse) + + group1 := model.GetGroupNameFromUserIds([]string{user1.Id, user2.Id, user3.Id}) + + if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+group1) { + t.Fatal("failed to create group channel") + } + + rs2 := Client.Must(Client.Command("", "/groupmsg "+user3.Username+","+user4.Username+" foobar")).Data.(*model.CommandResponse) + group2 := model.GetGroupNameFromUserIds([]string{user1.Id, user3.Id, user4.Id}) + + if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+group2) { + t.Fatal("failed to create second direct channel") + } + if result := Client.Must(Client.SearchPosts("foobar", false)).Data.(*model.PostList); len(result.Order) == 0 { + t.Fatal("post did not get sent to direct message") + } + + rs3 := Client.Must(Client.Command("", "/groupmsg "+user2.Username+","+user3.Username)).Data.(*model.CommandResponse) + if !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+group1) { + t.Fatal("failed to go back to existing group channel") + } + + Client.Must(Client.Command("", "/groupmsg "+user2.Username+" foobar")) + Client.Must(Client.Command("", "/groupmsg "+user2.Username+","+user3.Username+","+user4.Username+","+user5.Username+","+user6.Username+","+user7.Username+","+user8.Username+","+user9.Username+" foobar")) + Client.Must(Client.Command("", "/groupmsg junk foobar")) + Client.Must(Client.Command("", "/groupmsg junk,junk2 foobar")) +} diff --git a/app/command_groupmsg.go b/app/command_groupmsg.go new file mode 100644 index 000000000..a07309f04 --- /dev/null +++ b/app/command_groupmsg.go @@ -0,0 +1,137 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "fmt" + "strings" + + l4g "github.com/alecthomas/log4go" + "github.com/mattermost/mattermost-server/model" + goi18n "github.com/nicksnyder/go-i18n/i18n" +) + +type groupmsgProvider struct { +} + +const ( + CMD_GROUPMSG = "groupmsg" +) + +func init() { + RegisterCommandProvider(&groupmsgProvider{}) +} + +func (me *groupmsgProvider) GetTrigger() string { + return CMD_GROUPMSG +} + +func (me *groupmsgProvider) GetCommand(T goi18n.TranslateFunc) *model.Command { + return &model.Command{ + Trigger: CMD_GROUPMSG, + AutoComplete: true, + AutoCompleteDesc: T("api.command_groupmsg.desc"), + AutoCompleteHint: T("api.command_groupmsg.hint"), + DisplayName: T("api.command_groupmsg.name"), + } +} + +func (me *groupmsgProvider) DoCommand(a *App, args *model.CommandArgs, message string) *model.CommandResponse { + targetUsers := map[string]*model.User{} + targetUsersSlice := []string{args.UserId} + invalidUsernames := []string{} + + users, parsedMessage := groupMsgUsernames(message) + + for _, username := range users { + username = strings.TrimSpace(username) + username = strings.TrimPrefix(username, "@") + if result := <-a.Srv.Store.User().GetByUsername(username); result.Err != nil { + invalidUsernames = append(invalidUsernames, username) + } else { + targetUser := result.Data.(*model.User) + _, exists := targetUsers[targetUser.Id] + if !exists && targetUser.Id != args.UserId { + targetUsers[targetUser.Id] = targetUser + targetUsersSlice = append(targetUsersSlice, targetUser.Id) + } + } + } + + if len(invalidUsernames) > 0 { + invalidUsersString := map[string]interface{}{ + "Users": "@" + strings.Join(invalidUsernames, ", @"), + } + return &model.CommandResponse{ + Text: args.T("api.command_groupmsg.invalid_user.app_error", len(invalidUsernames), invalidUsersString), + ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, + } + } + + if len(targetUsersSlice) == 2 { + return GetCommandProvider("msg").DoCommand(a, args, fmt.Sprintf("%s %s", targetUsers[targetUsersSlice[1]].Username, parsedMessage)) + } + + if len(targetUsersSlice) < model.CHANNEL_GROUP_MIN_USERS { + minUsers := map[string]interface{}{ + "MinUsers": model.CHANNEL_GROUP_MIN_USERS - 1, + } + return &model.CommandResponse{ + Text: args.T("api.command_groupmsg.min_users.app_error", minUsers), + ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, + } + } + + if len(targetUsersSlice) > model.CHANNEL_GROUP_MAX_USERS { + maxUsers := map[string]interface{}{ + "MaxUsers": model.CHANNEL_GROUP_MAX_USERS - 1, + } + return &model.CommandResponse{ + Text: args.T("api.command_groupmsg.max_users.app_error", maxUsers), + ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, + } + } + + groupChannel, channelErr := a.CreateGroupChannel(targetUsersSlice, args.UserId) + if channelErr != nil { + l4g.Error(channelErr.Error()) + return &model.CommandResponse{Text: args.T("api.command_groupmsg.group_fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} + } + + if len(parsedMessage) > 0 { + post := &model.Post{} + post.Message = parsedMessage + post.ChannelId = groupChannel.Id + post.UserId = args.UserId + if _, err := a.CreatePostMissingChannel(post, true); err != nil { + return &model.CommandResponse{Text: args.T("api.command_groupmsg.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} + } + } + + team, err := a.GetTeam(args.TeamId) + if err != nil { + return &model.CommandResponse{Text: args.T("api.command_groupmsg.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} + } + + return &model.CommandResponse{GotoLocation: args.SiteURL + "/" + team.Name + "/channels/" + groupChannel.Name, Text: "", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} +} + +func groupMsgUsernames(message string) ([]string, string) { + result := []string{} + resultMessage := "" + for idx, part := range strings.Split(message, ",") { + clean := strings.TrimPrefix(strings.TrimSpace(part), "@") + split := strings.Fields(clean) + if len(split) > 0 { + result = append(result, split[0]) + } + if len(split) > 1 { + splitted := strings.SplitN(message, ",", idx+1) + resultMessage = strings.TrimPrefix(strings.TrimSpace(splitted[len(splitted)-1]), "@") + resultMessage = strings.TrimSpace(strings.TrimPrefix(resultMessage, split[0])) + break + } + } + return result, resultMessage +} diff --git a/app/command_groupmsg_test.go b/app/command_groupmsg_test.go new file mode 100644 index 000000000..610d2e446 --- /dev/null +++ b/app/command_groupmsg_test.go @@ -0,0 +1,37 @@ +package app + +import ( + "testing" +) + +func TestGroupMsgUsernames(t *testing.T) { + if users, parsedMessage := groupMsgUsernames(""); len(users) != 0 || parsedMessage != "" { + t.Fatal("error parsing empty message") + } + if users, parsedMessage := groupMsgUsernames("test"); len(users) != 1 || parsedMessage != "" { + t.Fatal("error parsing simple user") + } + if users, parsedMessage := groupMsgUsernames("test1, test2, test3 , test4"); len(users) != 4 || parsedMessage != "" { + t.Fatal("error parsing various users") + } + + if users, parsedMessage := groupMsgUsernames("test1, test2 message with spaces"); len(users) != 2 || parsedMessage != "message with spaces" { + t.Fatal("error parsing message") + } + + if users, parsedMessage := groupMsgUsernames("test1, test2 message with, comma"); len(users) != 2 || parsedMessage != "message with, comma" { + t.Fatal("error parsing messages with comma") + } + + if users, parsedMessage := groupMsgUsernames("test1,,,test2"); len(users) != 2 || parsedMessage != "" { + t.Fatal("error parsing multiple commas in username ") + } + + if users, parsedMessage := groupMsgUsernames(" test1, test2 other message "); len(users) != 2 || parsedMessage != "other message" { + t.Fatal("error parsing strange usage of spaces") + } + + if users, _ := groupMsgUsernames(" test1, test2,,123,@321,+123"); len(users) != 5 || users[0] != "test1" || users[1] != "test2" || users[2] != "123" || users[3] != "321" || users[4] != "+123" { + t.Fatal("error parsing different types of users") + } +} diff --git a/i18n/en.json b/i18n/en.json index c1c73ce91..9ef50217d 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -820,6 +820,57 @@ "translation": "Messaged user." }, { + "id": "api.command_groupmsg.desc", + "translation": "Sends a Group Message to the specified users" + }, + { + "id": "api.command_groupmsg.group_fail.app_error", + "translation": "An error occurred while creating the group message." + }, + { + "id": "api.command_groupmsg.fail.app_error", + "translation": "An error occurred while messaging the users." + }, + { + "id": "api.command_groupmsg.invalid_user.app_error", + "translation": { + "one": "We couldn't find the user: {{.Users}}", + "other": "We couldn't find the users: {{.Users}}" + } + }, + { + "id": "api.command_groupmsg.invalid_users.app_error", + "translation": "We couldn't find the users: %s" + }, + { + "id": "api.command_groupmsg.min_users.app_error", + "translation": "Group messages are limited to a minimun of {{.MinUsers}} users." + }, + { + "id": "api.command_groupmsg.max_users.app_error", + "translation": "Group messages are limited to a maximum of {{.MaxUsers}} users." + }, + { + "id": "api.command_groupmsg.hint", + "translation": "@[username1],@[username2] 'message'" + }, + { + "id": "api.command_groupmsg.list.app_error", + "translation": "An error occurred while listing users." + }, + { + "id": "api.command_groupmsg.missing.app_error", + "translation": "We couldn't find the user" + }, + { + "id": "api.command_groupmsg.name", + "translation": "message" + }, + { + "id": "api.command_groupmsg.success", + "translation": "Messaged users." + }, + { "id": "api.command_offline.desc", "translation": "Set your status offline" }, |