Ctrl K
ComunidadGuías…

cli/usereditroles.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package cli

import (
	"fmt"
	"slices"
	"strings"

	"golang.org/x/xerrors"

	"github.com/coder/coder/v2/cli/cliui"
	"github.com/coder/coder/v2/codersdk"
	"github.com/coder/pretty"
	"github.com/coder/serpent"
)

func (r *RootCmd) userEditRoles() *serpent.Command {
	var givenRoles []string
	cmd := &serpent.Command{
		Use:   "edit-roles <username|user_id>",
		Short: "Edit a user's roles by username or id",
		Long: FormatExamples(
			Example{
				Description: "--roles replaces the user's full set of site roles; any role not listed is removed",
				Command:     "coder users edit-roles example_user --roles owner user-admin",
			},
		),
		Options: []serpent.Option{
			cliui.SkipPromptOption(),
			{
				Name:        "roles",
				Description: "Replaces the user's full set of site roles with this list. Any existing role not included here is removed.",
				Flag:        "roles",
				Value:       serpent.StringArrayOf(&givenRoles),
			},
		},
		Middleware: serpent.Chain(serpent.RequireNArgs(1)),
		Handler: func(inv *serpent.Invocation) error {
			client, err := r.InitClient(inv)
			if err != nil {
				return err
			}

			ctx := inv.Context()
			skipPrompt, _ := inv.ParsedFlags().GetBool("yes")

			user, err := client.User(ctx, inv.Args[0])
			if err != nil {
				return xerrors.Errorf("fetch user: %w", err)
			}

			userRoles, err := client.UserRoles(ctx, user.Username)
			if err != nil {
				return xerrors.Errorf("fetch user roles: %w", err)
			}
			siteRoles, err := client.ListSiteRoles(ctx)
			if err != nil {
				return xerrors.Errorf("fetch site roles: %w", err)
			}
			siteRoleNames := make([]string, 0, len(siteRoles))
			for _, role := range siteRoles {
				siteRoleNames = append(siteRoleNames, role.Name)
			}

			var selectedRoles []string
			if len(givenRoles) > 0 {
				// Make sure all of the given roles are valid site roles
				for _, givenRole := range givenRoles {
					if !slices.Contains(siteRoleNames, givenRole) {
						siteRolesPretty := strings.Join(siteRoleNames, ", ")
						return xerrors.Errorf("The role %s is not valid. Please use one or more of the following roles: %s\n", givenRole, siteRolesPretty)
					}
				}

				selectedRoles = givenRoles
			} else {
				if skipPrompt {
					return xerrors.Errorf("--roles is required when using --yes; the interactive role picker cannot be used non-interactively")
				}

				selectedRoles, err = cliui.MultiSelect(inv, cliui.MultiSelectOptions{
					Message:  "Select the roles you'd like to assign to the user",
					Options:  siteRoleNames,
					Defaults: userRoles.Roles,
				})
				if err != nil {
					return xerrors.Errorf("selecting roles for user: %w", err)
				}
			}

			added, removed := diffRoles(userRoles.Roles, selectedRoles)
			if len(added) == 0 && len(removed) == 0 {
				_, _ = fmt.Fprintf(inv.Stdout, "No role changes for %s.\n", user.Username)
				return nil
			}

			if len(added) > 0 {
				_, _ = fmt.Fprintf(inv.Stdout, "Roles to add: %s\n", strings.Join(added, ", "))
			}
			if len(removed) > 0 {
				_, _ = fmt.Fprintf(inv.Stdout, "Roles to remove: %s\n", pretty.Sprint(cliui.DefaultStyles.Code, strings.Join(removed, ", ")))
			}

			_, err = cliui.Prompt(inv, cliui.PromptOptions{
				Text:      fmt.Sprintf("This replaces the full set of site roles for %s. Continue?", user.Username),
				IsConfirm: true,
				Default:   cliui.ConfirmYes,
			})
			if err != nil {
				return err
			}

			_, err = client.UpdateUserRoles(ctx, user.Username, codersdk.UpdateRoles{
				Roles: selectedRoles,
			})
			if err != nil {
				return xerrors.Errorf("update user roles: %w", err)
			}

			return nil
		},
	}

	return cmd
}

func diffRoles(current, next []string) (added, removed []string) {
	for _, role := range next {
		if !slices.Contains(current, role) {
			added = append(added, role)
		}
	}
	for _, role := range current {
		if !slices.Contains(next, role) {
			removed = append(removed, role)
		}
	}
	return added, removed
}