Files
zeekay 8feb24ea1f One name for this fork, and it is ours
The server module named github.com/hanzoai/team/server/v8 — a path that
resolves to the retired workspace's repository, not this one — while
server/public still published github.com/mattermost/mattermost/server/public.
Both are github.com/hanzoteam/server/... now, which is where this code
actually lives.

That second half is what made the binary unbootable. Upstream's public path
stayed claimed by upstream, mattermost-plugin-ai imported it, and the build
linked public/model twice; public/plugin's gob.Register then ran twice under
one name and panicked at init, before main. Reverting the rename traded the
brand for a working binary. Rebranding the plugin alongside it needs no such
trade: the agents fork is github.com/hanzoteam/agents/v2 against our public
module, so no module named mattermost/mattermost is in the graph at all.

Measured: `go list -deps ./cmd/mattermost` names exactly one public/model, and
it is ours.
2026-08-28 23:35:36 -07:00

286 lines
8.1 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"context"
"fmt"
"github.com/hanzoteam/server/server/public/model"
"github.com/hanzoteam/server/server/v8/cmd/mmctl/client"
"github.com/hanzoteam/server/server/v8/cmd/mmctl/printer"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
var BotCmd = &cobra.Command{
Use: "bot",
Short: "Management of bots",
}
var CreateBotCmd = &cobra.Command{
Use: "create [username]",
Short: "Create bot",
Long: "Create bot.",
Example: ` bot create testbot`,
PreRun: disableLocalPrecheck,
RunE: withClient(botCreateCmdF),
Args: cobra.ExactArgs(1),
}
var UpdateBotCmd = &cobra.Command{
Use: "update [username]",
Short: "Update bot",
Long: "Update bot information.",
Example: ` bot update testbot --username newbotusername`,
RunE: withClient(botUpdateCmdF),
Args: cobra.ExactArgs(1),
}
var ListBotCmd = &cobra.Command{
Use: "list",
Short: "List bots",
Long: "List the bots users.",
Example: ` bot list`,
RunE: withClient(botListCmdF),
Args: cobra.NoArgs,
}
var DisableBotCmd = &cobra.Command{
Use: "disable [username]",
Short: "Disable bot",
Long: "Disable an enabled bot",
Example: ` bot disable testbot`,
RunE: withClient(botDisableCmdF),
Args: cobra.MinimumNArgs(1),
}
var EnableBotCmd = &cobra.Command{
Use: "enable [username]",
Short: "Enable bot",
Long: "Enable a disabled bot",
Example: ` bot enable testbot`,
RunE: withClient(botEnableCmdF),
Args: cobra.MinimumNArgs(1),
}
var AssignBotCmd = &cobra.Command{
Use: "assign [bot-username] [new-owner-username]",
Short: "Assign bot",
Long: "Assign the ownership of a bot to another user",
Example: ` bot assign testbot user2`,
RunE: withClient(botAssignCmdF),
Args: cobra.ExactArgs(2),
}
func init() {
CreateBotCmd.Flags().String("display-name", "", "Optional. The display name for the new bot.")
CreateBotCmd.Flags().String("description", "", "Optional. The description text for the new bot.")
CreateBotCmd.Flags().Bool("with-token", false, "Optional. Auto genreate access token for the bot.")
ListBotCmd.Flags().Bool("orphaned", false, "Optional. Only show orphaned bots.")
ListBotCmd.Flags().Bool("all", false, "Optional. Show all bots (including deleleted and orphaned).")
UpdateBotCmd.Flags().String("username", "", "Optional. The new username for the bot.")
UpdateBotCmd.Flags().String("display-name", "", "Optional. The new display name for the bot.")
UpdateBotCmd.Flags().String("description", "", "Optional. The new description text for the bot.")
BotCmd.AddCommand(
CreateBotCmd,
UpdateBotCmd,
ListBotCmd,
EnableBotCmd,
DisableBotCmd,
AssignBotCmd,
)
RootCmd.AddCommand(BotCmd)
}
func botCreateCmdF(c client.Client, cmd *cobra.Command, args []string) error {
username := args[0]
displayName, _ := cmd.Flags().GetString("display-name")
description, _ := cmd.Flags().GetString("description")
bot, _, err := c.CreateBot(context.TODO(), &model.Bot{
Username: username,
DisplayName: displayName,
Description: description,
})
if err != nil {
return errors.Errorf("could not create bot: %s", err)
}
printer.PrintT("Created bot {{.UserId}}", bot)
if withToken, _ := cmd.Flags().GetBool("with-token"); withToken {
return generateTokenForAUserCmdF(c, cmd, []string{args[0], "autogenerated"})
}
return nil
}
func botUpdateCmdF(c client.Client, cmd *cobra.Command, args []string) error {
if !cmd.Flags().Changed("username") && !cmd.Flags().Changed("display-name") && !cmd.Flags().Changed("description") {
return errors.New("at least one of --username, --display-name or --description must be set")
}
user := getUserFromUserArg(c, args[0])
if user == nil {
return errors.New("unable to find user '" + args[0] + "'")
}
patch := model.BotPatch{}
username, err := cmd.Flags().GetString("username")
if err == nil && cmd.Flags().Changed("username") {
patch.Username = &username
}
displayName, err := cmd.Flags().GetString("display-name")
if err == nil && cmd.Flags().Changed("display-name") {
patch.DisplayName = &displayName
}
description, err := cmd.Flags().GetString("description")
if err == nil && cmd.Flags().Changed("description") {
patch.Description = &description
}
bot, _, err := c.PatchBot(context.TODO(), user.Id, &patch)
if err != nil {
return errors.Errorf("could not update bot: %s", err)
}
printer.PrintT("Updated bot {{.UserId}} ({{.Username}})", bot)
return nil
}
func botListCmdF(c client.Client, cmd *cobra.Command, args []string) error {
orphaned, _ := cmd.Flags().GetBool("orphaned")
all, _ := cmd.Flags().GetBool("all")
page := 0
perPage := DefaultPageSize
tpl := `{{.UserId}}: {{.Username}}`
for {
var bots []*model.Bot
var err error
if all { //nolint:gocritic
bots, _, err = c.GetBotsIncludeDeleted(context.TODO(), page, perPage, "")
} else if orphaned {
bots, _, err = c.GetBotsOrphaned(context.TODO(), page, perPage, "")
} else {
bots, _, err = c.GetBots(context.TODO(), page, perPage, "")
}
if err != nil {
return errors.Wrap(err, "Failed to fetch bots")
}
userIds := []string{}
for _, bot := range bots {
userIds = append(userIds, bot.OwnerId)
}
users, _, err := c.GetUsersByIds(context.TODO(), userIds)
if err != nil {
return errors.Wrap(err, "Failed to fetch bots")
}
usersByID := map[string]*model.User{}
for _, user := range users {
usersByID[user.Id] = user
}
var ownerName string
var ownerDeleteAt int64
for _, bot := range bots {
if owner, ok := usersByID[bot.OwnerId]; ok {
ownerName = owner.Username
ownerDeleteAt = owner.DeleteAt
} else {
// not all bots have a userId in their ownerId field.
ownerName = bot.OwnerId
ownerDeleteAt = 0
}
tplExtraText := fmt.Sprintf("(Owned by %s, {{if ne .DeleteAt 0}}Disabled{{else}}Enabled{{end}}{{if ne %d 0}}, Orphaned{{end}})", ownerName, ownerDeleteAt)
printer.PrintT(tpl+tplExtraText, bot)
}
if len(bots) < perPage {
break
}
page++
}
return nil
}
func botEnableCmdF(c client.Client, cmd *cobra.Command, args []string) error {
users := getUsersFromUserArgs(c, args)
var result *multierror.Error
for i, user := range users {
if user == nil {
printer.PrintError(fmt.Sprintf("can't find user '%v'", args[i]))
result = multierror.Append(result, fmt.Errorf("can't find user %q", args[i]))
continue
}
bot, _, err := c.EnableBot(context.TODO(), user.Id)
if err != nil {
printer.PrintError(fmt.Sprintf("could not enable bot '%v'", args[i]))
result = multierror.Append(result, fmt.Errorf("could not enable bot %q: %w", args[i], err))
continue
}
printer.PrintT("Enabled bot {{.UserId}} ({{.Username}})", bot)
}
return result.ErrorOrNil()
}
func botDisableCmdF(c client.Client, cmd *cobra.Command, args []string) error {
users := getUsersFromUserArgs(c, args)
var result *multierror.Error
for i, user := range users {
if user == nil {
printer.PrintError(fmt.Sprintf("can't find user '%v'", args[i]))
result = multierror.Append(result, fmt.Errorf("can't find user %q", args[i]))
continue
}
bot, _, err := c.DisableBot(context.TODO(), user.Id)
if err != nil {
printer.PrintError(fmt.Sprintf("could not disable bot '%v'", args[i]))
result = multierror.Append(result, fmt.Errorf("could not disable bot %q: %w", args[i], err))
continue
}
printer.PrintT("Disabled bot {{.UserId}} ({{.Username}})", bot)
}
return result.ErrorOrNil()
}
func botAssignCmdF(c client.Client, cmd *cobra.Command, args []string) error {
botUser := getUserFromUserArg(c, args[0])
if botUser == nil {
return errors.New("unable to find user '" + args[0] + "'")
}
newOwnerUser := getUserFromUserArg(c, args[1])
if newOwnerUser == nil {
return errors.New("unable to find user '" + args[1] + "'")
}
newBot, _, err := c.AssignBot(context.TODO(), botUser.Id, newOwnerUser.Id)
if err != nil {
return errors.Errorf("can not assign bot '%s' to user '%s'", args[0], args[1])
}
printer.PrintT("The bot {{.UserId}} ({{.Username}}) now belongs to the user "+newOwnerUser.Username, newBot)
return nil
}