summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Tadeu Panato Junior <ctadeu@gmail.com>2018-04-16 14:23:58 +0200
committerJesús Espino <jespinog@gmail.com>2018-04-16 14:23:58 +0200
commitbf24f51c4e1cc6286885460672f7f449e8c6f5ef (patch)
tree147773b452dd017451dcc63f3f752b82d5c7694a
parent0759cf639d1872680c9fc204cdef91cb784fac72 (diff)
downloadchat-bf24f51c4e1cc6286885460672f7f449e8c6f5ef.tar.gz
chat-bf24f51c4e1cc6286885460672f7f449e8c6f5ef.tar.bz2
chat-bf24f51c4e1cc6286885460672f7f449e8c6f5ef.zip
[MM-9904] Add /invite slash command to invite users to a channel (#8482)
* [MM-9904] Add /invite slash command to invite users to a channel * Update en.json
-rw-r--r--app/apptestlib.go14
-rw-r--r--app/command_invite.go102
-rw-r--r--app/command_invite_test.go108
-rw-r--r--i18n/en.json48
4 files changed, 272 insertions, 0 deletions
diff --git a/app/apptestlib.go b/app/apptestlib.go
index 6c2273c6e..1b22831c9 100644
--- a/app/apptestlib.go
+++ b/app/apptestlib.go
@@ -218,6 +218,20 @@ func (me *TestHelper) createChannel(team *model.Team, channelType string) *model
return channel
}
+func (me *TestHelper) CreateDmChannel(user *model.User) *model.Channel {
+ utils.DisableDebugLogForTest()
+ var err *model.AppError
+ var channel *model.Channel
+ if channel, err = me.App.CreateDirectChannel(me.BasicUser.Id, user.Id); err != nil {
+ l4g.Error(err.Error())
+ l4g.Close()
+ time.Sleep(time.Second)
+ panic(err)
+ }
+ utils.EnableDebugLogForTest()
+ return channel
+}
+
func (me *TestHelper) CreatePost(channel *model.Channel) *model.Post {
id := model.NewId()
diff --git a/app/command_invite.go b/app/command_invite.go
new file mode 100644
index 000000000..ce443bf3d
--- /dev/null
+++ b/app/command_invite.go
@@ -0,0 +1,102 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package app
+
+import (
+ "strings"
+
+ l4g "github.com/alecthomas/log4go"
+ "github.com/mattermost/mattermost-server/model"
+ goi18n "github.com/nicksnyder/go-i18n/i18n"
+)
+
+type InviteProvider struct {
+}
+
+const (
+ CMD_INVITE = "invite"
+)
+
+func init() {
+ RegisterCommandProvider(&InviteProvider{})
+}
+
+func (me *InviteProvider) GetTrigger() string {
+ return CMD_INVITE
+}
+
+func (me *InviteProvider) GetCommand(a *App, T goi18n.TranslateFunc) *model.Command {
+ return &model.Command{
+ Trigger: CMD_INVITE,
+ AutoComplete: true,
+ AutoCompleteDesc: T("api.command_invite.desc"),
+ AutoCompleteHint: T("api.command_invite.hint"),
+ DisplayName: T("api.command_invite.name"),
+ }
+}
+
+func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message string) *model.CommandResponse {
+ if message == "" {
+ return &model.CommandResponse{Text: args.T("api.command_invite.missing_message.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ l4g.Debug(message)
+
+ splitMessage := strings.SplitN(message, " ", 2)
+ targetUsername := splitMessage[0]
+ targetUsername = strings.TrimPrefix(targetUsername, "@")
+
+ var userProfile *model.User
+ if result := <-a.Srv.Store.User().GetByUsername(targetUsername); result.Err != nil {
+ l4g.Error(result.Err.Error())
+ return &model.CommandResponse{Text: args.T("api.command_invite.missing_user.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ } else {
+ userProfile = result.Data.(*model.User)
+ }
+
+ var channelToJoin *model.Channel
+ var err *model.AppError
+ // User set a channel to add the invited user
+ if len(splitMessage) > 1 && splitMessage[1] != "" {
+ targetChannelName := strings.TrimPrefix(strings.TrimSpace(splitMessage[1]), "~")
+
+ if channelToJoin, err = a.GetChannelByName(targetChannelName, args.TeamId); err != nil {
+ return &model.CommandResponse{Text: args.T("api.command_invite.channel.error", map[string]interface{}{"Channel": targetChannelName}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+ } else {
+ channelToJoin, err = a.GetChannel(args.ChannelId)
+ if err != nil {
+ return &model.CommandResponse{Text: args.T("api.command_invite.channel.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+ }
+
+ // Check if is a Direct Channel
+ if channelToJoin.Type == model.CHANNEL_DIRECT || channelToJoin.Type == model.CHANNEL_GROUP {
+ return &model.CommandResponse{Text: args.T("api.command_invite.directchannel.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ // Check if user is already in the channel
+ _, err = a.GetChannelMember(channelToJoin.Id, userProfile.Id)
+ if err == nil {
+ return &model.CommandResponse{Text: args.T("api.command_invite.user_already_in_channel.app_error", map[string]interface{}{"User": userProfile.Username}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ if channelToJoin.Type == model.CHANNEL_OPEN && !a.SessionHasPermissionToChannel(args.Session, channelToJoin.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS) {
+ return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ if channelToJoin.Type == model.CHANNEL_PRIVATE && !a.SessionHasPermissionToChannel(args.Session, channelToJoin.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) {
+ return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ if _, err := a.AddChannelMember(userProfile.Id, channelToJoin, args.Session.UserId, ""); err != nil {
+ return &model.CommandResponse{Text: args.T("api.command_invite.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ if args.ChannelId != channelToJoin.Id {
+ return &model.CommandResponse{Text: args.T("api.command_invite.success", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
+ }
+
+ return &model.CommandResponse{}
+}
diff --git a/app/command_invite_test.go b/app/command_invite_test.go
new file mode 100644
index 000000000..c46bc4628
--- /dev/null
+++ b/app/command_invite_test.go
@@ -0,0 +1,108 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package app
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/mattermost/mattermost-server/model"
+)
+
+func TestInviteProvider(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN)
+ privateChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE)
+ dmChannel := th.CreateDmChannel(th.BasicUser2)
+
+ basicUser3 := th.CreateUser()
+ th.LinkUserToTeam(basicUser3, th.BasicTeam)
+ basicUser4 := th.CreateUser()
+
+ InviteP := InviteProvider{}
+ args := &model.CommandArgs{
+ T: func(s string, args ...interface{}) string { return s },
+ ChannelId: th.BasicChannel.Id,
+ TeamId: th.BasicTeam.Id,
+ Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}},
+ }
+
+ userAndWrongChannel := "@" + th.BasicUser2.Username + " wrongchannel1"
+ userAndChannel := "@" + th.BasicUser2.Username + " ~" + channel.Name + " "
+ userAndDisplayChannel := "@" + th.BasicUser2.Username + " ~" + channel.DisplayName + " "
+ userAndPrivateChannel := "@" + th.BasicUser2.Username + " ~" + privateChannel.Name
+ userAndDMChannel := "@" + basicUser3.Username + " ~" + dmChannel.Name
+
+ tests := []struct {
+ desc string
+ expected string
+ msg string
+ }{
+ {
+ desc: "Missing user and channel in the command",
+ expected: "api.command_invite.missing_message.app_error",
+ msg: "",
+ },
+ {
+ desc: "User added in the current channel",
+ expected: "",
+ msg: th.BasicUser2.Username,
+ },
+ {
+ desc: "Add user to another channel not the current",
+ expected: "api.command_invite.success",
+ msg: userAndChannel,
+ },
+ {
+ desc: "try to add a user to a direct channel",
+ expected: "api.command_invite.directchannel.app_error",
+ msg: userAndDMChannel,
+ },
+ {
+ desc: "Try to add a user to a invalid channel",
+ expected: "api.command_invite.channel.error",
+ msg: userAndWrongChannel,
+ },
+ {
+ desc: "Try to add a user to an private channel",
+ expected: "api.command_invite.success",
+ msg: userAndPrivateChannel,
+ },
+ {
+ desc: "Using display channel name which is different form Channel name",
+ expected: "api.command_invite.channel.error",
+ msg: userAndDisplayChannel,
+ },
+ {
+ desc: "Invalid user to current channel",
+ expected: "api.command_invite.missing_user.app_error",
+ msg: "@invalidUser123",
+ },
+ {
+ desc: "Invalid user to current channel without @",
+ expected: "api.command_invite.missing_user.app_error",
+ msg: "invalidUser321",
+ },
+ {
+ desc: "try to add a user which is not part of the team",
+ expected: "api.command_invite.fail.app_error",
+ msg: basicUser4.Username,
+ },
+ {
+ desc: "try to add a user to a direct channel",
+ expected: "api.command_invite.directchannel.app_error",
+ msg: userAndDMChannel,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.desc, func(t *testing.T) {
+ actual := InviteP.DoCommand(th.App, args, test.msg).Text
+ assert.Equal(t, test.expected, actual)
+ })
+ }
+}
diff --git a/i18n/en.json b/i18n/en.json
index 02ac46e70..c7276b6cc 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -815,6 +815,54 @@
"translation": "Joined channel."
},
{
+ "id": "api.command_invite.hint",
+ "translation": "@[username] ~[channel]"
+ },
+ {
+ "id": "api.command_invite.name",
+ "translation": "invite"
+ },
+ {
+ "id": "api.command_invite.desc",
+ "translation": "Invite a user to a channel"
+ },
+ {
+ "id": "api.command_invite.missing_message.app_error",
+ "translation": "Missing Username and Channel."
+ },
+ {
+ "id": "api.command_invite.missing_user.app_error",
+ "translation": "We couldn't find the user."
+ },
+ {
+ "id": "api.command_invite.channel.app_error",
+ "translation": "Error to retrieve the current channel."
+ },
+ {
+ "id": "api.command_invite.channel.error",
+ "translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels."
+ },
+ {
+ "id": "api.command_invite.fail.app_error",
+ "translation": "An error occurred while joining the channel."
+ },
+ {
+ "id": "api.command_invite.permission.app_error",
+ "translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}."
+ },
+ {
+ "id": "api.command_invite.directchannel.app_error",
+ "translation": "You can't add someone to a direct message channel."
+ },
+ {
+ "id": "api.command_invite.user_already_in_channel.app_error",
+ "translation": "{{.User}} is already in the channel."
+ },
+ {
+ "id": "api.command_invite.success",
+ "translation": "{{.User}} added to {{.Channel}} channel."
+ },
+ {
"id": "api.command_kick.name",
"translation": "kick"
},