From 6d0658076b6ccf4e3d8f63fda7df39ec1cb794ce Mon Sep 17 00:00:00 2001 From: Doug Lauder Date: Thu, 12 Mar 2020 03:37:14 -0400 Subject: [PATCH] MM-23031 support team:trigger syntax (#135) * MM-23031 support team:trigger syntax * remove redundant check; compare error strings in unit tests * Update commands/commandargs.go Co-Authored-By: Miguel de la Cruz Co-authored-by: Miguel de la Cruz Co-authored-by: mattermod --- commands/command_test.go | 97 ++++++++++++++++++++++++++++++++++++++-- commands/commandargs.go | 40 +++++++++++++++-- 2 files changed, 130 insertions(+), 7 deletions(-) diff --git a/commands/command_test.go b/commands/command_test.go index 6909f8e01..6fa4fd6a3 100644 --- a/commands/command_test.go +++ b/commands/command_test.go @@ -33,7 +33,7 @@ func (s *MmctlUnitTestSuite) TestCommandCreateCmd() { autocompleteDesc := "autocompleteDesc" autocompleteHint := "autocompleteHint" - mockTeam := model.Team{Id: teamArg} + mockTeam := model.Team{Id: teamArg, Name: "TeamRed"} mockUser := model.User{Id: creatorIDArg, Username: creatorUsernameArg} mockCommand := model.Command{ TeamId: teamArg, @@ -678,7 +678,7 @@ func (s *MmctlUnitTestSuite) TestCommandModifyCmd() { s.EqualError(err, "a trigger word must not contain spaces") }) - s.Run("Create slash command with trigger word prefixed with /", func() { + s.Run("Modify slash command with trigger word prefixed with /", func() { printer.Clean() mockCommandModified := copyCommand(&mockCommand) mockCommandModified.Trigger = "/modified_with_slash" @@ -709,7 +709,7 @@ func (s *MmctlUnitTestSuite) TestCommandModifyCmd() { s.EqualError(err, "a trigger word cannot begin with a /") }) - s.Run("Create slash command fail", func() { + s.Run("Modify slash command fail", func() { printer.Clean() mockCommandModified := copyCommand(&mockCommand) mockCommandModified.Trigger = creatorIDArg + "_modified" @@ -928,8 +928,9 @@ func (s *MmctlUnitTestSuite) TestCommandShowCmd() { AutoCompleteDesc: "example autocomplete description", AutoCompleteHint: "autocompleteHint", } + mockTeam := model.Team{Id: "mockteamid", Name: "TeamRed"} - s.Run("Show custom slash command", func() { + s.Run("Show custom slash command via id", func() { printer.Clean() // showCommandCmdF will look up command by id @@ -962,6 +963,94 @@ func (s *MmctlUnitTestSuite) TestCommandShowCmd() { s.Require().Len(printer.GetErrorLines(), 0) }) + s.Run("Show custom slash command via team:trigger", func() { + printer.Clean() + + list := []*model.Command{copyCommand(&mockCommand), &mockCommand, copyCommand(&mockCommand)} + list[0].Trigger = "bloop" + list[2].Trigger = "bleep" + + s.client. + EXPECT(). + GetTeamByName(mockTeam.Name, ""). + Return(&mockTeam, &model.Response{Error: nil}). + Times(1) + + s.client. + EXPECT(). + ListCommands(mockTeam.Id, false). + Return(list, &model.Response{Error: nil}). + Times(1) + + err := showCommandCmdF(s.client, &cobra.Command{}, []string{fmt.Sprintf("%s:%s", mockTeam.Name, mockCommand.Trigger)}) + s.Require().NoError(err) + s.Require().Len(printer.GetLines(), 1) + s.Equal(&mockCommand, printer.GetLines()[0]) + s.Require().Len(printer.GetErrorLines(), 0) + }) + + s.Run("Show custom slash command via team:trigger with invalid team", func() { + printer.Clean() + + list := []*model.Command{copyCommand(&mockCommand), &mockCommand, copyCommand(&mockCommand)} + list[0].Trigger = "bloop" + list[2].Trigger = "bleep" + + const teamName = "bogus_team" + teamTrigger := fmt.Sprintf("%s:%s", teamName, mockCommand.Trigger) + + s.client. + EXPECT(). + GetTeamByName(teamName, ""). + Return(nil, &model.Response{Error: &model.AppError{Message: "team not found"}}). + Times(1) + + s.client. + EXPECT(). + GetCommandById(teamTrigger). + Return(nil, &model.Response{Error: &model.AppError{Message: "command not found"}}). + Times(1) + + err := showCommandCmdF(s.client, &cobra.Command{}, []string{teamTrigger}) + s.Require().EqualError(err, fmt.Sprintf("unable to find command '%s'", teamTrigger)) + s.Require().Len(printer.GetLines(), 0) + s.Require().Len(printer.GetErrorLines(), 0) + }) + + s.Run("Show custom slash command via team:trigger with invalid trigger", func() { + printer.Clean() + + list := []*model.Command{copyCommand(&mockCommand), &mockCommand, copyCommand(&mockCommand)} + list[0].Trigger = "bloop" + list[2].Trigger = "bleep" + + const trigger = "bogus_trigger" + teamTrigger := fmt.Sprintf("%s:%s", mockTeam.Name, trigger) + + s.client. + EXPECT(). + GetTeamByName(mockTeam.Name, ""). + Return(&mockTeam, &model.Response{Error: nil}). + Times(1) + + s.client. + EXPECT(). + ListCommands(mockTeam.Id, false). + Return(list, &model.Response{Error: nil}). + Times(1) + + s.client. + EXPECT(). + GetCommandById(teamTrigger). + Return(nil, &model.Response{Error: &model.AppError{Message: "bogus"}}). + Times(1) + + err := showCommandCmdF(s.client, &cobra.Command{}, []string{teamTrigger}) + s.Require().EqualError(err, fmt.Sprintf("unable to find command '%s'", teamTrigger)) + s.Require().Len(printer.GetLines(), 0) + s.Require().Len(printer.GetErrorLines(), 0) + }) + s.Run("Avoid path traversal", func() { printer.Clean() arg := "\"test/../hello?\"move" diff --git a/commands/commandargs.go b/commands/commandargs.go index 6c67f7b17..0cc2741e9 100644 --- a/commands/commandargs.go +++ b/commands/commandargs.go @@ -4,18 +4,52 @@ package commands import ( + "strings" + "github.com/mattermost/mmctl/client" "github.com/mattermost/mattermost-server/v5/model" ) -// getCommandFromCommandArg retrieves a Command by command id. Future versions -// may allow lookup by team:trigger +// getCommandFromCommandArg retrieves a Command by command id or team:trigger. func getCommandFromCommandArg(c client.Client, commandArg string) *model.Command { if checkSlash(commandArg) { return nil } - cmd, _ := c.GetCommandById(commandArg) + cmd := getCommandFromTeamTrigger(c, commandArg) + if cmd == nil { + cmd, _ = c.GetCommandById(commandArg) + } return cmd } + +// getCommandFromTeamTrigger retrieves a Command via team:trigger syntax. +func getCommandFromTeamTrigger(c client.Client, teamTrigger string) *model.Command { + arr := strings.Split(teamTrigger, ":") + if len(arr) != 2 { + return nil + } + + team, _ := c.GetTeamByName(arr[0], "") + if team == nil { + return nil + } + + trigger := arr[1] + if len(trigger) == 0 { + return nil + } + + list, _ := c.ListCommands(team.Id, false) + if list == nil { + return nil + } + + for _, cmd := range list { + if cmd.Trigger == trigger { + return cmd + } + } + return nil +}