From ac636b53cf74c5d851e09f734adadc6a30d071f2 Mon Sep 17 00:00:00 2001 From: Joe Chen <jc@unknwon.io> Date: Fri, 3 Nov 2023 22:22:21 -0400 Subject: [PATCH] `DeleteByID` --- internal/db/org.go | 34 ---------------------------------- internal/db/organizations.go | 34 ++++++++++++++++++++++++++++++++++ internal/db/repo.go | 10 ++++++++++ internal/db/users.go | 3 +-- internal/route/org/setting.go | 5 +++-- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/internal/db/org.go b/internal/db/org.go index f504993df..5c791adf9 100644 --- a/internal/db/org.go +++ b/internal/db/org.go @@ -5,46 +5,12 @@ package db import ( - "context" "fmt" "xorm.io/builder" "xorm.io/xorm" ) -// deleteBeans deletes all given beans, beans should contain delete conditions. -func deleteBeans(e Engine, beans ...any) (err error) { - for i := range beans { - if _, err = e.Delete(beans[i]); err != nil { - return err - } - } - return nil -} - -// DeleteOrganization completely and permanently deletes everything of organization. -func DeleteOrganization(org *User) error { - err := Users.DeleteByID(context.TODO(), org.ID, false) - if err != nil { - return err - } - - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return err - } - - if err = deleteBeans(sess, - &Team{OrgID: org.ID}, - &OrgUser{OrgID: org.ID}, - &TeamUser{OrgID: org.ID}, - ); err != nil { - return fmt.Errorf("deleteBeans: %v", err) - } - return sess.Commit() -} - func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) { orgs := make([]*User, 0, 10) if !showAll { diff --git a/internal/db/organizations.go b/internal/db/organizations.go index 3d65b0d15..d5a2f2add 100644 --- a/internal/db/organizations.go +++ b/internal/db/organizations.go @@ -40,6 +40,9 @@ type OrganizationsStore interface { CountByUser(ctx context.Context, userID int64) (int64, error) // Count returns the total number of organizations. Count(ctx context.Context) int64 + // DeleteByID deletes the given organization and all their resources. It returns + // ErrOrganizationOwnRepos when the user still has repository ownership. + DeleteByID(ctx context.Context, orgID int64) error // AddMember adds a new member to the given organization. AddMember(ctx context.Context, orgID, userID int64) error @@ -541,6 +544,37 @@ func (db *organizations) Count(ctx context.Context) int64 { return count } +type ErrOrganizationOwnRepos struct { + args errutil.Args +} + +// IsErrOrganizationOwnRepos returns true if the underlying error has the type +// ErrOrganizationOwnRepos. +func IsErrOrganizationOwnRepos(err error) bool { + return errors.As(errors.Cause(err), &ErrOrganizationOwnRepos{}) +} + +func (err ErrOrganizationOwnRepos) Error() string { + return fmt.Sprintf("organization still has repository ownership: %v", err.args) +} + +func (db *organizations) DeleteByID(ctx context.Context, orgID int64) error { + return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + for _, t := range []any{&Team{}, &OrgUser{}, &TeamUser{}} { + err := tx.Where("org_id = ?", orgID).Delete(t).Error + if err != nil { + return errors.Wrapf(err, "clean up table %T", t) + } + } + + err := NewUsersStore(tx).DeleteByID(ctx, orgID, false) + if err != nil { + return errors.Wrap(err, "delete organization") + } + return nil + }) +} + var _ errutil.NotFound = (*ErrTeamNotExist)(nil) type ErrTeamNotExist struct { diff --git a/internal/db/repo.go b/internal/db/repo.go index 184d9fb2e..a878344e0 100644 --- a/internal/db/repo.go +++ b/internal/db/repo.go @@ -1791,6 +1791,16 @@ func DeleteRepository(ownerID, repoID int64) error { return nil } +// deleteBeans deletes all given beans, beans should contain delete conditions. +func deleteBeans(e Engine, beans ...any) (err error) { + for i := range beans { + if _, err = e.Delete(beans[i]); err != nil { + return err + } + } + return nil +} + // GetRepositoryByRef returns a Repository specified by a GFM reference. // See https://help.github.com/articles/writing-on-github#references for more information on the syntax. func GetRepositoryByRef(ref string) (*Repository, error) { diff --git a/internal/db/users.go b/internal/db/users.go index 68170c943..53be95965 100644 --- a/internal/db/users.go +++ b/internal/db/users.go @@ -467,8 +467,7 @@ type ErrUserOwnRepos struct { // IsErrUserOwnRepos returns true if the underlying error has the type // ErrUserOwnRepos. func IsErrUserOwnRepos(err error) bool { - _, ok := errors.Cause(err).(ErrUserOwnRepos) - return ok + return errors.As(errors.Cause(err), &ErrUserOwnRepos{}) } func (err ErrUserOwnRepos) Error() string { diff --git a/internal/route/org/setting.go b/internal/route/org/setting.go index e632e8a7a..817022d84 100644 --- a/internal/route/org/setting.go +++ b/internal/route/org/setting.go @@ -115,8 +115,9 @@ func SettingsDelete(c *context.Context) { return } - if err := db.DeleteOrganization(org); err != nil { - if db.IsErrUserOwnRepos(err) { + err := db.Organizations.DeleteByID(c.Req.Context(), org.ID) + if err != nil { + if db.IsErrOrganizationOwnRepos(err) { c.Flash.Error(c.Tr("form.org_still_own_repo")) c.Redirect(c.Org.OrgLink + "/settings/delete") } else {