1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-03 09:07:19 +00:00

Repository transfer has to be confirmed, if user can not create repo for new owner (#14792)

* make repo as "pending transfer" if on transfer start doer has no right to create repo in new destination

* if new pending transfer ocured, create UI & Mail notifications
This commit is contained in:
6543
2021-03-01 01:47:30 +01:00
committed by GitHub
parent e0900310c4
commit a4148c0f12
32 changed files with 898 additions and 167 deletions

View File

@ -96,17 +96,27 @@ func Transfer(ctx *context.APIContext) {
}
}
if err = repo_service.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository, teams); err != nil {
if err := repo_service.StartRepositoryTransfer(ctx.User, newOwner, ctx.Repo.Repository, teams); err != nil {
if models.IsErrRepoTransferInProgress(err) {
ctx.Error(http.StatusConflict, "CreatePendingRepositoryTransfer", err)
return
}
if models.IsErrRepoAlreadyExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "CreatePendingRepositoryTransfer", err)
return
}
ctx.InternalServerError(err)
return
}
newRepo, err := models.GetRepositoryByName(newOwner.ID, ctx.Repo.Repository.Name)
if err != nil {
ctx.InternalServerError(err)
if ctx.Repo.Repository.Status == models.RepositoryPendingTransfer {
log.Trace("Repository transfer initiated: %s -> %s", ctx.Repo.Repository.FullName(), newOwner.Name)
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx.Repo.Repository, models.AccessModeAdmin))
return
}
log.Trace("Repository transferred: %s -> %s", ctx.Repo.Repository.FullName(), newOwner.Name)
ctx.JSON(http.StatusAccepted, convert.ToRepo(newRepo, models.AccessModeAdmin))
ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx.Repo.Repository, models.AccessModeAdmin))
}

View File

@ -6,6 +6,7 @@
package repo
import (
"errors"
"fmt"
"strings"
"time"
@ -274,6 +275,10 @@ func Action(ctx *context.Context) {
err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
case "unstar":
err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
case "accept_transfer":
err = acceptOrRejectRepoTransfer(ctx, true)
case "reject_transfer":
err = acceptOrRejectRepoTransfer(ctx, false)
case "desc": // FIXME: this is not used
if !ctx.Repo.IsOwner() {
ctx.Error(404)
@ -293,6 +298,36 @@ func Action(ctx *context.Context) {
ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink)
}
func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository)
if err != nil {
return err
}
if err := repoTransfer.LoadAttributes(); err != nil {
return err
}
if !repoTransfer.CanUserAcceptTransfer(ctx.User) {
return errors.New("user does not have enough permissions")
}
if accept {
if err := repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil {
return err
}
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success"))
} else {
if err := models.CancelRepositoryTransfer(ctx.Repo.Repository); err != nil {
return err
}
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.rejected"))
}
ctx.Redirect(ctx.Repo.Repository.HTMLURL())
return nil
}
// RedirectDownload return a file based on the following infos:
func RedirectDownload(ctx *context.Context) {
var (

View File

@ -477,18 +477,54 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo.Close()
ctx.Repo.GitRepo = nil
}
if err = repo_service.TransferOwnership(ctx.User, newOwner, repo, nil); err != nil {
if err := repo_service.StartRepositoryTransfer(ctx.User, newOwner, repo, nil); err != nil {
if models.IsErrRepoAlreadyExist(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
} else if models.IsErrRepoTransferInProgress(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
} else {
ctx.ServerError("TransferOwnership", err)
}
return
}
log.Trace("Repository transferred: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
ctx.Redirect(setting.AppSubURL + "/" + newOwner.Name + "/" + repo.Name)
log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName()))
ctx.Redirect(setting.AppSubURL + "/" + ctx.Repo.Owner.Name + "/" + repo.Name + "/settings")
case "cancel_transfer":
if !ctx.Repo.IsOwner() {
ctx.Error(404)
return
}
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository)
if err != nil {
if models.IsErrNoPendingTransfer(err) {
ctx.Flash.Error("repo.settings.transfer_abort_invalid")
ctx.Redirect(setting.AppSubURL + "/" + ctx.User.Name + "/" + repo.Name + "/settings")
} else {
ctx.ServerError("GetPendingRepositoryTransfer", err)
}
return
}
if err := repoTransfer.LoadAttributes(); err != nil {
ctx.ServerError("LoadRecipient", err)
return
}
if err := models.CancelRepositoryTransfer(ctx.Repo.Repository); err != nil {
ctx.ServerError("CancelRepositoryTransfer", err)
return
}
log.Trace("Repository transfer process was cancelled: %s/%s ", ctx.Repo.Owner.Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_abort_success", repoTransfer.Recipient.Name))
ctx.Redirect(setting.AppSubURL + "/" + ctx.Repo.Owner.Name + "/" + repo.Name + "/settings")
case "delete":
if !ctx.Repo.IsOwner() {

View File

@ -586,6 +586,14 @@ func Home(ctx *context.Context) {
return
}
if ctx.IsSigned {
// Set repo notification-status read if unread
if err := ctx.Repo.Repository.ReadBy(ctx.User.ID); err != nil {
ctx.ServerError("ReadBy", err)
return
}
}
var firstUnit *models.Unit
for _, repoUnit := range ctx.Repo.Units {
if repoUnit.Type == models.UnitTypeCode {