From 4e49cc4b53f9e896d8f8b35ce985d3bf714bfedc Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 20 Jun 2024 16:41:46 -0500 Subject: [PATCH] feat: add cli command to remove organization member --- cli/organizationmembers.go | 36 ++++++++++++++++++++++++-- cli/organizationmembers_test.go | 46 +++++++++++++++++++++++++++++++++ codersdk/organizations.go | 7 +++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/cli/organizationmembers.go b/cli/organizationmembers.go index e5754fda7220b..521ec5bfb7d37 100644 --- a/cli/organizationmembers.go +++ b/cli/organizationmembers.go @@ -20,6 +20,7 @@ func (r *RootCmd) organizationMembers() *serpent.Command { r.listOrganizationMembers(), r.assignOrganizationRoles(), r.addOrganizationMember(), + r.removeOrganizationMember(), }, Handler: func(inv *serpent.Invocation) error { return inv.Command.HelpHandler(inv) @@ -29,6 +30,37 @@ func (r *RootCmd) organizationMembers() *serpent.Command { return cmd } +func (r *RootCmd) removeOrganizationMember() *serpent.Command { + client := new(codersdk.Client) + + cmd := &serpent.Command{ + Use: "remove ", + 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 { client := new(codersdk.Client) @@ -49,10 +81,10 @@ func (r *RootCmd) addOrganizationMember() *serpent.Command { _, err = client.PostOrganizationMember(ctx, organization.ID, user) 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 }, } diff --git a/cli/organizationmembers_test.go b/cli/organizationmembers_test.go index 89c10e8cf2e92..bb0029d77a98b 100644 --- a/cli/organizationmembers_test.go +++ b/cli/organizationmembers_test.go @@ -72,3 +72,49 @@ func TestAddOrganizationMembers(t *testing.T) { 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") + }) +} diff --git a/codersdk/organizations.go b/codersdk/organizations.go index 35bd1d64568e0..bc9e2514b2c15 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -50,6 +50,13 @@ type Organization struct { Icon string `table:"icon" json:"icon"` } +func (o Organization) HumanName() string { + if o.DisplayName == "" { + return o.Name + } + return o.DisplayName +} + type OrganizationMember struct { UserID uuid.UUID `table:"user id" json:"user_id" format:"uuid"` OrganizationID uuid.UUID `table:"organization id" json:"organization_id" format:"uuid"`