MM-12358 Create CLI command "command modify" (#10538)
* Added ability to modify a command using the CLI * Added ability to modify a command using the CLI * Added TestModifyCommand to command_test.go and unit tests for new modify command * Added ability to modify a command using the CLI * Added TestModifyCommand to command_test.go and unit tests for new modify command
Этот коммит содержится в:
коммит произвёл
George Goldberg
родитель
40b97a1a4f
Коммит
1a102e13c8
@@ -62,6 +62,15 @@ var CommandDeleteCmd = &cobra.Command{
|
|||||||
RunE: deleteCommandCmdF,
|
RunE: deleteCommandCmdF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var CommandModifyCmd = &cobra.Command{
|
||||||
|
Use: "modify",
|
||||||
|
Short: "Modify a slash command",
|
||||||
|
Long: `Modify a slash command. Commands can be specified by command ID.`,
|
||||||
|
Example: ` command modify commandID`,
|
||||||
|
Args: cobra.MinimumNArgs(1),
|
||||||
|
RunE: modifyCommandCmdF,
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
CommandCreateCmd.Flags().String("title", "", "Command Title")
|
CommandCreateCmd.Flags().String("title", "", "Command Title")
|
||||||
CommandCreateCmd.Flags().String("description", "", "Command Description")
|
CommandCreateCmd.Flags().String("description", "", "Command Description")
|
||||||
@@ -78,12 +87,25 @@ func init() {
|
|||||||
CommandCreateCmd.Flags().String("autocompleteHint", "", "Command Arguments displayed as help in autocomplete list")
|
CommandCreateCmd.Flags().String("autocompleteHint", "", "Command Arguments displayed as help in autocomplete list")
|
||||||
CommandCreateCmd.Flags().Bool("post", false, "Use POST method for Callback URL")
|
CommandCreateCmd.Flags().Bool("post", false, "Use POST method for Callback URL")
|
||||||
|
|
||||||
|
CommandModifyCmd.Flags().String("title", "", "Command Title")
|
||||||
|
CommandModifyCmd.Flags().String("description", "", "Command Description")
|
||||||
|
CommandModifyCmd.Flags().String("trigger-word", "", "Command Trigger Word")
|
||||||
|
CommandModifyCmd.Flags().String("url", "", "Command Callback URL")
|
||||||
|
CommandModifyCmd.Flags().String("creator", "", "Command Creator's Username")
|
||||||
|
CommandModifyCmd.Flags().String("response-username", "", "Command Response Username")
|
||||||
|
CommandModifyCmd.Flags().String("icon", "", "Command Icon URL")
|
||||||
|
CommandModifyCmd.Flags().Bool("autocomplete", false, "Show Command in autocomplete list")
|
||||||
|
CommandModifyCmd.Flags().String("autocompleteDesc", "", "Short Command Description for autocomplete list")
|
||||||
|
CommandModifyCmd.Flags().String("autocompleteHint", "", "Command Arguments displayed as help in autocomplete list")
|
||||||
|
CommandModifyCmd.Flags().Bool("post", false, "Use POST method for Callback URL")
|
||||||
|
|
||||||
CommandCmd.AddCommand(
|
CommandCmd.AddCommand(
|
||||||
CommandCreateCmd,
|
CommandCreateCmd,
|
||||||
CommandShowCmd,
|
CommandShowCmd,
|
||||||
CommandMoveCmd,
|
CommandMoveCmd,
|
||||||
CommandListCmd,
|
CommandListCmd,
|
||||||
CommandDeleteCmd,
|
CommandDeleteCmd,
|
||||||
|
CommandModifyCmd,
|
||||||
)
|
)
|
||||||
RootCmd.AddCommand(CommandCmd)
|
RootCmd.AddCommand(CommandCmd)
|
||||||
}
|
}
|
||||||
@@ -268,3 +290,97 @@ func deleteCommandCmdF(command *cobra.Command, args []string) error {
|
|||||||
CommandPrettyPrintln("Deleted command '" + slashCommand.Id + "' (" + slashCommand.DisplayName + ")")
|
CommandPrettyPrintln("Deleted command '" + slashCommand.Id + "' (" + slashCommand.DisplayName + ")")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func modifyCommandCmdF(command *cobra.Command, args []string) error {
|
||||||
|
a, err := InitDBCommandContextCobra(command)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer a.Shutdown()
|
||||||
|
|
||||||
|
oldCommand := getCommandFromCommandArg(a, args[0])
|
||||||
|
if oldCommand == nil {
|
||||||
|
command.SilenceUsage = true
|
||||||
|
return errors.New("Unable to find command '" + args[0] + "'")
|
||||||
|
}
|
||||||
|
modifiedCommand := oldCommand
|
||||||
|
|
||||||
|
// get creator user
|
||||||
|
creator, _ := command.Flags().GetString("creator")
|
||||||
|
if creator != "" {
|
||||||
|
user := getUserFromUserArg(a, creator)
|
||||||
|
if user == nil {
|
||||||
|
return errors.New("unable to find user '" + creator + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if creator has permission to create slash commands
|
||||||
|
if !a.HasPermissionToTeam(user.Id, modifiedCommand.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
|
||||||
|
return errors.New("the creator must be a user who has permissions to manage slash commands")
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiedCommand.CreatorId = user.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
title, _ := command.Flags().GetString("title")
|
||||||
|
if title != "" {
|
||||||
|
modifiedCommand.DisplayName = title
|
||||||
|
}
|
||||||
|
|
||||||
|
description, _ := command.Flags().GetString("description")
|
||||||
|
if description != "" {
|
||||||
|
modifiedCommand.Description = description
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger, _ := command.Flags().GetString("trigger-word")
|
||||||
|
if trigger != "" {
|
||||||
|
if strings.HasPrefix(trigger, "/") {
|
||||||
|
return errors.New("a trigger word cannot begin with a /")
|
||||||
|
}
|
||||||
|
if strings.Contains(trigger, " ") {
|
||||||
|
return errors.New("a trigger word must not contain spaces")
|
||||||
|
}
|
||||||
|
modifiedCommand.Trigger = trigger
|
||||||
|
}
|
||||||
|
|
||||||
|
url, _ := command.Flags().GetString("url")
|
||||||
|
if url != "" {
|
||||||
|
modifiedCommand.URL = url
|
||||||
|
}
|
||||||
|
|
||||||
|
responseUsername, _ := command.Flags().GetString("response-username")
|
||||||
|
if responseUsername != "" {
|
||||||
|
modifiedCommand.Username = responseUsername
|
||||||
|
}
|
||||||
|
|
||||||
|
icon, _ := command.Flags().GetString("icon")
|
||||||
|
if icon != "" {
|
||||||
|
modifiedCommand.IconURL = icon
|
||||||
|
}
|
||||||
|
|
||||||
|
autocomplete, _ := command.Flags().GetBool("autocomplete")
|
||||||
|
modifiedCommand.AutoComplete = autocomplete
|
||||||
|
|
||||||
|
autocompleteDesc, _ := command.Flags().GetString("autocompleteDesc")
|
||||||
|
if autocompleteDesc != "" {
|
||||||
|
modifiedCommand.AutoCompleteDesc = autocompleteDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
autocompleteHint, _ := command.Flags().GetString("autocompleteHint")
|
||||||
|
if autocompleteHint != "" {
|
||||||
|
modifiedCommand.AutoCompleteHint = autocompleteHint
|
||||||
|
}
|
||||||
|
|
||||||
|
post, err := command.Flags().GetBool("post")
|
||||||
|
method := "P"
|
||||||
|
if err != nil || post == false {
|
||||||
|
method = "G"
|
||||||
|
}
|
||||||
|
modifiedCommand.Method = method
|
||||||
|
|
||||||
|
if _, err := a.UpdateCommand(oldCommand, modifiedCommand); err != nil {
|
||||||
|
return errors.New("unable to modify command '" + modifiedCommand.DisplayName + "'. " + err.Error())
|
||||||
|
}
|
||||||
|
CommandPrettyPrintln("modified command '" + modifiedCommand.DisplayName + "'")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -214,3 +214,231 @@ func TestDeleteCommand(t *testing.T) {
|
|||||||
assert.Error(t, th.RunCommand(t, "command", "delete", "invalid"))
|
assert.Error(t, th.RunCommand(t, "command", "delete", "invalid"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestModifyCommand(t *testing.T) {
|
||||||
|
th := Setup().InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
// set config
|
||||||
|
config := th.Config()
|
||||||
|
*config.ServiceSettings.EnableCommands = true
|
||||||
|
th.SetConfig(config)
|
||||||
|
|
||||||
|
// set team and users
|
||||||
|
team := th.BasicTeam
|
||||||
|
adminUser := th.TeamAdminUser
|
||||||
|
user := th.BasicUser
|
||||||
|
|
||||||
|
// create test command to modify
|
||||||
|
url := "http://localhost:8000/test-command"
|
||||||
|
th.LinkUserToTeam(user, team)
|
||||||
|
trigger := "trigger_" + model.NewId()
|
||||||
|
displayName := "dn_" + model.NewId()
|
||||||
|
|
||||||
|
c := &model.Command{
|
||||||
|
DisplayName: displayName,
|
||||||
|
Method: "G",
|
||||||
|
TeamId: team.Id,
|
||||||
|
Username: user.Username,
|
||||||
|
CreatorId: user.Id,
|
||||||
|
URL: url,
|
||||||
|
Trigger: trigger,
|
||||||
|
}
|
||||||
|
|
||||||
|
command, err := th.App.CreateCommand(c)
|
||||||
|
require.Nil(t, err)
|
||||||
|
commands, err := th.App.ListTeamCommands(team.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, len(commands), 1)
|
||||||
|
|
||||||
|
t.Run("command not specified", func(t *testing.T) {
|
||||||
|
args := []string{"command", "", command.Id, "--trigger-word", "sometrigger"}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
assert.Contains(t, string(output), "Error: unknown flag: --trigger-word")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("modify command unchanged", func(t *testing.T) {
|
||||||
|
args := []string{"command", "modify", command.Id}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.DisplayName, command.DisplayName)
|
||||||
|
assert.Equal(t, cmd.Method, command.Method)
|
||||||
|
assert.Equal(t, cmd.TeamId, command.TeamId)
|
||||||
|
assert.Equal(t, cmd.Username, command.Username)
|
||||||
|
assert.Equal(t, cmd.CreatorId, command.CreatorId)
|
||||||
|
assert.Equal(t, cmd.URL, command.URL)
|
||||||
|
assert.Equal(t, cmd.Trigger, command.Trigger)
|
||||||
|
assert.Equal(t, cmd.AutoComplete, command.AutoComplete)
|
||||||
|
assert.Equal(t, cmd.AutoCompleteDesc, command.AutoCompleteDesc)
|
||||||
|
assert.Equal(t, cmd.AutoCompleteHint, command.AutoCompleteHint)
|
||||||
|
assert.Equal(t, cmd.IconURL, command.IconURL)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("mispelled flag", func(t *testing.T) {
|
||||||
|
args := []string{"command", "", command.Id, "--trigger-wor", "sometrigger"}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
assert.Contains(t, string(output), "Error: unknown flag:")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple flags nil error", func(t *testing.T) {
|
||||||
|
testName := "multitrigger"
|
||||||
|
testURL := "http://localhost:8000/test-modify"
|
||||||
|
testDescription := "multiple field test"
|
||||||
|
args := []string{"command", "modify", command.Id, "--trigger-word", testName, "--url", testURL, "--description", testDescription}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.Trigger, testName)
|
||||||
|
assert.Equal(t, cmd.URL, testURL)
|
||||||
|
assert.Equal(t, cmd.Description, testDescription)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("displayname nil error", func(t *testing.T) {
|
||||||
|
testVal := "newName"
|
||||||
|
args := []string{"command", "modify", command.Id, "--title", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.DisplayName, testVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("description nil error", func(t *testing.T) {
|
||||||
|
testVal := "test description"
|
||||||
|
args := []string{"command", "modify", command.Id, "--description", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.Description, testVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("trigger nil error", func(t *testing.T) {
|
||||||
|
testVal := "testtrigger"
|
||||||
|
args := []string{"command", "modify", command.Id, "--trigger-word", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.Trigger, testVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("trigger with space", func(t *testing.T) {
|
||||||
|
testVal := "bad trigger"
|
||||||
|
args := []string{"command", "modify", command.Id, "--trigger-word", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
assert.Contains(t, string(output), "Error: a trigger word must not contain spaces")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("trigger with leading /", func(t *testing.T) {
|
||||||
|
testVal := "/bad-trigger"
|
||||||
|
args := []string{"command", "modify", command.Id, "--trigger-word", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
assert.Contains(t, string(output), "Error: a trigger word cannot begin with a /")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("blank trigger", func(t *testing.T) {
|
||||||
|
cmd_unmodified, _ := th.App.GetCommand(command.Id)
|
||||||
|
args := []string{"command", "modify", command.Id, "--trigger-word", ""}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd_modified, _ := th.App.GetCommand(command.Id)
|
||||||
|
|
||||||
|
// assert trigger remains unchanged
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd_unmodified.Trigger, cmd_modified.Trigger)
|
||||||
|
})
|
||||||
|
|
||||||
|
//url case
|
||||||
|
t.Run("url nil error", func(t *testing.T) {
|
||||||
|
testVal := "http://localhost:8000/modify-command"
|
||||||
|
args := []string{"command", "modify", command.Id, "--url", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.URL, testVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("blank url", func(t *testing.T) {
|
||||||
|
cmd_unmodified, _ := th.App.GetCommand(command.Id)
|
||||||
|
args := []string{"command", "modify", command.Id, "--url", ""}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd_modified, _ := th.App.GetCommand(command.Id)
|
||||||
|
|
||||||
|
//assert URL remains unchanged
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd_unmodified.URL, cmd_modified.URL)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("icon url nil error", func(t *testing.T) {
|
||||||
|
testVal := "http://localhost:8000/testicon.png"
|
||||||
|
args := []string{"command", "modify", command.Id, "--icon", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.IconURL, testVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("creator nil error", func(t *testing.T) {
|
||||||
|
testVal := adminUser
|
||||||
|
args := []string{"command", "modify", command.Id, "--creator", testVal.Username}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.CreatorId, testVal.Id)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("creator not found", func(t *testing.T) {
|
||||||
|
testVal := "fakeuser"
|
||||||
|
args := []string{"command", "modify", command.Id, "--creator", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
assert.Contains(t, string(output), "unable to find user")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("creator not admin user", func(t *testing.T) {
|
||||||
|
testVal := user.Username
|
||||||
|
args := []string{"command", "modify", command.Id, "--creator", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
assert.Contains(t, string(output), "the creator must be a user who has permissions to manage slash commands")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("response username nil error", func(t *testing.T) {
|
||||||
|
testVal := "response-test"
|
||||||
|
args := []string{"command", "modify", command.Id, "--response-username", testVal}
|
||||||
|
output, _ := th.RunCommandWithOutput(t, args...)
|
||||||
|
cmd, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output), "PASS")
|
||||||
|
assert.Equal(t, cmd.Username, testVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("post set and unset", func(t *testing.T) {
|
||||||
|
args_set := []string{"command", "modify", command.Id, "--post", ""}
|
||||||
|
args_unset := []string{"command", "modify", command.Id, "", ""}
|
||||||
|
|
||||||
|
// set post and check
|
||||||
|
output_set, _ := th.RunCommandWithOutput(t, args_set...)
|
||||||
|
cmd_set, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output_set), "PASS")
|
||||||
|
assert.Equal(t, cmd_set.Method, "P")
|
||||||
|
|
||||||
|
// unset post and check
|
||||||
|
output_unset, _ := th.RunCommandWithOutput(t, args_unset...)
|
||||||
|
cmd_unset, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output_unset), "PASS")
|
||||||
|
assert.Equal(t, cmd_unset.Method, "G")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("autocomplete set and unset", func(t *testing.T) {
|
||||||
|
args_set := []string{"command", "modify", command.Id, "--autocomplete", ""}
|
||||||
|
args_unset := []string{"command", "modify", command.Id, "", ""}
|
||||||
|
|
||||||
|
// set autocomplete and check
|
||||||
|
output_set, _ := th.RunCommandWithOutput(t, args_set...)
|
||||||
|
cmd_set, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output_set), "PASS")
|
||||||
|
assert.Equal(t, cmd_set.AutoComplete, true)
|
||||||
|
|
||||||
|
// unset autocomplete and check
|
||||||
|
output_unset, _ := th.RunCommandWithOutput(t, args_unset...)
|
||||||
|
cmd_unset, _ := th.App.GetCommand(command.Id)
|
||||||
|
assert.Contains(t, string(output_unset), "PASS")
|
||||||
|
assert.Equal(t, cmd_unset.AutoComplete, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user