diff --git a/models/repo/transfer.go b/models/repo/transfer.go index 2d7762aa23f23..a03cee05b1fe7 100644 --- a/models/repo/transfer.go +++ b/models/repo/transfer.go @@ -135,10 +135,10 @@ func (r *RepoTransfer) LoadAttributes(ctx context.Context) error { return nil } -// CanUserAcceptTransfer checks if the user has the rights to accept/decline a repo transfer. +// CanUserAcceptOrRejectTransfer checks if the user has the rights to accept/decline a repo transfer. // For user, it checks if it's himself // For organizations, it checks if the user is able to create repos -func (r *RepoTransfer) CanUserAcceptTransfer(ctx context.Context, u *user_model.User) bool { +func (r *RepoTransfer) CanUserAcceptOrRejectTransfer(ctx context.Context, u *user_model.User) bool { if err := r.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return false @@ -157,32 +157,6 @@ func (r *RepoTransfer) CanUserAcceptTransfer(ctx context.Context, u *user_model. return allowed } -func (r *RepoTransfer) CanUserCancelTransfer(ctx context.Context, u *user_model.User) bool { - if r.DoerID == u.ID { // sender can cancel the transfer - return true - } - if err := r.Repo.LoadOwner(ctx); err != nil { - log.Error("LoadOwner: %v", err) - return false - } - if !r.Repo.Owner.IsOrganization() { - if u.ID == r.Repo.OwnerID { // owner can cancel the transfer - return true - } - } else { - allowed, err := organization.CanCreateOrgRepo(ctx, r.Repo.OwnerID, u.ID) - if err != nil { - log.Error("CanCreateOrgRepo: %v", err) - return false - } - if allowed { - return true - } - } - - return r.CanUserAcceptTransfer(ctx, u) // the user who can accept the transfer can also reject it -} - type PendingRepositoryTransferOptions struct { RepoID int64 SenderID int64 diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index 883c14ac9a88f..8a258f30b303d 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -204,7 +204,7 @@ func RejectTransfer(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - err := repo_service.CancelRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer) + err := repo_service.RejectRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer) if err != nil { switch { case repo_model.IsErrNoPendingTransfer(err): diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index f2158b07b0997..066643302300d 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -328,7 +328,7 @@ func Action(ctx *context.Context) { } ctx.Redirect(ctx.Repo.Repository.Link()) case "reject_transfer": - err = repo_service.CancelRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer) + err = repo_service.RejectRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer) if err == nil { ctx.Flash.Success(ctx.Tr("repo.settings.transfer.rejected")) } diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 0fc87a89fcff0..fa3c567b34dbf 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -829,7 +829,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := repo_service.CancelRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer); err != nil { + if err := repo_service.CancelRepositoryTransfer(ctx, repoTransfer, ctx.Doer); err != nil { ctx.ServerError("CancelRepositoryTransfer", err) return } diff --git a/services/context/repo.go b/services/context/repo.go index 05f6bb40f94ae..6db042bef7563 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -674,7 +674,8 @@ func RepoAssignment(ctx *Context) { ctx.Data["RepoTransfer"] = repoTransfer if ctx.Doer != nil { - ctx.Data["CanUserAcceptTransfer"] = repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer) + ctx.Data["CanUserAcceptTransfer"] = repoTransfer.CanUserAcceptOrRejectTransfer(ctx, ctx.Doer) + ctx.Data["CanUserRejectTransfer"] = ctx.Data["CanUserAcceptTransfer"] } } diff --git a/services/repository/transfer.go b/services/repository/transfer.go index 70c70f7fcf080..2f9b1d16b1d3d 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -48,7 +48,7 @@ func AcceptTransferOwnership(ctx context.Context, repo *repo_model.Repository, d return err } - if !repoTransfer.CanUserAcceptTransfer(ctx, doer) { + if !repoTransfer.CanUserAcceptOrRejectTransfer(ctx, doer) { return util.ErrPermissionDenied } @@ -452,10 +452,10 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use return nil } -// CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry, +// RejectRepositoryTransfer marks the repository as ready and remove pending transfer entry, // thus cancel the transfer process. -// Both the sender and the accepter can cancel the transfer. -func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository, doer *user_model.User) error { +// The accepter can reject the transfer. +func RejectRepositoryTransfer(ctx context.Context, repo *repo_model.Repository, doer *user_model.User) error { return db.WithTx(ctx, func(ctx context.Context) error { repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, repo) if err != nil { @@ -466,7 +466,7 @@ func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository, return err } - if !repoTransfer.CanUserCancelTransfer(ctx, doer) { + if !repoTransfer.CanUserAcceptOrRejectTransfer(ctx, doer) { return util.ErrPermissionDenied } @@ -478,3 +478,51 @@ func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository, return repo_model.DeleteRepositoryTransfer(ctx, repo.ID) }) } + +func canUserCancelTransfer(ctx context.Context, r *repo_model.RepoTransfer, u *user_model.User) bool { + if u.ID == r.DoerID { + return true + } + + if err := r.LoadAttributes(ctx); err != nil { + log.Error("LoadAttributes: %v", err) + return false + } + + if err := r.Repo.LoadOwner(ctx); err != nil { + log.Error("LoadOwner: %v", err) + return false + } + + if !r.Repo.Owner.IsOrganization() { + return r.Repo.OwnerID == u.ID + } + + perm, err := access_model.GetUserRepoPermission(ctx, r.Repo, u) + if err != nil { + log.Error("GetUserRepoPermission: %v", err) + return false + } + return perm.IsAdmin() +} + +// CancelRepositoryTransfer cancels the repository transfer process. The sender or +// the users who have admin permission of the original repository can cancel the transfer +func CancelRepositoryTransfer(ctx context.Context, repoTransfer *repo_model.RepoTransfer, doer *user_model.User) error { + return db.WithTx(ctx, func(ctx context.Context) error { + if err := repoTransfer.LoadAttributes(ctx); err != nil { + return err + } + + if !canUserCancelTransfer(ctx, repoTransfer, doer) { + return util.ErrPermissionDenied + } + + repoTransfer.Repo.Status = repo_model.RepositoryReady + if err := repo_model.UpdateRepositoryCols(ctx, repoTransfer.Repo, "status"); err != nil { + return err + } + + return repo_model.DeleteRepositoryTransfer(ctx, repoTransfer.RepoID) + }) +} diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go index 9fb46c57614ad..16a8fb6e1eed2 100644 --- a/services/repository/transfer_test.go +++ b/services/repository/transfer_test.go @@ -93,7 +93,7 @@ func TestRepositoryTransfer(t *testing.T) { assert.NotNil(t, transfer) // Cancel transfer - assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo, doer)) + assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, transfer, doer)) transfer, err = repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.Error(t, err) @@ -121,7 +121,7 @@ func TestRepositoryTransfer(t *testing.T) { err = repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo2.ID, nil) assert.Error(t, err) - // Cancel transfer - err = CancelRepositoryTransfer(db.DefaultContext, repo2, doer) + // Reject transfer + err = RejectRepositoryTransfer(db.DefaultContext, repo2, doer) assert.True(t, repo_model.IsErrNoPendingTransfer(err)) } diff --git a/services/user/block.go b/services/user/block.go index 0a2254b0132e9..7727780dfc919 100644 --- a/services/user/block.go +++ b/services/user/block.go @@ -202,12 +202,7 @@ func cancelRepositoryTransfers(ctx context.Context, doer, sender, recipient *use } for _, transfer := range transfers { - repo, err := repo_model.GetRepositoryByID(ctx, transfer.RepoID) - if err != nil { - return err - } - - if err := repo_service.CancelRepositoryTransfer(ctx, repo, doer); err != nil { + if err := repo_service.CancelRepositoryTransfer(ctx, transfer, doer); err != nil { return err } } diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 3e7214f48cf7f..c3edbcba2dd17 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -47,8 +47,8 @@
{{$.CsrfTokenHtml}} -
-