mattermost-community-enterp.../cmd/mmctl/commands/team.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

379 lines
11 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"context"
"errors"
"fmt"
"sort"
"github.com/hashicorp/go-multierror"
"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/spf13/cobra"
)
var TeamCmd = &cobra.Command{
Use: "team",
Short: "Management of teams",
}
var TeamCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a team",
Long: `Create a team.`,
Example: ` team create --name mynewteam --display-name "My New Team"
team create --name private --display-name "My New Private Team" --private`,
RunE: withClient(createTeamCmdF),
}
var DeleteTeamsCmd = &cobra.Command{
Use: "delete [teams]",
Short: "Delete teams",
Long: `Permanently delete some teams.
Permanently deletes a team along with all related information including posts from the database.`,
Example: " team delete myteam",
Args: cobra.MinimumNArgs(1),
RunE: withClient(deleteTeamsCmdF),
}
var ArchiveTeamsCmd = &cobra.Command{
Use: "archive [teams]",
Short: "Archive teams",
Long: `Archive some teams.
Archives a team along with all related information including posts from the database.`,
Example: " team archive myteam",
Args: cobra.MinimumNArgs(1),
RunE: withClient(archiveTeamsCmdF),
}
var RestoreTeamsCmd = &cobra.Command{
Use: "restore [teams]",
Short: "Restore teams",
Long: "Restores archived teams.",
Example: " team restore myteam",
Args: cobra.MinimumNArgs(1),
RunE: withClient(restoreTeamsCmdF),
}
var ListTeamsCmd = &cobra.Command{
Use: "list",
Short: "List all teams",
Long: `List all teams on the server.`,
Example: " team list",
RunE: withClient(listTeamsCmdF),
}
var SearchTeamCmd = &cobra.Command{
Use: "search [teams]",
Short: "Search for teams",
Long: "Search for teams based on name",
Example: " team search team1",
Args: cobra.MinimumNArgs(1),
RunE: withClient(searchTeamCmdF),
}
// RenameTeamCmd is the command to rename team along with its display name
var RenameTeamCmd = &cobra.Command{
Use: "rename [team]",
Short: "Rename team",
Long: "Rename an existing team",
Example: " team rename old-team --display-name 'New Display Name'",
Args: cobra.ExactArgs(1),
RunE: withClient(renameTeamCmdF),
}
var ModifyTeamsCmd = &cobra.Command{
Use: "modify [teams] [flag]",
Short: "Modify teams",
Long: "Modify teams' privacy setting to public or private",
Example: " team modify myteam --private",
Args: cobra.MinimumNArgs(1),
RunE: withClient(modifyTeamsCmdF),
}
func init() {
TeamCreateCmd.Flags().String("name", "", "Team Name")
TeamCreateCmd.Flags().String("display-name", "", "Team Display Name")
TeamCreateCmd.Flags().Bool("private", false, "Create a private team.")
TeamCreateCmd.Flags().String("email", "", "Administrator Email (anyone with this email is automatically a team admin)")
DeleteTeamsCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the team and a DB backup has been performed.")
ArchiveTeamsCmd.Flags().Bool("confirm", false, "Confirm you really want to archive the team and a DB backup has been performed.")
ModifyTeamsCmd.Flags().Bool("private", false, "Modify team to be private.")
ModifyTeamsCmd.Flags().Bool("public", false, "Modify team to be public.")
// Add flag declaration for RenameTeam
RenameTeamCmd.Flags().String("display-name", "", "Team Display Name")
_ = RenameTeamCmd.MarkFlagRequired("display-name")
TeamCmd.AddCommand(
TeamCreateCmd,
DeleteTeamsCmd,
ArchiveTeamsCmd,
RestoreTeamsCmd,
ListTeamsCmd,
SearchTeamCmd,
RenameTeamCmd,
ModifyTeamsCmd,
)
RootCmd.AddCommand(TeamCmd)
}
func createTeamCmdF(c client.Client, cmd *cobra.Command, args []string) error {
printer.SetSingle(true)
name, errn := cmd.Flags().GetString("name")
if errn != nil || name == "" {
return errors.New("name is required")
}
displayname, errdn := cmd.Flags().GetString("display-name")
if errdn != nil || displayname == "" {
return errors.New("display-name is required")
}
email, _ := cmd.Flags().GetString("email")
useprivate, _ := cmd.Flags().GetBool("private")
teamType := model.TeamOpen
allowOpenInvite := true
if useprivate {
teamType = model.TeamInvite
allowOpenInvite = false
}
team := &model.Team{
Name: name,
DisplayName: displayname,
Email: email,
Type: teamType,
AllowOpenInvite: allowOpenInvite,
}
newTeam, _, err := c.CreateTeam(context.TODO(), team)
if err != nil {
return errors.New("Team creation failed: " + err.Error())
}
printer.PrintT("New team {{.Name}} successfully created", newTeam)
return nil
}
func deleteTeam(c client.Client, team *model.Team) (*model.Response, error) {
return c.PermanentDeleteTeam(context.TODO(), team.Id)
}
func archiveTeamsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
var result *multierror.Error
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag {
if err := getConfirmation("Are you sure you want to archive the specified teams?", true); err != nil {
return err
}
}
teams := getTeamsFromTeamArgs(c, args)
for i, team := range teams {
if team == nil {
printer.PrintError("Unable to find team '" + args[i] + "'")
result = multierror.Append(result, errors.New("Unable to find team '"+args[i]+"'"))
continue
}
if _, err := c.SoftDeleteTeam(context.TODO(), team.Id); err != nil {
printer.PrintError("Unable to archive team '" + team.Name + "' error: " + err.Error())
result = multierror.Append(result, errors.New("Unable to archive team '"+team.Name+"' error: "+err.Error()))
} else {
printer.PrintT("Archived team '{{.Name}}'", team)
}
}
return result.ErrorOrNil()
}
func listTeamsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
page := 0
for {
teams, _, err := c.GetAllTeams(context.TODO(), "", page, DefaultPageSize)
if err != nil {
return err
}
for _, team := range teams {
if team.DeleteAt > 0 {
printer.PrintT("{{.Name}} (archived)", team)
} else {
printer.PrintT("{{.Name}}", team)
}
}
if len(teams) < DefaultPageSize {
break
}
page++
}
return nil
}
func searchTeamCmdF(c client.Client, cmd *cobra.Command, args []string) error {
var teams []*model.Team
for _, searchTerm := range args {
foundTeams, _, err := c.SearchTeams(context.TODO(), &model.TeamSearch{Term: searchTerm})
if err != nil {
return err
}
if len(foundTeams) == 0 {
printer.PrintError("Unable to find team '" + searchTerm + "'")
continue
}
teams = append(teams, foundTeams...)
}
sortedTeams := removeDuplicatesAndSortTeams(teams)
for _, team := range sortedTeams {
printer.PrintT("{{.Name}}: {{.DisplayName}} ({{.Id}})", team)
}
return nil
}
// Removes duplicates and sorts teams by name
func removeDuplicatesAndSortTeams(teams []*model.Team) []*model.Team {
keys := make(map[string]bool)
result := []*model.Team{}
for _, team := range teams {
if _, value := keys[team.Name]; !value {
keys[team.Name] = true
result = append(result, team)
}
}
sort.Slice(result, func(i, j int) bool {
return result[i].Name < result[j].Name
})
return result
}
func renameTeamCmdF(c client.Client, cmd *cobra.Command, args []string) error {
oldTeamName := args[0]
newDisplayName, _ := cmd.Flags().GetString("display-name")
if newDisplayName == "" {
return errors.New("display-name is required")
}
team := getTeamFromTeamArg(c, oldTeamName)
if team == nil {
return errors.New("Unable to find team '" + oldTeamName + "', to see the all teams try 'team list' command")
}
team.DisplayName = newDisplayName
// Using UpdateTeam API Method to rename team
_, _, err := c.UpdateTeam(context.TODO(), team)
if err != nil {
return errors.New("Cannot rename team '" + oldTeamName + "', error : " + err.Error())
}
printer.Print("'" + oldTeamName + "' team renamed")
return nil
}
func deleteTeamsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag {
if err := getConfirmation("Are you sure you want to delete the teams specified? All data will be permanently deleted?", true); err != nil {
return err
}
}
var result *multierror.Error
teams := getTeamsFromTeamArgs(c, args)
for i, team := range teams {
if team == nil {
printer.PrintError("Unable to find team '" + args[i] + "'")
result = multierror.Append(result, fmt.Errorf("unable to find team %s", args[i]))
continue
}
if _, err := deleteTeam(c, team); err != nil {
printer.PrintError("Unable to delete team '" + team.Name + "' error: " + err.Error())
result = multierror.Append(result, fmt.Errorf("unable to delete team %s error: %w", team.Name, err))
} else {
printer.PrintT("Deleted team '{{.Name}}'", team)
}
}
return result.ErrorOrNil()
}
func modifyTeamsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
private, _ := cmd.Flags().GetBool("private")
public, _ := cmd.Flags().GetBool("public")
if (!private && !public) || (private && public) {
return errors.New("must specify one of --private or --public")
}
var errs *multierror.Error
// I = invite only (private)
// O = open (public)
privacy := model.TeamInvite
if public {
privacy = model.TeamOpen
}
teams := getTeamsFromTeamArgs(c, args)
for i, team := range teams {
if team == nil {
errs = multierror.Append(errs, errors.New("Unable to find team '"+args[i]+"'"))
continue
}
updatedTeam, _, err := c.UpdateTeamPrivacy(context.TODO(), team.Id, privacy)
if err != nil {
errs = multierror.Append(errs, errors.New("Unable to modify team '"+team.Name+"' error: "+err.Error()))
continue
}
printer.PrintT("Modified team '{{.Name}}'", updatedTeam)
}
for _, err := range errs.WrappedErrors() {
printer.PrintError(err.Error())
}
return errs.ErrorOrNil()
}
func restoreTeamsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
teams := getTeamsFromTeamArgs(c, args)
var result *multierror.Error
for i, team := range teams {
if team == nil {
result = multierror.Append(result, fmt.Errorf("unable to find team '%s'", args[i]))
printer.PrintError("Unable to find team '" + args[i] + "'")
continue
}
if rteam, _, err := c.RestoreTeam(context.TODO(), team.Id); err != nil {
result = multierror.Append(result, fmt.Errorf("unable to restore team '%s' error: %w", team.Name, err))
printer.PrintError("Unable to restore team '" + team.Name + "' error: " + err.Error())
} else {
printer.PrintT("Restored team '{{.Name}}'", rteam)
}
}
return result.ErrorOrNil()
}