package cli import ( "fmt" "strings" "golang.org/x/xerrors" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" "github.com/coder/serpent" ) func (r *RootCmd) organizationMembers(orgContext *OrganizationContext) *serpent.Command { cmd := &serpent.Command{ Use: "members", Aliases: []string{"member"}, Short: "Manage organization members", Children: []*serpent.Command{ r.listOrganizationMembers(orgContext), r.assignOrganizationRoles(orgContext), r.addOrganizationMember(orgContext), r.removeOrganizationMember(orgContext), }, Handler: func(inv *serpent.Invocation) error { return inv.Command.HelpHandler(inv) }, } return cmd } func (r *RootCmd) removeOrganizationMember(orgContext *OrganizationContext) *serpent.Command { cmd := &serpent.Command{ Use: "remove ", Short: "Remove a new member to the current organization", 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() organization, err := orgContext.Selected(inv, client) if err != nil { return err } user := inv.Args[0] err = client.DeleteOrganizationMember(ctx, organization.ID, user) if err != nil { return xerrors.Errorf("could not remove member from organization %q: %w", organization.HumanName(), err) } _, _ = fmt.Fprintf(inv.Stdout, "Organization member removed from %q\n", organization.HumanName()) return nil }, } return cmd } func (r *RootCmd) addOrganizationMember(orgContext *OrganizationContext) *serpent.Command { cmd := &serpent.Command{ Use: "add ", Short: "Add a new member to the current organization", 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() organization, err := orgContext.Selected(inv, client) if err != nil { return err } user := inv.Args[0] _, err = client.PostOrganizationMember(ctx, organization.ID, user) if err != nil { return xerrors.Errorf("could not add member to organization %q: %w", organization.HumanName(), err) } _, _ = fmt.Fprintf(inv.Stdout, "Organization member added to %q\n", organization.HumanName()) return nil }, } return cmd } func (r *RootCmd) assignOrganizationRoles(orgContext *OrganizationContext) *serpent.Command { cmd := &serpent.Command{ Use: "edit-roles [roles...]", Aliases: []string{"edit-role"}, Short: "Edit organization member's roles", Handler: func(inv *serpent.Invocation) error { client, err := r.InitClient(inv) if err != nil { return err } ctx := inv.Context() organization, err := orgContext.Selected(inv, client) if err != nil { return err } if len(inv.Args) < 1 { return xerrors.Errorf("user_id or username is required as the first argument") } userIdentifier := inv.Args[0] roles := inv.Args[1:] member, err := client.UpdateOrganizationMemberRoles(ctx, organization.ID, userIdentifier, codersdk.UpdateRoles{ Roles: roles, }) if err != nil { return xerrors.Errorf("update member roles: %w", err) } updatedTo := make([]string, 0) for _, role := range member.Roles { updatedTo = append(updatedTo, role.String()) } _, _ = fmt.Fprintf(inv.Stdout, "Member roles updated to [%s]\n", strings.Join(updatedTo, ", ")) return nil }, } return cmd } func (r *RootCmd) listOrganizationMembers(orgContext *OrganizationContext) *serpent.Command { formatter := cliui.NewOutputFormatter( cliui.TableFormat([]codersdk.OrganizationMemberWithUserData{}, []string{"username", "organization roles"}), cliui.JSONFormat(), ) cmd := &serpent.Command{ Use: "list", Short: "List all organization members", Middleware: serpent.Chain( serpent.RequireNArgs(0), ), Handler: func(inv *serpent.Invocation) error { client, err := r.InitClient(inv) if err != nil { return err } ctx := inv.Context() organization, err := orgContext.Selected(inv, client) if err != nil { return err } res, err := client.OrganizationMembers(ctx, organization.ID) if err != nil { return xerrors.Errorf("fetch members: %w", err) } out, err := formatter.Format(inv.Context(), res) if err != nil { return err } if out == "" { cliui.Infof(inv.Stderr, "No organization members found.") return nil } _, err = fmt.Fprintln(inv.Stdout, out) return err }, } formatter.AttachOptions(&cmd.Options) return cmd }