API endpoint for repo transfer (#9947)
	
		
	
				
					
				
			* squash * optimize * fail before make any changes * fix-headertokarchuk/v1.17
							parent
							
								
									d816f7018b
								
							
						
					
					
						commit
						13bc82009c
					
				@ -0,0 +1,100 @@ | 
				
			|||||||
 | 
					// 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" | 
				
			||||||
 | 
						repo_service "code.gitea.io/gitea/services/repository" | 
				
			||||||
 | 
					) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Transfer transfers the ownership of a repository
 | 
				
			||||||
 | 
					func Transfer(ctx *context.APIContext, opts api.TransferRepoOption) { | 
				
			||||||
 | 
						// 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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newOwner, err := models.GetUserByName(opts.NewOwner) | 
				
			||||||
 | 
						if err != nil { | 
				
			||||||
 | 
							if models.IsErrUserNotExist(err) { | 
				
			||||||
 | 
								ctx.Error(http.StatusNotFound, "GetUserByName", err) | 
				
			||||||
 | 
								return | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							ctx.InternalServerError(err) | 
				
			||||||
 | 
							return | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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) | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = repo_service.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository, teams); err != nil { | 
				
			||||||
 | 
							ctx.InternalServerError(err) | 
				
			||||||
 | 
							return | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newRepo, err := models.GetRepositoryByName(newOwner.ID, ctx.Repo.Repository.Name) | 
				
			||||||
 | 
						if err != nil { | 
				
			||||||
 | 
							ctx.InternalServerError(err) | 
				
			||||||
 | 
							return | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Trace("Repository transferred: %s -> %s", ctx.Repo.Repository.FullName(), newOwner.Name) | 
				
			||||||
 | 
						ctx.JSON(http.StatusAccepted, newRepo.APIFormat(models.AccessModeAdmin)) | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue