summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/command.go10
-rw-r--r--app/command_test.go46
-rw-r--r--cmd/platform/command.go69
-rw-r--r--cmd/platform/commandargs.go63
-rw-r--r--cmd/platform/mattermost.go2
-rw-r--r--i18n/en.json4
-rw-r--r--store/sqlstore/command_store.go21
-rw-r--r--store/sqlstore/command_store_test.go36
-rw-r--r--store/store.go2
9 files changed, 252 insertions, 1 deletions
diff --git a/app/command.go b/app/command.go
index d3e36b0e0..6e439537e 100644
--- a/app/command.go
+++ b/app/command.go
@@ -336,6 +336,16 @@ func (a *App) UpdateCommand(oldCmd, updatedCmd *model.Command) (*model.Command,
}
}
+func (a *App) MoveCommand(team *model.Team, command *model.Command) *model.AppError {
+ command.TeamId = team.Id
+
+ if result := <-a.Srv.Store.Command().Update(command); result.Err != nil {
+ return result.Err
+ }
+
+ return nil
+}
+
func (a *App) RegenCommandToken(cmd *model.Command) (*model.Command, *model.AppError) {
if !*utils.Cfg.ServiceSettings.EnableCommands {
return nil, model.NewAppError("RegenCommandToken", "api.command.disabled.app_error", nil, "", http.StatusNotImplemented)
diff --git a/app/command_test.go b/app/command_test.go
new file mode 100644
index 000000000..be1da3ac7
--- /dev/null
+++ b/app/command_test.go
@@ -0,0 +1,46 @@
+// Copyright (c) 2017-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 TestMoveCommand(t *testing.T) {
+ th := Setup().InitBasic()
+
+ sourceTeam := th.CreateTeam()
+ targetTeam := th.CreateTeam()
+
+ command := &model.Command{}
+ command.CreatorId = model.NewId()
+ command.Method = model.COMMAND_METHOD_POST
+ command.TeamId = sourceTeam.Id
+ command.URL = "http://nowhere.com/"
+ command.Trigger = "trigger1"
+
+ command, err := th.App.CreateCommand(command)
+ assert.Nil(t, err)
+
+ defer func() {
+ th.App.PermanentDeleteTeam(sourceTeam)
+ th.App.PermanentDeleteTeam(targetTeam)
+ }()
+
+ // Move a command and check the team is updated.
+ assert.Nil(t, th.App.MoveCommand(targetTeam, command))
+ retrievedCommand, err := th.App.GetCommand(command.Id)
+ assert.Nil(t, err)
+ assert.EqualValues(t, targetTeam.Id, retrievedCommand.TeamId)
+
+ // Move it to the team it's already in. Nothing should change.
+ assert.Nil(t, th.App.MoveCommand(targetTeam, command))
+ retrievedCommand, err = th.App.GetCommand(command.Id)
+ assert.Nil(t, err)
+ assert.EqualValues(t, targetTeam.Id, retrievedCommand.TeamId)
+}
diff --git a/cmd/platform/command.go b/cmd/platform/command.go
new file mode 100644
index 000000000..245fb7912
--- /dev/null
+++ b/cmd/platform/command.go
@@ -0,0 +1,69 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+package main
+
+import (
+ "errors"
+ "github.com/mattermost/mattermost-server/app"
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/spf13/cobra"
+)
+
+var commandCmd = &cobra.Command{
+ Use: "command",
+ Short: "Management of slash commands",
+}
+
+var commandMoveCmd = &cobra.Command{
+ Use: "move",
+ Short: "Move a slash command to a different team",
+ Long: `Move a slash command to a different team. Commands can be specified by [team]:[command-trigger-word]. ie. myteam:trigger or by command ID.`,
+ Example: ` command move newteam oldteam:command`,
+ RunE: moveCommandCmdF,
+}
+
+func init() {
+ commandCmd.AddCommand(
+ commandMoveCmd,
+ )
+}
+
+func moveCommandCmdF(cmd *cobra.Command, args []string) error {
+ a, err := initDBCommandContextCobra(cmd)
+ if err != nil {
+ return err
+ }
+
+ if len(args) < 2 {
+ return errors.New("Enter the destination team and at least one comamnd to move.")
+ }
+
+ team := getTeamFromTeamArg(a, args[0])
+ if team == nil {
+ return errors.New("Unable to find destination team '" + args[0] + "'")
+ }
+
+ commands := getCommandsFromCommandArgs(a, args[1:])
+ CommandPrintErrorln(commands)
+ for i, command := range commands {
+ if command == nil {
+ CommandPrintErrorln("Unable to find command '" + args[i+1] + "'")
+ continue
+ }
+ if err := moveCommand(a, team, command); err != nil {
+ CommandPrintErrorln("Unable to move command '" + command.Trigger + "' error: " + err.Error())
+ } else {
+ CommandPrettyPrintln("Moved command '" + command.Trigger + "'")
+ }
+ }
+
+ return nil
+}
+
+func moveCommand(a *app.App, team *model.Team, command *model.Command) *model.AppError {
+ if err := a.MoveCommand(team, command); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/cmd/platform/commandargs.go b/cmd/platform/commandargs.go
new file mode 100644
index 000000000..96e756815
--- /dev/null
+++ b/cmd/platform/commandargs.go
@@ -0,0 +1,63 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+package main
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/mattermost/mattermost-server/app"
+ "github.com/mattermost/mattermost-server/model"
+)
+
+const COMMAND_ARGS_SEPARATOR = ":"
+
+func getCommandsFromCommandArgs(a *app.App, commandArgs []string) []*model.Command {
+ commands := make([]*model.Command, 0, len(commandArgs))
+
+ for _, commandArg := range commandArgs {
+ command := getCommandFromCommandArg(a, commandArg)
+ commands = append(commands, command)
+ }
+
+ return commands
+}
+
+func parseCommandArg(commandArg string) (string, string) {
+ result := strings.SplitN(commandArg, COMMAND_ARGS_SEPARATOR, 2)
+
+ if len(result) == 1 {
+ return "", commandArg
+ }
+
+ return result[0], result[1]
+}
+
+func getCommandFromCommandArg(a *app.App, commandArg string) *model.Command {
+ teamArg, commandPart := parseCommandArg(commandArg)
+ if teamArg == "" && commandPart == "" {
+ return nil
+ }
+
+ var command *model.Command
+ if teamArg != "" {
+ team := getTeamFromTeamArg(a, teamArg)
+ if team == nil {
+ return nil
+ }
+
+ if result := <-a.Srv.Store.Command().GetByTrigger(team.Id, commandPart); result.Err == nil {
+ command = result.Data.(*model.Command)
+ } else {
+ fmt.Println(result.Err.Error())
+ }
+ }
+
+ if command == nil {
+ if result := <-a.Srv.Store.Command().Get(commandPart); result.Err == nil {
+ command = result.Data.(*model.Command)
+ }
+ }
+
+ return command
+}
diff --git a/cmd/platform/mattermost.go b/cmd/platform/mattermost.go
index 3c0add061..8e35dca05 100644
--- a/cmd/platform/mattermost.go
+++ b/cmd/platform/mattermost.go
@@ -40,7 +40,7 @@ func init() {
resetCmd.Flags().Bool("confirm", false, "Confirm you really want to delete everything and a DB backup has been performed.")
- rootCmd.AddCommand(serverCmd, versionCmd, userCmd, teamCmd, licenseCmd, importCmd, resetCmd, channelCmd, rolesCmd, testCmd, ldapCmd, configCmd, jobserverCmd)
+ rootCmd.AddCommand(serverCmd, versionCmd, userCmd, teamCmd, licenseCmd, importCmd, resetCmd, channelCmd, rolesCmd, testCmd, ldapCmd, configCmd, jobserverCmd, commandCmd)
}
var rootCmd = &cobra.Command{
diff --git a/i18n/en.json b/i18n/en.json
index 610186a8c..df30fd9d5 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -5580,6 +5580,10 @@
"translation": "We couldn't update the command"
},
{
+ "id": "store.sql_command.get_by_trigger.app_error",
+ "translation": "We couldn't get the command"
+ },
+ {
"id": "store.sql_command_webhooks.get.app_error",
"translation": "We couldn't get the webhook"
},
diff --git a/store/sqlstore/command_store.go b/store/sqlstore/command_store.go
index f156daab1..8284f889b 100644
--- a/store/sqlstore/command_store.go
+++ b/store/sqlstore/command_store.go
@@ -119,6 +119,27 @@ func (s SqlCommandStore) GetByTeam(teamId string) store.StoreChannel {
return storeChannel
}
+func (s SqlCommandStore) GetByTrigger(teamId string, trigger string) store.StoreChannel {
+ storeChannel := make(store.StoreChannel, 1)
+
+ go func() {
+ result := store.StoreResult{}
+
+ var command model.Command
+
+ if err := s.GetReplica().SelectOne(&command, "SELECT * FROM Commands WHERE TeamId = :TeamId AND `Trigger` = :Trigger AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Trigger": trigger}); err != nil {
+ result.Err = model.NewAppError("SqlCommandStore.GetByTrigger", "store.sql_command.get_by_trigger.app_error", nil, "teamId="+teamId+", trigger="+trigger+", err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ result.Data = &command
+
+ storeChannel <- result
+ close(storeChannel)
+ }()
+
+ return storeChannel
+}
+
func (s SqlCommandStore) Delete(commandId string, time int64) store.StoreChannel {
storeChannel := make(store.StoreChannel, 1)
diff --git a/store/sqlstore/command_store_test.go b/store/sqlstore/command_store_test.go
index 85eed64cc..407eae72e 100644
--- a/store/sqlstore/command_store_test.go
+++ b/store/sqlstore/command_store_test.go
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
)
func TestCommandStoreSave(t *testing.T) {
@@ -82,6 +83,41 @@ func TestCommandStoreGetByTeam(t *testing.T) {
}
}
+func TestCommandStoreGetByTrigger(t *testing.T) {
+ ss := Setup()
+
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger1"
+
+ o2 := &model.Command{}
+ o2.CreatorId = model.NewId()
+ o2.Method = model.COMMAND_METHOD_POST
+ o2.TeamId = model.NewId()
+ o2.URL = "http://nowhere.com/"
+ o2.Trigger = "trigger1"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+ o2 = (<-ss.Command().Save(o2)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().GetByTrigger(o1.TeamId, o1.Trigger); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Command).Id != o1.Id {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ store.Must(ss.Command().Delete(o1.Id, model.GetMillis()))
+
+ if result := <-ss.Command().GetByTrigger(o1.TeamId, o1.Trigger); result.Err == nil {
+ t.Fatal("no commands should have returned")
+ }
+}
+
func TestCommandStoreDelete(t *testing.T) {
ss := Setup()
diff --git a/store/store.go b/store/store.go
index 9694921c8..bc9aa8f1a 100644
--- a/store/store.go
+++ b/store/store.go
@@ -7,6 +7,7 @@ import (
"time"
l4g "github.com/alecthomas/log4go"
+
"github.com/mattermost/mattermost-server/model"
)
@@ -322,6 +323,7 @@ type CommandStore interface {
Save(webhook *model.Command) StoreChannel
Get(id string) StoreChannel
GetByTeam(teamId string) StoreChannel
+ GetByTrigger(teamId string, trigger string) StoreChannel
Delete(commandId string, time int64) StoreChannel
PermanentDeleteByTeam(teamId string) StoreChannel
PermanentDeleteByUser(userId string) StoreChannel