Skip to content

Commit f6fe6f2

Browse files
committed
chore: implement delete organization member
Side effects of removing an organization member will orphan their user resources. These side effects are not addressed here
1 parent ce367e5 commit f6fe6f2

File tree

15 files changed

+295
-0
lines changed

15 files changed

+295
-0
lines changed

coderd/apidoc/docs.go

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,7 @@ func New(options *Options) *API {
860860
r.Use(
861861
httpmw.ExtractOrganizationMemberParam(options.Database),
862862
)
863+
r.Delete("/", api.deleteOrganizationMember)
863864
r.Put("/roles", api.putMemberRoles)
864865
r.Post("/workspaces", api.postWorkspacesByOrganization)
865866
})

coderd/database/dbauthz/dbauthz.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,16 @@ func (q *querier) DeleteOrganization(ctx context.Context, id uuid.UUID) error {
10351035
return deleteQ(q.log, q.auth, q.db.GetOrganizationByID, q.db.DeleteOrganization)(ctx, id)
10361036
}
10371037

1038+
func (q *querier) DeleteOrganizationMember(ctx context.Context, arg database.DeleteOrganizationMemberParams) error {
1039+
return deleteQ[database.OrganizationMember](q.log, q.auth, func(ctx context.Context, arg database.DeleteOrganizationMemberParams) (database.OrganizationMember, error) {
1040+
member, err := database.ExpectOne(q.OrganizationMembers(ctx, database.OrganizationMembersParams(arg)))
1041+
if err != nil {
1042+
return database.OrganizationMember{}, err
1043+
}
1044+
return member.OrganizationMember, nil
1045+
}, q.db.DeleteOrganizationMember)(ctx, arg)
1046+
}
1047+
10381048
func (q *querier) DeleteReplicasUpdatedBefore(ctx context.Context, updatedAt time.Time) error {
10391049
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceSystem); err != nil {
10401050
return err

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,23 @@ func (s *MethodTestSuite) TestOrganization() {
628628
rbac.ResourceAssignOrgRole.InOrg(o.ID), policy.ActionAssign,
629629
rbac.ResourceOrganizationMember.InOrg(o.ID).WithID(u.ID), policy.ActionCreate)
630630
}))
631+
s.Run("DeleteOrganizationMember", s.Subtest(func(db database.Store, check *expects) {
632+
o := dbgen.Organization(s.T(), db, database.Organization{})
633+
u := dbgen.User(s.T(), db, database.User{})
634+
member := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{UserID: u.ID, OrganizationID: o.ID})
635+
636+
check.Args(database.DeleteOrganizationMemberParams{
637+
OrganizationID: o.ID,
638+
UserID: u.ID,
639+
}).Asserts(
640+
// Reads the org member before it tries to delete it
641+
member, policy.ActionRead,
642+
member, policy.ActionDelete).
643+
// SQL Filter returns a 404
644+
WithNotAuthorized("no rows").
645+
WithCancelled("no rows").
646+
Errors(sql.ErrNoRows)
647+
}))
631648
s.Run("UpdateOrganization", s.Subtest(func(db database.Store, check *expects) {
632649
o := dbgen.Organization(s.T(), db, database.Organization{
633650
Name: "something-unique",

coderd/database/dbmem/dbmem.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,24 @@ func (q *FakeQuerier) DeleteOrganization(_ context.Context, id uuid.UUID) error
16321632
return sql.ErrNoRows
16331633
}
16341634

1635+
func (q *FakeQuerier) DeleteOrganizationMember(_ context.Context, arg database.DeleteOrganizationMemberParams) error {
1636+
err := validateDatabaseType(arg)
1637+
if err != nil {
1638+
return err
1639+
}
1640+
1641+
q.mutex.Lock()
1642+
defer q.mutex.Unlock()
1643+
1644+
deleted := slices.DeleteFunc(q.data.organizationMembers, func(member database.OrganizationMember) bool {
1645+
return member.OrganizationID == arg.OrganizationID && member.UserID == arg.UserID
1646+
})
1647+
if len(deleted) == 0 {
1648+
return sql.ErrNoRows
1649+
}
1650+
return nil
1651+
}
1652+
16351653
func (q *FakeQuerier) DeleteReplicasUpdatedBefore(_ context.Context, before time.Time) error {
16361654
q.mutex.Lock()
16371655
defer q.mutex.Unlock()

coderd/database/dbmetrics/dbmetrics.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)