mattermost/server/cmd/mmctl/commands/webhook.go
Ben Schumacher 2c139a293b
Add missing parenthesis in mmctl webhook list (#28778)
* Add missing parenthesis in mmctl webhook list

* Use generics in StoreResult
2024-10-17 07:45:10 +02:00

481 lines
17 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"context"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/client"
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type StoreResult[T any] struct {
Data T
Err error
}
var WebhookCmd = &cobra.Command{
Use: "webhook",
Short: "Management of webhooks",
}
var ListWebhookCmd = &cobra.Command{
Use: "list",
Short: "List webhooks",
Long: "list all webhooks",
Example: " webhook list myteam",
RunE: withClient(listWebhookCmdF),
}
var ShowWebhookCmd = &cobra.Command{
Use: "show [webhookId]",
Short: "Show a webhook",
Long: "Show the webhook specified by [webhookId]",
Args: cobra.ExactArgs(1),
Example: " webhook show w16zb5tu3n1zkqo18goqry1je",
RunE: withClient(showWebhookCmdF),
}
var CreateIncomingWebhookCmd = &cobra.Command{
Use: "create-incoming",
Short: "Create incoming webhook",
Long: "create incoming webhook which allows external posting of messages to specific channel",
Example: " webhook create-incoming --channel [channelID] --user [userID] --display-name [displayName] --description [webhookDescription] --lock-to-channel --icon [iconURL]",
RunE: withClient(createIncomingWebhookCmdF),
}
var ModifyIncomingWebhookCmd = &cobra.Command{
Use: "modify-incoming",
Short: "Modify incoming webhook",
Long: "Modify existing incoming webhook by changing its title, description, channel or icon url",
Args: cobra.ExactArgs(1),
Example: " webhook modify-incoming [webhookID] --channel [channelID] --display-name [displayName] --description [webhookDescription] --lock-to-channel --icon [iconURL]",
RunE: withClient(modifyIncomingWebhookCmdF),
}
var CreateOutgoingWebhookCmd = &cobra.Command{
Use: "create-outgoing",
Short: "Create outgoing webhook",
Long: "create outgoing webhook which allows external posting of messages from a specific channel",
Example: ` webhook create-outgoing --team myteam --user myusername --display-name mywebhook --trigger-word "build" --trigger-word "test" --url http://localhost:8000/my-webhook-handler
webhook create-outgoing --team myteam --channel mychannel --user myusername --display-name mywebhook --description "My cool webhook" --trigger-when start --trigger-word build --trigger-word test --icon http://localhost:8000/my-slash-handler-bot-icon.png --url http://localhost:8000/my-webhook-handler --content-type "application/json"`,
RunE: withClient(createOutgoingWebhookCmdF),
}
var ModifyOutgoingWebhookCmd = &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",
Args: cobra.ExactArgs(1),
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: withClient(modifyOutgoingWebhookCmdF),
}
var DeleteWebhookCmd = &cobra.Command{
Use: "delete",
Short: "Delete webhooks",
Long: "Delete webhook with given id",
Args: cobra.ExactArgs(1),
Example: " webhook delete [webhookID]",
RunE: withClient(deleteWebhookCmdF),
}
func listWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
var teams []*model.Team
if len(args) < 1 {
var err error
// If no team is specified, list all teams
teams, err = getPages(func(page, numPerPage int, etag string) ([]*model.Team, *model.Response, error) {
return c.GetAllTeams(context.TODO(), etag, page, numPerPage)
}, DefaultPageSize)
if err != nil {
return err
}
} else {
teams = getTeamsFromTeamArgs(c, args)
}
for i, team := range teams {
if team == nil {
printer.PrintError("Unable to find team '" + args[i] + "'")
continue
}
incomingResult := make(chan StoreResult[[]*model.IncomingWebhook], 1)
go func() {
incomingHooks, err := getPages(func(page, numPerPage int, etag string) ([]*model.IncomingWebhook, *model.Response, error) {
return c.GetIncomingWebhooksForTeam(context.TODO(), team.Id, page, numPerPage, etag)
}, DefaultPageSize)
incomingResult <- StoreResult[[]*model.IncomingWebhook]{Data: incomingHooks, Err: err}
close(incomingResult)
}()
outgoingResult := make(chan StoreResult[[]*model.OutgoingWebhook], 1)
go func() {
outgoingHooks, err := getPages(func(page, numPerPage int, etag string) ([]*model.OutgoingWebhook, *model.Response, error) {
return c.GetOutgoingWebhooksForTeam(context.TODO(), team.Id, page, numPerPage, etag)
}, DefaultPageSize)
outgoingResult <- StoreResult[[]*model.OutgoingWebhook]{Data: outgoingHooks, Err: err}
close(outgoingResult)
}()
if result := <-incomingResult; result.Err == nil {
for _, hook := range result.Data {
printer.PrintT("Incoming:\t{{.DisplayName}} ({{.Id}})", hook)
}
} else {
printer.PrintError("Unable to list incoming webhooks for '" + team.Id + "': " + result.Err.Error())
}
if result := <-outgoingResult; result.Err == nil {
for _, hook := range result.Data {
printer.PrintT("Outgoing:\t {{.DisplayName}} ({{.Id}})", hook)
}
} else {
printer.PrintError("Unable to list outgoing webhooks for '" + team.Id + "': " + result.Err.Error())
}
}
return nil
}
func createIncomingWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
printer.SetSingle(true)
channelArg, _ := command.Flags().GetString("channel")
channel := getChannelFromChannelArg(c, channelArg)
if channel == nil {
return errors.New("Unable to find channel '" + channelArg + "'")
}
userArg, _ := command.Flags().GetString("user")
user := getUserFromUserArg(c, userArg)
if user == nil {
return errors.New("Unable to find user '" + userArg + "'")
}
displayName, _ := command.Flags().GetString("display-name")
description, _ := command.Flags().GetString("description")
iconURL, _ := command.Flags().GetString("icon")
channelLocked, _ := command.Flags().GetBool("lock-to-channel")
incomingWebhook := &model.IncomingWebhook{
ChannelId: channel.Id,
DisplayName: displayName,
Description: description,
IconURL: iconURL,
ChannelLocked: channelLocked,
Username: user.Username,
UserId: user.Id,
}
createdIncoming, _, err := c.CreateIncomingWebhook(context.TODO(), incomingWebhook)
if err != nil {
printer.PrintError("Unable to create webhook")
return err
}
tpl := `Id: {{.Id}}
Display Name: {{.DisplayName}}`
printer.PrintT(tpl, createdIncoming)
return nil
}
func modifyIncomingWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
printer.SetSingle(true)
webhookArg := args[0]
oldHook, _, err := c.GetIncomingWebhook(context.TODO(), webhookArg, "")
if err != nil {
return errors.New("Unable to find webhook '" + webhookArg + "'")
}
updatedHook := oldHook
channelArg, _ := command.Flags().GetString("channel")
if channelArg != "" {
channel := getChannelFromChannelArg(c, channelArg)
if channel == nil {
return errors.New("Unable to find channel '" + 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
}
iconURL, _ := command.Flags().GetString("icon")
if iconURL != "" {
updatedHook.IconURL = iconURL
}
channelLocked, _ := command.Flags().GetBool("lock-to-channel")
updatedHook.ChannelLocked = channelLocked
var newHook *model.IncomingWebhook
if newHook, _, err = c.UpdateIncomingWebhook(context.TODO(), updatedHook); err != nil {
printer.PrintError("Unable to modify incoming webhook")
return err
}
printer.PrintT("Webhook {{.Id}} successfully updated", newHook)
return nil
}
func createOutgoingWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
printer.SetSingle(true)
teamArg, _ := command.Flags().GetString("team")
team := getTeamFromTeamArg(c, teamArg)
if team == nil {
return errors.New("Unable to find team: " + teamArg)
}
userArg, _ := command.Flags().GetString("user")
user := getUserFromUserArg(c, userArg)
if user == nil {
return errors.New("Unable to find user: " + userArg)
}
displayName, _ := command.Flags().GetString("display-name")
triggerWords, _ := command.Flags().GetStringArray("trigger-word")
callbackURLs, _ := command.Flags().GetStringArray("url")
triggerWhenString, _ := command.Flags().GetString("trigger-when")
var triggerWhen int
switch triggerWhenString {
case "exact":
triggerWhen = 0
case "start":
triggerWhen = 1
default:
return errors.New("invalid trigger when parameter")
}
description, _ := command.Flags().GetString("description")
contentType, _ := command.Flags().GetString("content-type")
iconURL, _ := command.Flags().GetString("icon")
outgoingWebhook := &model.OutgoingWebhook{
CreatorId: user.Id,
Username: user.Username,
TeamId: team.Id,
TriggerWords: triggerWords,
TriggerWhen: triggerWhen,
CallbackURLs: callbackURLs,
DisplayName: displayName,
Description: description,
ContentType: contentType,
IconURL: iconURL,
}
channelArg, _ := command.Flags().GetString("channel")
if channelArg != "" {
channel := getChannelFromChannelArg(c, channelArg)
if channel != nil {
outgoingWebhook.ChannelId = channel.Id
}
}
createdOutgoing, _, err := c.CreateOutgoingWebhook(context.TODO(), outgoingWebhook)
if err != nil {
printer.PrintError("Unable to create outgoing webhook")
return err
}
tpl := `Id: {{.Id}}
Display Name: {{.DisplayName}}`
printer.PrintT(tpl, createdOutgoing)
return nil
}
func modifyOutgoingWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
printer.SetSingle(true)
webhookArg := args[0]
oldHook, _, err := c.GetOutgoingWebhook(context.TODO(), webhookArg)
if err != nil {
return errors.New("unable to find webhook '" + webhookArg + "'")
}
updatedHook := oldHook
channelArg, _ := command.Flags().GetString("channel")
if channelArg != "" {
channel := getChannelFromChannelArg(c, channelArg)
if channel == nil {
return errors.New("unable to find channel '" + 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
switch triggerWhenString {
case "exact":
triggerWhen = 0
case "start":
triggerWhen = 1
default:
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
}
var newHook *model.OutgoingWebhook
if newHook, _, err = c.UpdateOutgoingWebhook(context.TODO(), updatedHook); err != nil {
printer.PrintError("Unable to modify outgoing webhook")
return err
}
printer.PrintT("Webhook {{.Id}} successfully updated", newHook)
return nil
}
func deleteWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
printer.SetSingle(true)
webhookID := args[0]
if incomingWebhook, _, err := c.GetIncomingWebhook(context.TODO(), webhookID, ""); err == nil {
_, err := c.DeleteIncomingWebhook(context.TODO(), webhookID)
if err != nil {
printer.PrintError("Unable to delete webhook '" + webhookID + "'")
return err
}
printer.PrintT("Webhook {{.Id}} successfully deleted", incomingWebhook)
return nil
}
if outgoingWebhook, _, err := c.GetOutgoingWebhook(context.TODO(), webhookID); err == nil {
_, err := c.DeleteOutgoingWebhook(context.TODO(), webhookID)
if err != nil {
printer.PrintError("Unable to delete webhook '" + webhookID + "'")
return err
}
printer.PrintT("Webhook {{.Id}} successfully deleted", outgoingWebhook)
return nil
}
return errors.New("Webhook with id '" + webhookID + "' not found")
}
func showWebhookCmdF(c client.Client, command *cobra.Command, args []string) error {
printer.SetSingle(true)
webhookID := args[0]
if incomingWebhook, _, err := c.GetIncomingWebhook(context.TODO(), webhookID, ""); err == nil {
printer.Print(*incomingWebhook)
return nil
}
if outgoingWebhook, _, err := c.GetOutgoingWebhook(context.TODO(), webhookID); err == nil {
printer.Print(*outgoingWebhook)
return nil
}
return errors.New("Webhook with id '" + webhookID + "' not found")
}
func init() {
CreateIncomingWebhookCmd.Flags().String("channel", "", "Channel ID (required)")
_ = CreateIncomingWebhookCmd.MarkFlagRequired("channel")
CreateIncomingWebhookCmd.Flags().String("user", "", "User ID (required)")
_ = CreateIncomingWebhookCmd.MarkFlagRequired("user")
CreateIncomingWebhookCmd.Flags().String("display-name", "", "Incoming webhook display name")
CreateIncomingWebhookCmd.Flags().String("description", "", "Incoming webhook description")
CreateIncomingWebhookCmd.Flags().String("icon", "", "Icon URL")
CreateIncomingWebhookCmd.Flags().Bool("lock-to-channel", false, "Lock to channel")
ModifyIncomingWebhookCmd.Flags().String("channel", "", "Channel ID")
ModifyIncomingWebhookCmd.Flags().String("display-name", "", "Incoming webhook display name")
ModifyIncomingWebhookCmd.Flags().String("description", "", "Incoming webhook description")
ModifyIncomingWebhookCmd.Flags().String("icon", "", "Icon URL")
ModifyIncomingWebhookCmd.Flags().Bool("lock-to-channel", false, "Lock to channel")
CreateOutgoingWebhookCmd.Flags().String("team", "", "Team name or ID (required)")
_ = CreateOutgoingWebhookCmd.MarkFlagRequired("team")
CreateOutgoingWebhookCmd.Flags().String("channel", "", "Channel name or ID")
CreateOutgoingWebhookCmd.Flags().String("user", "", "User username, email, or ID (required)")
_ = CreateOutgoingWebhookCmd.MarkFlagRequired("user")
CreateOutgoingWebhookCmd.Flags().String("display-name", "", "Outgoing webhook display name (required)")
_ = CreateOutgoingWebhookCmd.MarkFlagRequired("display-name")
CreateOutgoingWebhookCmd.Flags().String("description", "", "Outgoing webhook description")
CreateOutgoingWebhookCmd.Flags().StringArray("trigger-word", []string{}, "Word to trigger webhook (required)")
_ = CreateOutgoingWebhookCmd.MarkFlagRequired("trigger-word")
CreateOutgoingWebhookCmd.Flags().String("trigger-when", "exact", "When to trigger webhook (exact: for first word matches a trigger word exactly, start: for first word starts with a trigger word)")
CreateOutgoingWebhookCmd.Flags().String("icon", "", "Icon URL")
CreateOutgoingWebhookCmd.Flags().StringArray("url", []string{}, "Callback URL (required)")
_ = CreateOutgoingWebhookCmd.MarkFlagRequired("url")
CreateOutgoingWebhookCmd.Flags().String("content-type", "", "Content-type")
ModifyOutgoingWebhookCmd.Flags().String("channel", "", "Channel name or ID")
ModifyOutgoingWebhookCmd.Flags().String("display-name", "", "Outgoing webhook display name")
ModifyOutgoingWebhookCmd.Flags().String("description", "", "Outgoing webhook description")
ModifyOutgoingWebhookCmd.Flags().StringArray("trigger-word", []string{}, "Word to trigger webhook")
ModifyOutgoingWebhookCmd.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)")
ModifyOutgoingWebhookCmd.Flags().String("icon", "", "Icon URL")
ModifyOutgoingWebhookCmd.Flags().StringArray("url", []string{}, "Callback URL")
ModifyOutgoingWebhookCmd.Flags().String("content-type", "", "Content-type")
WebhookCmd.AddCommand(
ListWebhookCmd,
CreateIncomingWebhookCmd,
ModifyIncomingWebhookCmd,
CreateOutgoingWebhookCmd,
ModifyOutgoingWebhookCmd,
DeleteWebhookCmd,
ShowWebhookCmd,
)
RootCmd.AddCommand(WebhookCmd)
}