mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
feat: add cli command to remove organization member (#13619)
This commit is contained in:
@ -20,6 +20,7 @@ func (r *RootCmd) organizationMembers() *serpent.Command {
|
|||||||
r.listOrganizationMembers(),
|
r.listOrganizationMembers(),
|
||||||
r.assignOrganizationRoles(),
|
r.assignOrganizationRoles(),
|
||||||
r.addOrganizationMember(),
|
r.addOrganizationMember(),
|
||||||
|
r.removeOrganizationMember(),
|
||||||
},
|
},
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
return inv.Command.HelpHandler(inv)
|
return inv.Command.HelpHandler(inv)
|
||||||
@ -29,6 +30,37 @@ func (r *RootCmd) organizationMembers() *serpent.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RootCmd) removeOrganizationMember() *serpent.Command {
|
||||||
|
client := new(codersdk.Client)
|
||||||
|
|
||||||
|
cmd := &serpent.Command{
|
||||||
|
Use: "remove <username | user_id>",
|
||||||
|
Short: "Remove a new member to the current organization",
|
||||||
|
Middleware: serpent.Chain(
|
||||||
|
r.InitClient(client),
|
||||||
|
serpent.RequireNArgs(1),
|
||||||
|
),
|
||||||
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
|
ctx := inv.Context()
|
||||||
|
organization, err := CurrentOrganization(r, 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() *serpent.Command {
|
func (r *RootCmd) addOrganizationMember() *serpent.Command {
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
|
||||||
@ -49,10 +81,10 @@ func (r *RootCmd) addOrganizationMember() *serpent.Command {
|
|||||||
|
|
||||||
_, err = client.PostOrganizationMember(ctx, organization.ID, user)
|
_, err = client.PostOrganizationMember(ctx, organization.ID, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("could not add member to organization: %w", err)
|
return xerrors.Errorf("could not add member to organization %q: %w", organization.HumanName(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, "Organization member added")
|
_, _ = fmt.Fprintf(inv.Stdout, "Organization member added to %q\n", organization.HumanName())
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -72,3 +72,49 @@ func TestAddOrganizationMembers(t *testing.T) {
|
|||||||
require.Len(t, members, 2)
|
require.Len(t, members, 2)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRemoveOrganizationMembers(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("OK", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ownerClient := coderdtest.New(t, &coderdtest.Options{})
|
||||||
|
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
||||||
|
orgAdminClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAdmin(owner.OrganizationID))
|
||||||
|
_, user := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
|
||||||
|
|
||||||
|
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||||
|
|
||||||
|
inv, root := clitest.New(t, "organization", "members", "remove", "--organization", owner.OrganizationID.String(), user.Username)
|
||||||
|
clitest.SetupConfig(t, orgAdminClient, root)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
inv.Stdout = buf
|
||||||
|
err := inv.WithContext(ctx).Run()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
members, err := orgAdminClient.OrganizationMembers(ctx, owner.OrganizationID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, members, 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UserNotExists", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ownerClient := coderdtest.New(t, &coderdtest.Options{})
|
||||||
|
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
||||||
|
orgAdminClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAdmin(owner.OrganizationID))
|
||||||
|
|
||||||
|
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||||
|
|
||||||
|
inv, root := clitest.New(t, "organization", "members", "remove", "--organization", owner.OrganizationID.String(), "random_name")
|
||||||
|
clitest.SetupConfig(t, orgAdminClient, root)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
inv.Stdout = buf
|
||||||
|
err := inv.WithContext(ctx).Run()
|
||||||
|
require.ErrorContains(t, err, "must be an existing uuid or username")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -50,6 +50,13 @@ type Organization struct {
|
|||||||
Icon string `table:"icon" json:"icon"`
|
Icon string `table:"icon" json:"icon"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o Organization) HumanName() string {
|
||||||
|
if o.DisplayName == "" {
|
||||||
|
return o.Name
|
||||||
|
}
|
||||||
|
return o.DisplayName
|
||||||
|
}
|
||||||
|
|
||||||
type OrganizationMember struct {
|
type OrganizationMember struct {
|
||||||
UserID uuid.UUID `table:"user id" json:"user_id" format:"uuid"`
|
UserID uuid.UUID `table:"user id" json:"user_id" format:"uuid"`
|
||||||
OrganizationID uuid.UUID `table:"organization id" json:"organization_id" format:"uuid"`
|
OrganizationID uuid.UUID `table:"organization id" json:"organization_id" format:"uuid"`
|
||||||
|
Reference in New Issue
Block a user