diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2024-02-05 14:17:23 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-05 06:17:23 +0000 |
commit | 9bb1adf8ea5db928e0b21d6ee89876d15d2ec6a1 (patch) | |
tree | 78c0dc8b7558273eceddcf168a9d811084e4c5ff /models | |
parent | 2da233ad8be107de29190720f1c30199410fe0cd (diff) | |
download | gitea-9bb1adf8ea5db928e0b21d6ee89876d15d2ec6a1.tar.gz gitea-9bb1adf8ea5db928e0b21d6ee89876d15d2ec6a1.zip |
Move some repository transfer functions to service layer (#28855)
Diffstat (limited to 'models')
-rw-r--r-- | models/repo/update.go | 50 | ||||
-rw-r--r-- | models/repo_transfer.go | 247 | ||||
-rw-r--r-- | models/repo_transfer_test.go | 57 |
3 files changed, 1 insertions, 353 deletions
diff --git a/models/repo/update.go b/models/repo/update.go index 6ddf1a8905..e7ca224028 100644 --- a/models/repo/update.go +++ b/models/repo/update.go @@ -6,7 +6,6 @@ package repo import ( "context" "fmt" - "strings" "time" "code.gitea.io/gitea/models/db" @@ -135,55 +134,6 @@ func CheckCreateRepository(ctx context.Context, doer, u *user_model.User, name s return nil } -// ChangeRepositoryName changes all corresponding setting from old repository name to new one. -func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *Repository, newRepoName string) (err error) { - oldRepoName := repo.Name - newRepoName = strings.ToLower(newRepoName) - if err = IsUsableRepoName(newRepoName); err != nil { - return err - } - - if err := repo.LoadOwner(ctx); err != nil { - return err - } - - has, err := IsRepositoryModelOrDirExist(ctx, repo.Owner, newRepoName) - if err != nil { - return fmt.Errorf("IsRepositoryExist: %w", err) - } else if has { - return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName} - } - - newRepoPath := RepoPath(repo.Owner.Name, newRepoName) - if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil { - return fmt.Errorf("rename repository directory: %w", err) - } - - wikiPath := repo.WikiPath() - isExist, err := util.IsExist(wikiPath) - if err != nil { - log.Error("Unable to check if %s exists. Error: %v", wikiPath, err) - return err - } - if isExist { - if err = util.Rename(wikiPath, WikiPath(repo.Owner.Name, newRepoName)); err != nil { - return fmt.Errorf("rename repository wiki: %w", err) - } - } - - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - if err := NewRedirect(ctx, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil { - return err - } - - return committer.Commit() -} - // UpdateRepoSize updates the repository size, calculating it using getDirectorySize func UpdateRepoSize(ctx context.Context, repoID, gitSize, lfsSize int64) error { _, err := db.GetEngine(ctx).ID(repoID).Cols("size", "git_size", "lfs_size").NoAutoTime().Update(&Repository{ diff --git a/models/repo_transfer.go b/models/repo_transfer.go index 630c243c8e..676e2dbb63 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -6,17 +6,13 @@ package models import ( "context" "fmt" - "os" "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" - access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" ) // RepoTransfer is used to manage repository transfers @@ -115,32 +111,11 @@ func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Reposito return transfer, nil } -func deleteRepositoryTransfer(ctx context.Context, repoID int64) error { +func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error { _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(&RepoTransfer{}) return err } -// CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry, -// thus cancel the transfer process. -func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) error { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - repo.Status = repo_model.RepositoryReady - if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { - return err - } - - if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil { - return err - } - - return committer.Commit() -} - // TestRepositoryReadyForTransfer make sure repo is ready to transfer func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error { switch status { @@ -197,223 +172,3 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m return db.Insert(ctx, transfer) }) } - -// TransferOwnership transfers all corresponding repository items from old user to new one. -func TransferOwnership(ctx context.Context, doer *user_model.User, newOwnerName string, repo *repo_model.Repository) (err error) { - repoRenamed := false - wikiRenamed := false - oldOwnerName := doer.Name - - defer func() { - if !repoRenamed && !wikiRenamed { - return - } - - recoverErr := recover() - if err == nil && recoverErr == nil { - return - } - - if repoRenamed { - if err := util.Rename(repo_model.RepoPath(newOwnerName, repo.Name), repo_model.RepoPath(oldOwnerName, repo.Name)); err != nil { - log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, - repo_model.RepoPath(newOwnerName, repo.Name), repo_model.RepoPath(oldOwnerName, repo.Name), err) - } - } - - if wikiRenamed { - if err := util.Rename(repo_model.WikiPath(newOwnerName, repo.Name), repo_model.WikiPath(oldOwnerName, repo.Name)); err != nil { - log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, - repo_model.WikiPath(newOwnerName, repo.Name), repo_model.WikiPath(oldOwnerName, repo.Name), err) - } - } - - if recoverErr != nil { - log.Error("Panic within TransferOwnership: %v\n%s", recoverErr, log.Stack(2)) - panic(recoverErr) - } - }() - - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - sess := db.GetEngine(ctx) - - newOwner, err := user_model.GetUserByName(ctx, newOwnerName) - if err != nil { - return fmt.Errorf("get new owner '%s': %w", newOwnerName, err) - } - newOwnerName = newOwner.Name // ensure capitalisation matches - - // Check if new owner has repository with same name. - if has, err := repo_model.IsRepositoryModelOrDirExist(ctx, newOwner, repo.Name); err != nil { - return fmt.Errorf("IsRepositoryExist: %w", err) - } else if has { - return repo_model.ErrRepoAlreadyExist{ - Uname: newOwnerName, - Name: repo.Name, - } - } - - oldOwner := repo.Owner - oldOwnerName = oldOwner.Name - - // Note: we have to set value here to make sure recalculate accesses is based on - // new owner. - repo.OwnerID = newOwner.ID - repo.Owner = newOwner - repo.OwnerName = newOwner.Name - - // Update repository. - if _, err := sess.ID(repo.ID).Update(repo); err != nil { - return fmt.Errorf("update owner: %w", err) - } - - // Remove redundant collaborators. - collaborators, err := repo_model.GetCollaborators(ctx, repo.ID, db.ListOptions{}) - if err != nil { - return fmt.Errorf("getCollaborators: %w", err) - } - - // Dummy object. - collaboration := &repo_model.Collaboration{RepoID: repo.ID} - for _, c := range collaborators { - if c.IsGhost() { - collaboration.ID = c.Collaboration.ID - if _, err := sess.Delete(collaboration); err != nil { - return fmt.Errorf("remove collaborator '%d': %w", c.ID, err) - } - collaboration.ID = 0 - } - - if c.ID != newOwner.ID { - isMember, err := organization.IsOrganizationMember(ctx, newOwner.ID, c.ID) - if err != nil { - return fmt.Errorf("IsOrgMember: %w", err) - } else if !isMember { - continue - } - } - collaboration.UserID = c.ID - if _, err := sess.Delete(collaboration); err != nil { - return fmt.Errorf("remove collaborator '%d': %w", c.ID, err) - } - collaboration.UserID = 0 - } - - // Remove old team-repository relations. - if oldOwner.IsOrganization() { - if err := organization.RemoveOrgRepo(ctx, oldOwner.ID, repo.ID); err != nil { - return fmt.Errorf("removeOrgRepo: %w", err) - } - } - - if newOwner.IsOrganization() { - teams, err := organization.FindOrgTeams(ctx, newOwner.ID) - if err != nil { - return fmt.Errorf("LoadTeams: %w", err) - } - for _, t := range teams { - if t.IncludesAllRepositories { - if err := AddRepository(ctx, t, repo); err != nil { - return fmt.Errorf("AddRepository: %w", err) - } - } - } - } else if err := access_model.RecalculateAccesses(ctx, repo); err != nil { - // Organization called this in addRepository method. - return fmt.Errorf("recalculateAccesses: %w", err) - } - - // Update repository count. - if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil { - return fmt.Errorf("increase new owner repository count: %w", err) - } else if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil { - return fmt.Errorf("decrease old owner repository count: %w", err) - } - - if err := repo_model.WatchRepo(ctx, doer.ID, repo.ID, true); err != nil { - return fmt.Errorf("watchRepo: %w", err) - } - - // Remove watch for organization. - if oldOwner.IsOrganization() { - if err := repo_model.WatchRepo(ctx, oldOwner.ID, repo.ID, false); err != nil { - return fmt.Errorf("watchRepo [false]: %w", err) - } - } - - // Delete labels that belong to the old organization and comments that added these labels - if oldOwner.IsOrganization() { - if _, err := sess.Exec(`DELETE FROM issue_label WHERE issue_label.id IN ( - SELECT il_too.id FROM ( - SELECT il_too_too.id - FROM issue_label AS il_too_too - INNER JOIN label ON il_too_too.label_id = label.id - INNER JOIN issue on issue.id = il_too_too.issue_id - WHERE - issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?)) - ) AS il_too )`, repo.ID, newOwner.ID); err != nil { - return fmt.Errorf("Unable to remove old org labels: %w", err) - } - - if _, err := sess.Exec(`DELETE FROM comment WHERE comment.id IN ( - SELECT il_too.id FROM ( - SELECT com.id - FROM comment AS com - INNER JOIN label ON com.label_id = label.id - INNER JOIN issue ON issue.id = com.issue_id - WHERE - com.type = ? AND issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?)) - ) AS il_too)`, issues_model.CommentTypeLabel, repo.ID, newOwner.ID); err != nil { - return fmt.Errorf("Unable to remove old org label comments: %w", err) - } - } - - // Rename remote repository to new path and delete local copy. - dir := user_model.UserPath(newOwner.Name) - - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return fmt.Errorf("Failed to create dir %s: %w", dir, err) - } - - if err := util.Rename(repo_model.RepoPath(oldOwner.Name, repo.Name), repo_model.RepoPath(newOwner.Name, repo.Name)); err != nil { - return fmt.Errorf("rename repository directory: %w", err) - } - repoRenamed = true - - // Rename remote wiki repository to new path and delete local copy. - wikiPath := repo_model.WikiPath(oldOwner.Name, repo.Name) - - if isExist, err := util.IsExist(wikiPath); err != nil { - log.Error("Unable to check if %s exists. Error: %v", wikiPath, err) - return err - } else if isExist { - if err := util.Rename(wikiPath, repo_model.WikiPath(newOwner.Name, repo.Name)); err != nil { - return fmt.Errorf("rename repository wiki: %w", err) - } - wikiRenamed = true - } - - if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil { - return fmt.Errorf("deleteRepositoryTransfer: %w", err) - } - repo.Status = repo_model.RepositoryReady - if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { - return err - } - - // If there was previously a redirect at this location, remove it. - if err := repo_model.DeleteRedirect(ctx, newOwner.ID, repo.Name); err != nil { - return fmt.Errorf("delete repo redirect: %w", err) - } - - if err := repo_model.NewRedirect(ctx, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil { - return fmt.Errorf("repo_model.NewRedirect: %w", err) - } - - return committer.Commit() -} diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go deleted file mode 100644 index b55cef9473..0000000000 --- a/models/repo_transfer_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package models - -import ( - "testing" - - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - - "github.com/stretchr/testify/assert" -) - -func TestRepositoryTransfer(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) - - transfer, err := GetPendingRepositoryTransfer(db.DefaultContext, repo) - assert.NoError(t, err) - assert.NotNil(t, transfer) - - // Cancel transfer - assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo)) - - transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) - assert.Error(t, err) - assert.Nil(t, transfer) - assert.True(t, IsErrNoPendingTransfer(err)) - - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - - assert.NoError(t, CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil)) - - transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) - assert.Nil(t, err) - assert.NoError(t, transfer.LoadAttributes(db.DefaultContext)) - assert.Equal(t, "user2", transfer.Recipient.Name) - - org6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - - // Only transfer can be started at any given time - err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, org6, repo.ID, nil) - assert.Error(t, err) - assert.True(t, IsErrRepoTransferInProgress(err)) - - // Unknown user - err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil) - assert.Error(t, err) - - // Cancel transfer - assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo)) -} |