fix(repo): preserve transfer recipient collaboration (#39042)

Remove temporary recipient access after a transfer ends while preserving
existing collaboration.

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
bircni
2026-08-22 21:43:42 +02:00
committed by GitHub
parent 9251eeb66b
commit e6af4c341c
7 changed files with 138 additions and 27 deletions
+21 -4
View File
@@ -450,7 +450,7 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use
return transferOwnership(ctx, doer, newOwner.Name, repo, teams)
}
if user_model.IsUserBlockedBy(ctx, doer, newOwner.ID) {
if user_model.IsUserBlockedBy(ctx, doer, newOwner.ID) || user_model.IsUserBlockedBy(ctx, newOwner, repo.OwnerID) {
return user_model.ErrBlockedUser
}
@@ -471,15 +471,19 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use
if err != nil {
return err
}
if !hasAccess {
if err := AddOrUpdateCollaborator(ctx, repo, newOwner, perm.AccessModeRead); err != nil {
grantRecipientTempAccess := !hasAccess
if grantRecipientTempAccess {
if err := db.Insert(ctx, &repo_model.Collaboration{RepoID: repo.ID, UserID: newOwner.ID, Mode: perm.AccessModeRead}); err != nil {
return err
}
if err := access_model.RecalculateUserAccess(ctx, repo, newOwner.ID); err != nil {
return err
}
}
// Make repo as pending for transfer
repo.Status = repo_model.RepositoryPendingTransfer
return repo_model.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams)
return repo_model.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams, grantRecipientTempAccess)
}); err != nil {
return err
}
@@ -511,6 +515,9 @@ func RejectRepositoryTransfer(ctx context.Context, repo *repo_model.Repository,
if !repoTransfer.CanUserAcceptOrRejectTransfer(ctx, doer) {
return util.ErrPermissionDenied
}
if err := removeTransferRecipientCollaboration(ctx, repoTransfer); err != nil {
return err
}
repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "status"); err != nil {
@@ -521,6 +528,13 @@ func RejectRepositoryTransfer(ctx context.Context, repo *repo_model.Repository,
})
}
func removeTransferRecipientCollaboration(ctx context.Context, repoTransfer *repo_model.RepoTransfer) error {
if !repoTransfer.RecipientAccessGranted {
return nil
}
return deleteCollaborationByMode(ctx, repoTransfer.Repo, repoTransfer.Recipient, perm.AccessModeRead)
}
func canUserCancelTransfer(ctx context.Context, r *repo_model.RepoTransfer, u *user_model.User) bool {
if u.IsAdmin || u.ID == r.DoerID {
return true
@@ -559,6 +573,9 @@ func CancelRepositoryTransfer(ctx context.Context, repoTransfer *repo_model.Repo
if !canUserCancelTransfer(ctx, repoTransfer, doer) {
return util.ErrPermissionDenied
}
if err := removeTransferRecipientCollaboration(ctx, repoTransfer); err != nil {
return err
}
repoTransfer.Repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repoTransfer.Repo, "status"); err != nil {