2020-01-31 16:49:04 +01:00
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"fmt"
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
2020-01-31 16:49:04 +01:00
repo_service "code.gitea.io/gitea/services/repository"
)
// Transfer transfers the ownership of a repository
2021-01-26 23:36:53 +08:00
func Transfer ( ctx * context . APIContext ) {
2020-01-31 16:49:04 +01:00
// swagger:operation POST /repos/{owner}/{repo}/transfer repository repoTransfer
// ---
// summary: Transfer a repo ownership
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo to transfer
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo to transfer
// type: string
// required: true
// - name: body
// in: body
// description: "Transfer Options"
// required: true
// schema:
// "$ref": "#/definitions/TransferRepoOption"
// responses:
// "202":
// "$ref": "#/responses/Repository"
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
2021-01-26 23:36:53 +08:00
opts := web . GetForm ( ctx ) . ( * api . TransferRepoOption )
2020-01-31 16:49:04 +01:00
newOwner , err := models . GetUserByName ( opts . NewOwner )
if err != nil {
if models . IsErrUserNotExist ( err ) {
2020-08-16 21:27:08 +01:00
ctx . Error ( http . StatusNotFound , "" , "The new owner does not exist or cannot be found" )
2020-01-31 16:49:04 +01:00
return
}
ctx . InternalServerError ( err )
return
}
2020-08-16 21:27:08 +01:00
if newOwner . Type == models . UserTypeOrganization {
2021-11-08 08:04:13 +01:00
if ! ctx . User . IsAdmin && newOwner . Visibility == api . VisibleTypePrivate && ! newOwner . HasMemberWithUserID ( ctx . User . ID ) {
2020-08-16 21:27:08 +01:00
// The user shouldn't know about this organization
ctx . Error ( http . StatusNotFound , "" , "The new owner does not exist or cannot be found" )
return
}
}
2020-01-31 16:49:04 +01:00
var teams [ ] * models . Team
if opts . TeamIDs != nil {
if ! newOwner . IsOrganization ( ) {
ctx . Error ( http . StatusUnprocessableEntity , "repoTransfer" , "Teams can only be added to organization-owned repositories" )
return
}
org := convert . ToOrganization ( newOwner )
for _ , tID := range * opts . TeamIDs {
team , err := models . GetTeamByID ( tID )
if err != nil {
ctx . Error ( http . StatusUnprocessableEntity , "team" , fmt . Errorf ( "team %d not found" , tID ) )
return
}
if team . OrgID != org . ID {
ctx . Error ( http . StatusForbidden , "team" , fmt . Errorf ( "team %d belongs not to org %d" , tID , org . ID ) )
return
}
teams = append ( teams , team )
}
}
2021-03-01 01:47:30 +01:00
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
}
2020-01-31 16:49:04 +01:00
ctx . InternalServerError ( err )
return
}
2021-03-01 01:47:30 +01:00
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 ) )
2020-01-31 16:49:04 +01:00
return
}
log . Trace ( "Repository transferred: %s -> %s" , ctx . Repo . Repository . FullName ( ) , newOwner . Name )
2021-03-01 01:47:30 +01:00
ctx . JSON ( http . StatusAccepted , convert . ToRepo ( ctx . Repo . Repository , models . AccessModeAdmin ) )
2020-01-31 16:49:04 +01:00
}