[MM 12373] Create CLI command "webhook modify-outgoing" (#10028)
* Add test for modifying outgoing webhook * Add command to modify an outgoing webhook * Use updated test helper * Use errors.Wrap * Lower case error strings and use fmt.Errorf * Clone webhook into updatedHook * Rename error variables
Этот коммит содержится в:
коммит произвёл
Jesse Hallam
родитель
ca4dcf4404
Коммит
6b59ab4ee8
@@ -5,6 +5,7 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -49,6 +50,14 @@ var WebhookCreateOutgoingCmd = &cobra.Command{
|
|||||||
RunE: createOutgoingWebhookCmdF,
|
RunE: createOutgoingWebhookCmdF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var WebhookModifyOutgoingCmd = &cobra.Command{
|
||||||
|
Use: "modify-outgoing",
|
||||||
|
Short: "Modify outgoing webhook",
|
||||||
|
Long: "Modify existing outgoing webhook by changing its title, description, channel, icon, url, content-type, and triggers",
|
||||||
|
Example: ` webhook modify-outgoing [webhookId] --channel [channelId] --display-name [displayName] --description "New webhook description" --icon http://localhost:8000/my-slash-handler-bot-icon.png --url http://localhost:8000/my-webhook-handler --content-type "application/json" --trigger-word test --trigger-when start`,
|
||||||
|
RunE: modifyOutgoingWebhookCmdF,
|
||||||
|
}
|
||||||
|
|
||||||
var WebhookDeleteCmd = &cobra.Command{
|
var WebhookDeleteCmd = &cobra.Command{
|
||||||
Use: "delete",
|
Use: "delete",
|
||||||
Short: "Delete webhooks",
|
Short: "Delete webhooks",
|
||||||
@@ -285,6 +294,90 @@ func createOutgoingWebhookCmdF(command *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func modifyOutgoingWebhookCmdF(command *cobra.Command, args []string) error {
|
||||||
|
app, err := InitDBCommandContextCobra(command)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer app.Shutdown()
|
||||||
|
|
||||||
|
if len(args) < 1 {
|
||||||
|
return errors.New("WebhookID is not specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookArg := args[0]
|
||||||
|
oldHook, appErr := app.GetOutgoingWebhook(webhookArg)
|
||||||
|
if appErr != nil {
|
||||||
|
return fmt.Errorf("unable to find webhook '%s'", webhookArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedHook := model.OutgoingWebhookFromJson(strings.NewReader(oldHook.ToJson()))
|
||||||
|
|
||||||
|
channelArg, _ := command.Flags().GetString("channel")
|
||||||
|
if channelArg != "" {
|
||||||
|
channel := getChannelFromChannelArg(app, channelArg)
|
||||||
|
if channel == nil {
|
||||||
|
return fmt.Errorf("unable to find channel '%s'", channelArg)
|
||||||
|
}
|
||||||
|
updatedHook.ChannelId = channel.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
displayName, _ := command.Flags().GetString("display-name")
|
||||||
|
if displayName != "" {
|
||||||
|
updatedHook.DisplayName = displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
description, _ := command.Flags().GetString("description")
|
||||||
|
if description != "" {
|
||||||
|
updatedHook.Description = description
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerWords, err := command.Flags().GetStringArray("trigger-word")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "invalid trigger-word parameter")
|
||||||
|
}
|
||||||
|
if len(triggerWords) > 0 {
|
||||||
|
updatedHook.TriggerWords = triggerWords
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerWhenString, _ := command.Flags().GetString("trigger-when")
|
||||||
|
if triggerWhenString != "" {
|
||||||
|
var triggerWhen int
|
||||||
|
if triggerWhenString == "exact" {
|
||||||
|
triggerWhen = 0
|
||||||
|
} else if triggerWhenString == "start" {
|
||||||
|
triggerWhen = 1
|
||||||
|
} else {
|
||||||
|
return errors.New("invalid trigger-when parameter")
|
||||||
|
}
|
||||||
|
updatedHook.TriggerWhen = triggerWhen
|
||||||
|
}
|
||||||
|
|
||||||
|
iconURL, _ := command.Flags().GetString("icon")
|
||||||
|
if iconURL != "" {
|
||||||
|
updatedHook.IconURL = iconURL
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType, _ := command.Flags().GetString("content-type")
|
||||||
|
if contentType != "" {
|
||||||
|
updatedHook.ContentType = contentType
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackURLs, err := command.Flags().GetStringArray("url")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "invalid URL parameter")
|
||||||
|
}
|
||||||
|
if len(callbackURLs) > 0 {
|
||||||
|
updatedHook.CallbackURLs = callbackURLs
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, appErr := app.UpdateOutgoingWebhook(oldHook, updatedHook); appErr != nil {
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func deleteWebhookCmdF(command *cobra.Command, args []string) error {
|
func deleteWebhookCmdF(command *cobra.Command, args []string) error {
|
||||||
app, err := InitDBCommandContextCobra(command)
|
app, err := InitDBCommandContextCobra(command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -332,11 +425,21 @@ func init() {
|
|||||||
WebhookCreateOutgoingCmd.Flags().StringArray("url", []string{}, "Callback URL (required)")
|
WebhookCreateOutgoingCmd.Flags().StringArray("url", []string{}, "Callback URL (required)")
|
||||||
WebhookCreateOutgoingCmd.Flags().String("content-type", "", "Content-type")
|
WebhookCreateOutgoingCmd.Flags().String("content-type", "", "Content-type")
|
||||||
|
|
||||||
|
WebhookModifyOutgoingCmd.Flags().String("channel", "", "Channel name or ID")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().String("display-name", "", "Outgoing webhook display name")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().String("description", "", "Outgoing webhook description")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().StringArray("trigger-word", []string{}, "Word to trigger webhook")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().String("trigger-when", "", "When to trigger webhook (exact: for first word matches a trigger word exactly, start: for first word starts with a trigger word)")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().String("icon", "", "Icon URL")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().StringArray("url", []string{}, "Callback URL")
|
||||||
|
WebhookModifyOutgoingCmd.Flags().String("content-type", "", "Content-type")
|
||||||
|
|
||||||
WebhookCmd.AddCommand(
|
WebhookCmd.AddCommand(
|
||||||
WebhookListCmd,
|
WebhookListCmd,
|
||||||
WebhookCreateIncomingCmd,
|
WebhookCreateIncomingCmd,
|
||||||
WebhookModifyIncomingCmd,
|
WebhookModifyIncomingCmd,
|
||||||
WebhookCreateOutgoingCmd,
|
WebhookCreateOutgoingCmd,
|
||||||
|
WebhookModifyOutgoingCmd,
|
||||||
WebhookDeleteCmd,
|
WebhookDeleteCmd,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -245,6 +245,105 @@ func TestCreateOutgoingWebhook(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestModifyOutgoingWebhook(t *testing.T) {
|
||||||
|
th := Setup().InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
config := th.Config()
|
||||||
|
config.ServiceSettings.EnableOutgoingWebhooks = true
|
||||||
|
th.SetConfig(config)
|
||||||
|
|
||||||
|
defaultRolePermissions := th.SaveDefaultRolePermissions()
|
||||||
|
defer func() {
|
||||||
|
th.RestoreDefaultRolePermissions(defaultRolePermissions)
|
||||||
|
}()
|
||||||
|
th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
|
||||||
|
th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
|
||||||
|
|
||||||
|
description := "myhookoutdesc"
|
||||||
|
displayName := "myhookoutname"
|
||||||
|
triggerWords := model.StringArray{"myhookoutword1"}
|
||||||
|
triggerWhen := 0
|
||||||
|
callbackURLs := model.StringArray{"http://myhookouturl1"}
|
||||||
|
iconURL := "myhookicon1"
|
||||||
|
contentType := "myhookcontent1"
|
||||||
|
|
||||||
|
outgoingWebhook := &model.OutgoingWebhook{
|
||||||
|
CreatorId: th.BasicUser.Id,
|
||||||
|
Username: th.BasicUser.Username,
|
||||||
|
TeamId: th.BasicTeam.Id,
|
||||||
|
ChannelId: th.BasicChannel.Id,
|
||||||
|
DisplayName: displayName,
|
||||||
|
Description: description,
|
||||||
|
TriggerWords: triggerWords,
|
||||||
|
TriggerWhen: triggerWhen,
|
||||||
|
CallbackURLs: callbackURLs,
|
||||||
|
IconURL: iconURL,
|
||||||
|
ContentType: contentType,
|
||||||
|
}
|
||||||
|
|
||||||
|
oldHook, err := th.App.CreateOutgoingWebhook(outgoingWebhook)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("unable to create outgoing webhooks: " + err.Error())
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
th.App.DeleteOutgoingWebhook(oldHook.Id)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// should fail because you need to specify valid outgoing webhook
|
||||||
|
require.Error(t, th.RunCommand(t, "webhook", "modify-outgoing", "doesnotexist"))
|
||||||
|
// should fail because you need to specify valid channel
|
||||||
|
require.Error(t, th.RunCommand(t, "webhook", "modify-outgoing", oldHook.Id, "--channel", th.BasicTeam.Name+":doesnotexist"))
|
||||||
|
// should fail because you need to specify valid trigger when
|
||||||
|
require.Error(t, th.RunCommand(t, "webhook", "modify-outgoing", oldHook.Id, "--channel", th.BasicTeam.Name+th.BasicChannel.Id, "--trigger-when", "invalid"))
|
||||||
|
// should fail because you need to specify a valid callback URL
|
||||||
|
require.Error(t, th.RunCommand(t, "webhook", "modify-outgoing", oldHook.Id, "--channel", th.BasicTeam.Name+th.BasicChannel.Id, "--callback-url", "invalid"))
|
||||||
|
|
||||||
|
modifiedChannelID := th.BasicChannel2.Id
|
||||||
|
modifiedDisplayName := "myhookoutname2"
|
||||||
|
modifiedDescription := "myhookoutdesc2"
|
||||||
|
modifiedTriggerWords := model.StringArray{"myhookoutword2A", "myhookoutword2B"}
|
||||||
|
modifiedTriggerWhen := "start"
|
||||||
|
modifiedIconURL := "myhookouticon2"
|
||||||
|
modifiedContentType := "myhookcontent2"
|
||||||
|
modifiedCallbackURLs := model.StringArray{"http://myhookouturl2A", "http://myhookouturl2B"}
|
||||||
|
|
||||||
|
th.CheckCommand(t, "webhook", "modify-outgoing", oldHook.Id,
|
||||||
|
"--channel", modifiedChannelID,
|
||||||
|
"--display-name", modifiedDisplayName,
|
||||||
|
"--description", modifiedDescription,
|
||||||
|
"--trigger-word", modifiedTriggerWords[0],
|
||||||
|
"--trigger-word", modifiedTriggerWords[1],
|
||||||
|
"--trigger-when", modifiedTriggerWhen,
|
||||||
|
"--icon", modifiedIconURL,
|
||||||
|
"--content-type", modifiedContentType,
|
||||||
|
"--url", modifiedCallbackURLs[0],
|
||||||
|
"--url", modifiedCallbackURLs[1],
|
||||||
|
)
|
||||||
|
|
||||||
|
modifiedHook, err := th.App.GetOutgoingWebhook(oldHook.Id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("unable to retrieve modified outgoing webhook")
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFailed := modifiedHook.ChannelId != modifiedChannelID ||
|
||||||
|
modifiedHook.DisplayName != modifiedDisplayName ||
|
||||||
|
modifiedHook.Description != modifiedDescription ||
|
||||||
|
len(modifiedHook.TriggerWords) != len(modifiedTriggerWords) ||
|
||||||
|
modifiedHook.TriggerWords[0] != modifiedTriggerWords[0] ||
|
||||||
|
modifiedHook.TriggerWords[1] != modifiedTriggerWords[1] ||
|
||||||
|
modifiedHook.TriggerWhen != 1 ||
|
||||||
|
modifiedHook.IconURL != modifiedIconURL ||
|
||||||
|
modifiedHook.ContentType != modifiedContentType ||
|
||||||
|
len(modifiedHook.CallbackURLs) != len(modifiedCallbackURLs) ||
|
||||||
|
modifiedHook.CallbackURLs[0] != modifiedCallbackURLs[0] ||
|
||||||
|
modifiedHook.CallbackURLs[1] != modifiedCallbackURLs[1]
|
||||||
|
|
||||||
|
if updateFailed {
|
||||||
|
t.Fatal("Failed to update outgoing webhook")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeleteWebhooks(t *testing.T) {
|
func TestDeleteWebhooks(t *testing.T) {
|
||||||
th := Setup().InitBasic()
|
th := Setup().InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user