diff options
author | 6543 <6543@obermui.de> | 2020-01-31 16:49:04 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-31 15:49:04 +0000 |
commit | 13bc82009c2def4e729f11340e74a14d6c6b32e8 (patch) | |
tree | b545d0af8fdebbddb79fee55b8e643c9f392ff49 /routers | |
parent | d816f7018b0726f868fa0cddf02ffae184601395 (diff) | |
download | gitea-13bc82009c2def4e729f11340e74a14d6c6b32e8.tar.gz gitea-13bc82009c2def4e729f11340e74a14d6c6b32e8.zip |
API endpoint for repo transfer (#9947)
* squash
* optimize
* fail before make any changes
* fix-header
Diffstat (limited to 'routers')
-rw-r--r-- | routers/api/v1/api.go | 1 | ||||
-rw-r--r-- | routers/api/v1/repo/transfer.go | 100 | ||||
-rw-r--r-- | routers/api/v1/swagger/options.go | 2 | ||||
-rw-r--r-- | routers/repo/setting.go | 14 |
4 files changed, 110 insertions, 7 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 4c9f9dd03e..0a352f6e46 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -620,6 +620,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Combo("").Get(reqAnyRepoReader(), repo.Get). Delete(reqToken(), reqOwner(), repo.Delete). Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRef(), repo.Edit) + m.Post("/transfer", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer) m.Combo("/notifications"). Get(reqToken(), notify.ListRepoNotifications). Put(reqToken(), notify.ReadRepoNotifications) diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go new file mode 100644 index 0000000000..847028d106 --- /dev/null +++ b/routers/api/v1/repo/transfer.go @@ -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)) +} diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index 83cbb3a74d..ab697811d0 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -84,6 +84,8 @@ type swaggerParameterBodies struct { // in:body EditRepoOption api.EditRepoOption // in:body + TransferRepoOption api.TransferRepoOption + // in:body CreateForkOption api.CreateForkOption // in:body diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 22699f9e8d..7a2db88c1f 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -369,14 +369,14 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { return } - newOwner := ctx.Query("new_owner_name") - isExist, err := models.IsUserExist(0, newOwner) + newOwner, err := models.GetUserByName(ctx.Query("new_owner_name")) if err != nil { + if models.IsErrUserNotExist(err) { + ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) + return + } ctx.ServerError("IsUserExist", err) return - } else if !isExist { - ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) - return } // Close the GitRepo if open @@ -384,7 +384,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo = nil } - if err = repo_service.TransferOwnership(ctx.User, newOwner, repo); err != nil { + if err = repo_service.TransferOwnership(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 { @@ -395,7 +395,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { 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 + "/" + repo.Name) + ctx.Redirect(setting.AppSubURL + "/" + newOwner.Name + "/" + repo.Name) case "delete": if !ctx.Repo.IsOwner() { |