From bf92bcdf666d455ed04a0aac91c0c24211af3e3b Mon Sep 17 00:00:00 2001 From: Joe Chen Date: Sun, 12 Nov 2023 22:04:25 -0500 Subject: [PATCH] orgsDeleteByID --- internal/db/organizations.go | 6 ++- internal/db/organizations_test.go | 70 ++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/internal/db/organizations.go b/internal/db/organizations.go index d0f6eb6ca..efaf72197 100644 --- a/internal/db/organizations.go +++ b/internal/db/organizations.go @@ -26,7 +26,8 @@ type OrganizationsStore interface { // name is not allowed as an organization name, or ErrOrganizationAlreadyExist // when a user or an organization with same name already exists. Create(ctx context.Context, name string, ownerID int64, opts CreateOrganizationOptions) (*Organization, error) - // GetByName returns the organization with given name. + // GetByName returns the organization with given name. It returns + // ErrOrganizationNotExist when not found. GetByName(ctx context.Context, name string) (*Organization, error) // SearchByName returns a list of organizations whose username or full name // matches the given keyword case-insensitively. Results are paginated by given @@ -628,6 +629,9 @@ func (db *organizations) DeleteByID(ctx context.Context, orgID int64) error { err := NewUsersStore(tx).DeleteByID(ctx, orgID, false) if err != nil { + if IsErrUserOwnRepos(err) { + return ErrOrganizationOwnRepos{args: map[string]any{"orgID": orgID}} + } return errors.Wrap(err, "delete organization") } return nil diff --git a/internal/db/organizations_test.go b/internal/db/organizations_test.go index a869ce386..cab03023d 100644 --- a/internal/db/organizations_test.go +++ b/internal/db/organizations_test.go @@ -26,7 +26,11 @@ func TestOrganizations(t *testing.T) { t.Parallel() ctx := context.Background() - tables := []any{new(User), new(EmailAddress), new(OrgUser), new(Team), new(TeamUser)} + tables := []any{ + new(User), new(EmailAddress), new(OrgUser), new(Team), new(TeamUser), new(Repository), new(Watch), new(Star), + new(Follow), new(Issue), new(PublicKey), new(AccessToken), new(Collaboration), new(Access), new(Action), + new(IssueUser), + } db := &organizations{ DB: dbtest.NewDB(t, "orgs", tables...), } @@ -41,6 +45,7 @@ func TestOrganizations(t *testing.T) { {"List", orgsList}, {"CountByUser", orgsCountByUser}, {"Count", orgsCount}, + {"DeleteByID", orgsDeleteByID}, } { t.Run(tc.name, func(t *testing.T) { t.Cleanup(func() { @@ -329,3 +334,66 @@ func orgsCount(t *testing.T, db *organizations) { got = db.Count(ctx) assert.Equal(t, int64(1), got) } + +func orgsDeleteByID(t *testing.T, db *organizations) { + ctx := context.Background() + + tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsDeleteByID-tempPictureAvatarUploadPath") + conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath}) + + t.Run("organization still has repository ownership", func(t *testing.T) { + org1, err := db.Create(ctx, "org1", 404, CreateOrganizationOptions{}) + require.NoError(t, err) + + _, err = NewRepositoriesStore(db.DB).Create(ctx, org1.ID, CreateRepoOptions{Name: "repo1"}) + require.NoError(t, err) + + err = db.DeleteByID(ctx, org1.ID) + wantErr := ErrOrganizationOwnRepos{errutil.Args{"orgID": org1.ID}} + assert.Equal(t, wantErr, err) + }) + + alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "alice@example.com", CreateUserOptions{}) + require.NoError(t, err) + org2, err := db.Create(ctx, "org2", alice.ID, CreateOrganizationOptions{}) + require.NoError(t, err) + + // Mock team membership + // TODO: Use Organizations.CreateTeam to replace SQL hack when the method is available. + team1 := &Team{ + OrgID: org2.ID, + LowerName: "team1", + Name: "team1", + NumMembers: 1, + } + err = db.DB.Create(team1).Error + require.NoError(t, err) + // TODO: Use Organizations.AddTeamMember to replace SQL hack when the method is available. + err = db.DB.Create( + &TeamUser{ + OrgID: org2.ID, + TeamID: team1.ID, + UID: alice.ID, + }, + ).Error + require.NoError(t, err) + + // Pull the trigger + err = db.DeleteByID(ctx, org2.ID) + require.NoError(t, err) + + // Verify after-the-fact data + for _, table := range []any{ + &Team{OrgID: org2.ID}, + &TeamUser{OrgID: org2.ID}, + } { + var count int64 + err = db.DB.Model(table).Where(table).Count(&count).Error + require.NoError(t, err, "table for %T", table) + assert.Equal(t, int64(0), count, "table for %T", table) + } + + _, err = db.GetByName(ctx, org2.Name) + wantErr := ErrOrganizationNotExist{errutil.Args{"name": org2.Name}} + assert.Equal(t, wantErr, err) +}