diff --git a/api/command.go b/api/command.go index 2248caf767ddd..b972951600d10 100644 --- a/api/command.go +++ b/api/command.go @@ -34,7 +34,7 @@ func InitCommand() { } func listCommands(c *Context, w http.ResponseWriter, r *http.Request) { - commands, err := app.ListCommands(c.TeamId, c.T) + commands, err := app.ListAutocompleteCommands(c.TeamId, c.T) if err != nil { c.Err = err return diff --git a/api4/command.go b/api4/command.go index 64766ef3c9512..41a85eac36160 100644 --- a/api4/command.go +++ b/api4/command.go @@ -5,6 +5,7 @@ package api4 import ( "net/http" + "strconv" l4g "github.com/alecthomas/log4go" "github.com/mattermost/platform/app" @@ -16,6 +17,7 @@ func InitCommand() { l4g.Debug(utils.T("api.command.init.debug")) BaseRoutes.Commands.Handle("", ApiSessionRequired(createCommand)).Methods("POST") + BaseRoutes.Commands.Handle("", ApiSessionRequired(listCommands)).Methods("GET") } func createCommand(c *Context, w http.ResponseWriter, r *http.Request) { @@ -44,3 +46,48 @@ func createCommand(c *Context, w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) w.Write([]byte(rcmd.ToJson())) } + +func listCommands(c *Context, w http.ResponseWriter, r *http.Request) { + customOnly, failConv := strconv.ParseBool(r.URL.Query().Get("custom_only")) + if failConv != nil { + customOnly = false + } + + teamId := r.URL.Query().Get("team_id") + + if len(teamId) == 0 { + c.SetInvalidParam("team_id") + return + } + + commands := []*model.Command{} + err := &model.AppError{} + if customOnly { + if !app.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { + c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS) + return + } + commands, err = app.ListTeamCommands(teamId) + if err != nil { + c.Err = err + return + } + } else { + //User with no permission should see only system commands + if !app.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { + commands, err = app.ListAutocompleteCommands(teamId, c.T) + if err != nil { + c.Err = err + return + } + } else { + commands, err = app.ListAllCommands(teamId, c.T) + if err != nil { + c.Err = err + return + } + } + } + + w.Write([]byte(model.CommandListToJson(commands))) +} diff --git a/api4/command_test.go b/api4/command_test.go index aa3ad37b6b50b..3c80764704f42 100644 --- a/api4/command_test.go +++ b/api4/command_test.go @@ -59,3 +59,80 @@ func TestCreateCommand(t *testing.T) { CheckNotImplementedStatus(t, resp) CheckErrorMessage(t, resp, "api.command.disabled.app_error") } + +func TestListCommands(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + + newCmd := &model.Command{ + CreatorId: th.BasicUser.Id, + TeamId: th.BasicTeam.Id, + URL: "http://nowhere.com", + Method: model.COMMAND_METHOD_POST, + Trigger: "custom_command"} + + _, resp := th.SystemAdminClient.CreateCommand(newCmd) + CheckNoError(t, resp) + + t.Run("ListSystemAndCustomCommands", func(t *testing.T) { + listCommands, resp := th.SystemAdminClient.ListCommands(th.BasicTeam.Id, false) + CheckNoError(t, resp) + + foundEcho := false + foundCustom := false + for _, command := range listCommands { + if command.Trigger == "echo" { + foundEcho = true + } + if command.Trigger == "custom_command" { + foundCustom = true + } + } + if !foundEcho { + t.Fatal("Couldn't find echo command") + } + if !foundCustom { + t.Fatal("Should list the custom command") + } + }) + + t.Run("ListCustomOnlyCommands", func(t *testing.T) { + listCommands, resp := th.SystemAdminClient.ListCommands(th.BasicTeam.Id, true) + CheckNoError(t, resp) + + if len(listCommands) > 1 { + t.Fatal("Should list just one custom command") + } + if listCommands[0].Trigger != "custom_command" { + t.Fatal("Wrong custom command trigger") + } + }) + + t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) { + _, resp := Client.ListCommands(th.BasicTeam.Id, true) + CheckForbiddenStatus(t, resp) + }) + + t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) { + listCommands, resp := Client.ListCommands(th.BasicTeam.Id, false) + CheckNoError(t, resp) + + foundEcho := false + foundCustom := false + for _, command := range listCommands { + if command.Trigger == "echo" { + foundEcho = true + } + if command.Trigger == "custom_command" { + foundCustom = true + } + } + if !foundEcho { + t.Fatal("Couldn't find echo command") + } + if foundCustom { + t.Fatal("Should not list the custom command") + } + }) +} diff --git a/app/command.go b/app/command.go index 4583cf81be7d6..44e846a8123e1 100644 --- a/app/command.go +++ b/app/command.go @@ -61,7 +61,8 @@ func CreateCommandPost(post *model.Post, teamId string, response *model.CommandR return post, nil } -func ListCommands(teamId string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { +// previous ListCommands now ListAutocompleteCommands +func ListAutocompleteCommands(teamId string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { commands := make([]*model.Command, 0, 32) seen := make(map[string]bool) for _, value := range commandProviders { @@ -103,6 +104,36 @@ func ListTeamCommands(teamId string) ([]*model.Command, *model.AppError) { } } +func ListAllCommands(teamId string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { + commands := make([]*model.Command, 0, 32) + seen := make(map[string]bool) + for _, value := range commandProviders { + cpy := *value.GetCommand(T) + if cpy.AutoComplete && !seen[cpy.Id] { + cpy.Sanitize() + seen[cpy.Trigger] = true + commands = append(commands, &cpy) + } + } + + if *utils.Cfg.ServiceSettings.EnableCommands { + if result := <-Srv.Store.Command().GetByTeam(teamId); result.Err != nil { + return nil, result.Err + } else { + teamCmds := result.Data.([]*model.Command) + for _, cmd := range teamCmds { + if !seen[cmd.Id] { + cmd.Sanitize() + seen[cmd.Trigger] = true + commands = append(commands, cmd) + } + } + } + } + + return commands, nil +} + func ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { parts := strings.Split(args.Command, " ") trigger := parts[0][1:] diff --git a/model/client4.go b/model/client4.go index e62ce57bdd582..c542851e9cc29 100644 --- a/model/client4.go +++ b/model/client4.go @@ -2019,6 +2019,17 @@ func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) { } } +// ListCommands will retrieve a list of commands available in the team. +func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) { + query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly) + if r, err := c.DoApiGet(c.GetCommandsRoute()+query, ""); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return CommandListFromJson(r.Body), BuildResponse(r) + } +} + // Status Section // GetUserStatus returns a user based on the provided user id string.