This commit is contained in:
Lunny Xiao 2025-07-19 11:00:56 -07:00
parent 804022bdb5
commit c89d939b54
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
4 changed files with 258 additions and 269 deletions

View File

@ -1114,8 +1114,7 @@ func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *us
// DeleteComment deletes the comment // DeleteComment deletes the comment
func DeleteComment(ctx context.Context, comment *Comment) (*Comment, error) { func DeleteComment(ctx context.Context, comment *Comment) (*Comment, error) {
e := db.GetEngine(ctx) if _, err := db.GetEngine(ctx).ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
return nil, err return nil, err
} }
@ -1130,7 +1129,7 @@ func DeleteComment(ctx context.Context, comment *Comment) (*Comment, error) {
return nil, err return nil, err
} }
} }
if _, err := e.Table("action"). if _, err := db.GetEngine(ctx).Table("action").
Where("comment_id = ?", comment.ID). Where("comment_id = ?", comment.ID).
Update(map[string]any{ Update(map[string]any{
"is_deleted": true, "is_deleted": true,

View File

@ -48,12 +48,11 @@ func deleteOrganization(ctx context.Context, org *org_model.Organization) error
// DeleteOrganization completely and permanently deletes everything of organization. // DeleteOrganization completely and permanently deletes everything of organization.
func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error { func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error {
ctx, committer, err := db.TxContext(ctx) // The repositories deletion of the organization cannot be under a transaction,
if err != nil { // because it cannot be rolled back because the content in disk will be deleted
return err // in the DeleteOwnerRepositoriesDirectly function.
} // Even not all repositories deleted successfully, we still delete the organization again.
defer committer.Close() // TODO: We should mark all the repositories as deleted and delete them in a background job.
if purge { if purge {
err := repo_service.DeleteOwnerRepositoriesDirectly(ctx, org.AsUser()) err := repo_service.DeleteOwnerRepositoriesDirectly(ctx, org.AsUser())
if err != nil { if err != nil {
@ -61,6 +60,7 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge
} }
} }
err := db.WithTx(ctx, func(ctx context.Context) error {
// Check ownership of repository. // Check ownership of repository.
count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: org.ID}) count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: org.ID})
if err != nil { if err != nil {
@ -79,8 +79,9 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge
if err := deleteOrganization(ctx, org); err != nil { if err := deleteOrganization(ctx, org); err != nil {
return fmt.Errorf("DeleteOrganization: %w", err) return fmt.Errorf("DeleteOrganization: %w", err)
} }
return nil
if err := committer.Commit(); err != nil { })
if err != nil {
return err return err
} }

View File

@ -51,15 +51,8 @@ func deleteDBRepository(ctx context.Context, repoID int64) error {
// DeleteRepository deletes a repository for a user or organization. // DeleteRepository deletes a repository for a user or organization.
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock) // make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams ...bool) error { func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams ...bool) error {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
sess := db.GetEngine(ctx)
repo := &repo_model.Repository{} repo := &repo_model.Repository{}
has, err := sess.ID(repoID).Get(repo) has, err := db.GetEngine(ctx).ID(repoID).Get(repo)
if err != nil { if err != nil {
return err return err
} else if !has { } else if !has {
@ -82,6 +75,13 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err) return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
} }
var needRewriteKeysFile bool
releaseAttachments := make([]*repo_model.Attachment, 0, 20)
var repoAttachments []*repo_model.Attachment
var archivePaths []string
var lfsPaths []string
err = db.WithTx(ctx, func(ctx context.Context) error {
// In case owner is a organization, we have to change repo specific teams // In case owner is a organization, we have to change repo specific teams
// if ignoreOrgTeams is not true // if ignoreOrgTeams is not true
var org *user_model.User var org *user_model.User
@ -96,7 +96,7 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
if err != nil { if err != nil {
return err return err
} }
needRewriteKeysFile := deleted > 0 needRewriteKeysFile = deleted > 0
if err := deleteDBRepository(ctx, repoID); err != nil { if err := deleteDBRepository(ctx, repoID); err != nil {
return err return err
@ -117,7 +117,6 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
} }
// some attachments have release_id but repo_id = 0 // some attachments have release_id but repo_id = 0
releaseAttachments := make([]*repo_model.Attachment, 0, 20)
if err = db.GetEngine(ctx).Join("INNER", "`release`", "`release`.id = `attachment`.release_id"). if err = db.GetEngine(ctx).Join("INNER", "`release`", "`release`.id = `attachment`.release_id").
Where("`release`.repo_id = ?", repoID). Where("`release`.repo_id = ?", repoID).
Find(&releaseAttachments); err != nil { Find(&releaseAttachments); err != nil {
@ -227,11 +226,11 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
// Remove LFS objects // Remove LFS objects
var lfsObjects []*git_model.LFSMetaObject var lfsObjects []*git_model.LFSMetaObject
if err = sess.Where("repository_id=?", repoID).Find(&lfsObjects); err != nil { if err = db.GetEngine(ctx).Where("repository_id=?", repoID).Find(&lfsObjects); err != nil {
return err return err
} }
lfsPaths := make([]string, 0, len(lfsObjects)) lfsPaths = make([]string, 0, len(lfsObjects))
for _, v := range lfsObjects { for _, v := range lfsObjects {
count, err := db.CountByBean(ctx, &git_model.LFSMetaObject{Pointer: lfs.Pointer{Oid: v.Oid}}) count, err := db.CountByBean(ctx, &git_model.LFSMetaObject{Pointer: lfs.Pointer{Oid: v.Oid}})
if err != nil { if err != nil {
@ -250,11 +249,11 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
// Remove archives // Remove archives
var archives []*repo_model.RepoArchiver var archives []*repo_model.RepoArchiver
if err = sess.Where("repo_id=?", repoID).Find(&archives); err != nil { if err = db.GetEngine(ctx).Where("repo_id=?", repoID).Find(&archives); err != nil {
return err return err
} }
archivePaths := make([]string, 0, len(archives)) archivePaths = make([]string, 0, len(archives))
for _, v := range archives { for _, v := range archives {
archivePaths = append(archivePaths, v.RelativePath()) archivePaths = append(archivePaths, v.RelativePath())
} }
@ -264,14 +263,13 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
} }
if repo.NumForks > 0 { if repo.NumForks > 0 {
if _, err = sess.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil { if _, err = db.GetEngine(ctx).Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
log.Error("reset 'fork_id' and 'is_fork': %v", err) log.Error("reset 'fork_id' and 'is_fork': %v", err)
} }
} }
// Get all attachments with repo_id = repo.ID. some release attachments have repo_id = 0 should be deleted before // Get all attachments with repo_id = repo.ID. some release attachments have repo_id = 0 should be deleted before
var repoAttachments []*repo_model.Attachment if err := db.GetEngine(ctx).Where(builder.Eq{
if err := sess.Where(builder.Eq{
"repo_id": repo.ID, "repo_id": repo.ID,
}).Find(&repoAttachments); err != nil { }).Find(&repoAttachments); err != nil {
return err return err
@ -281,16 +279,12 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams
} }
// unlink packages linked to this repository // unlink packages linked to this repository
if err = packages_model.UnlinkRepositoryFromAllPackages(ctx, repoID); err != nil { return packages_model.UnlinkRepositoryFromAllPackages(ctx, repoID)
})
if err != nil {
return err return err
} }
if err = committer.Commit(); err != nil {
return err
}
committer.Close()
if needRewriteKeysFile { if needRewriteKeysFile {
if err := asymkey_service.RewriteAllPublicKeys(ctx); err != nil { if err := asymkey_service.RewriteAllPublicKeys(ctx); err != nil {
log.Error("RewriteAllPublicKeys failed: %v", err) log.Error("RewriteAllPublicKeys failed: %v", err)

View File

@ -211,12 +211,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
} }
} }
ctx, committer, err := db.TxContext(ctx) toBeCleanedAttachments, err := db.WithTx2(ctx, func(ctx context.Context) ([]*repo_model.Attachment, error) {
if err != nil {
return err
}
defer committer.Close()
// Note: A user owns any repository or belongs to any organization // Note: A user owns any repository or belongs to any organization
// cannot perform delete operation. This causes a race with the purge above // cannot perform delete operation. This causes a race with the purge above
// however consistency requires that we ensure that this is the case // however consistency requires that we ensure that this is the case
@ -224,35 +219,35 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
// Check ownership of repository. // Check ownership of repository.
count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: u.ID}) count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: u.ID})
if err != nil { if err != nil {
return fmt.Errorf("GetRepositoryCount: %w", err) return nil, fmt.Errorf("GetRepositoryCount: %w", err)
} else if count > 0 { } else if count > 0 {
return repo_model.ErrUserOwnRepos{UID: u.ID} return nil, repo_model.ErrUserOwnRepos{UID: u.ID}
} }
// Check membership of organization. // Check membership of organization.
count, err = organization.GetOrganizationCount(ctx, u) count, err = organization.GetOrganizationCount(ctx, u)
if err != nil { if err != nil {
return fmt.Errorf("GetOrganizationCount: %w", err) return nil, fmt.Errorf("GetOrganizationCount: %w", err)
} else if count > 0 { } else if count > 0 {
return organization.ErrUserHasOrgs{UID: u.ID} return nil, organization.ErrUserHasOrgs{UID: u.ID}
} }
// Check ownership of packages. // Check ownership of packages.
if ownsPackages, err := packages_model.HasOwnerPackages(ctx, u.ID); err != nil { if ownsPackages, err := packages_model.HasOwnerPackages(ctx, u.ID); err != nil {
return fmt.Errorf("HasOwnerPackages: %w", err) return nil, fmt.Errorf("HasOwnerPackages: %w", err)
} else if ownsPackages { } else if ownsPackages {
return packages_model.ErrUserOwnPackages{UID: u.ID} return nil, packages_model.ErrUserOwnPackages{UID: u.ID}
} }
toBeCleanedAttachments, err := deleteUser(ctx, u, purge) toBeCleanedAttachments, err := deleteUser(ctx, u, purge)
if err != nil { if err != nil {
return fmt.Errorf("DeleteUser: %w", err) return nil, fmt.Errorf("DeleteUser: %w", err)
} }
return toBeCleanedAttachments, nil
if err := committer.Commit(); err != nil { })
if err != nil {
return err return err
} }
_ = committer.Close()
attachment_service.AddAttachmentsToCleanQueue(ctx, toBeCleanedAttachments) attachment_service.AddAttachmentsToCleanQueue(ctx, toBeCleanedAttachments)