Browse Source

#2924

add migrate submit api
tags/v1.22.11.1^2
chenyifan01 3 years ago
parent
commit
dd0adb0893
8 changed files with 310 additions and 0 deletions
  1. +1
    -0
      models/repo.go
  2. +1
    -0
      modules/convert/convert.go
  3. +1
    -0
      modules/structs/org.go
  4. +1
    -0
      modules/structs/repo.go
  5. +155
    -0
      routers/api/v1/admin/migrate_submit.go
  6. +1
    -0
      routers/api/v1/api.go
  7. +144
    -0
      routers/api/v1/repo/migrate.go
  8. +6
    -0
      routers/response/response_list.go

+ 1
- 0
models/repo.go View File

@@ -454,6 +454,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
AllowRebaseMerge: allowRebaseMerge,
AllowSquash: allowSquash,
AvatarURL: repo.avatarLink(e),
Status: int(repo.Status),
}
}



+ 1
- 0
modules/convert/convert.go View File

@@ -311,6 +311,7 @@ func ToOrganization(org *models.User) *api.Organization {
Location: org.Location,
Visibility: org.Visibility.String(),
RepoAdminChangeTeamAccess: org.RepoAdminChangeTeamAccess,
NumRepos: org.NumRepos,
}
}



+ 1
- 0
modules/structs/org.go View File

@@ -15,6 +15,7 @@ type Organization struct {
Location string `json:"location"`
Visibility string `json:"visibility"`
RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"`
NumRepos int `json:"num_repos"`
}

// CreateOrgOption options for creating an organization


+ 1
- 0
modules/structs/repo.go View File

@@ -90,6 +90,7 @@ type Repository struct {
AllowRebaseMerge bool `json:"allow_rebase_explicit"`
AllowSquash bool `json:"allow_squash_merge"`
AvatarURL string `json:"avatar_url"`
Status int `json:"status"`
}

// CreateRepoOption options when creating repository


+ 155
- 0
routers/api/v1/admin/migrate_submit.go View File

@@ -0,0 +1,155 @@
package admin

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/migrations"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/task"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/response"
"fmt"
"net/http"
"net/url"
"strings"
)

func MigrateSubmit(ctx *context.APIContext, form auth.MigrateRepoForm) {
ctxUser, bizErr := checkContextUser(ctx, form.UID)
if bizErr != nil {
ctx.JSON(http.StatusOK, response.ResponseError(bizErr))
return
}

remoteAddr, err := form.ParseRemoteAddr(ctx.User)
if err != nil {
if models.IsErrInvalidCloneAddr(err) {
addrErr := err.(models.ErrInvalidCloneAddr)
switch {
case addrErr.IsURLError:
ctx.JSON(http.StatusOK, response.PARAM_ERROR)
case addrErr.IsPermissionDenied:
ctx.JSON(http.StatusOK, response.INSUFFICIENT_PERMISSION)
case addrErr.IsInvalidPath:
ctx.JSON(http.StatusOK, response.PARAM_ERROR)
default:
ctx.JSON(http.StatusOK, response.SYSTEM_ERROR)
}
} else {
ctx.JSON(http.StatusOK, response.SYSTEM_ERROR)
}
return
}

var gitServiceType = structs.PlainGitService
u, err := url.Parse(form.CloneAddr)
if err == nil && strings.EqualFold(u.Host, "github.com") {
gitServiceType = structs.GithubService
}

var opts = migrations.MigrateOptions{
OriginalURL: form.CloneAddr,
GitServiceType: gitServiceType,
CloneAddr: remoteAddr,
RepoName: form.RepoName,
Alias: form.Alias,
Description: form.Description,
Private: form.Private || setting.Repository.ForcePrivate,
Mirror: form.Mirror,
AuthUsername: form.AuthUsername,
AuthPassword: form.AuthPassword,
Wiki: form.Wiki,
Issues: form.Issues,
Milestones: form.Milestones,
Labels: form.Labels,
Comments: true,
PullRequests: form.PullRequests,
Releases: form.Releases,
}
if opts.Mirror {
opts.Issues = false
opts.Milestones = false
opts.Labels = false
opts.Comments = false
opts.PullRequests = false
opts.Releases = false
}

err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, opts.Alias)
if err != nil {
handleMigrateError(ctx, ctxUser, remoteAddr, err)
return
}

err = task.MigrateRepository(ctx.User, ctxUser, opts)
if err == nil {
r := make(map[string]string)
r["OpenIUrl"] = strings.TrimSuffix(setting.AppURL, "/") + "/" + ctxUser.Name + "/" + opts.RepoName
r["OriginUrl"] = form.CloneAddr
ctx.JSON(http.StatusOK, response.SuccessWithData(r))
return
}

handleMigrateError(ctx, ctxUser, remoteAddr, err)
}

func checkContextUser(ctx *context.APIContext, uid int64) (*models.User, *response.BizError) {
if uid == ctx.User.ID || uid == 0 {
return ctx.User, nil
}

org, err := models.GetUserByID(uid)
if models.IsErrUserNotExist(err) {
return ctx.User, nil
}

if err != nil {
return nil, response.SYSTEM_ERROR
}

// Check ownership of organization.
if !org.IsOrganization() {
return nil, nil
}
if !ctx.User.IsAdmin {
canCreate, err := org.CanCreateOrgRepo(ctx.User.ID)
if err != nil {
return nil, response.NewBizError(err)
} else if !canCreate {
return nil, response.INSUFFICIENT_PERMISSION
}
}
return org, nil
}

func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteAddr string, err error) {
switch {
case models.IsErrRepoAlreadyExist(err):
ctx.JSON(http.StatusOK, response.ServerError("The repository with the same name already exists."))
case migrations.IsRateLimitError(err):
ctx.JSON(http.StatusOK, response.ServerError("Remote visit addressed rate limitation."))
case migrations.IsTwoFactorAuthError(err):
ctx.JSON(http.StatusOK, response.ServerError("Remote visit required two factors authentication."))
case models.IsErrReachLimitOfRepo(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit())))
case models.IsErrNameReserved(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("The username '%s' is reserved.", err.(models.ErrNameReserved).Name)))
case models.IsErrNameCharsNotAllowed(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("The username '%s' contains invalid characters.", err.(models.ErrNameCharsNotAllowed).Name)))
case models.IsErrNamePatternNotAllowed(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern)))
default:
err = util.URLSanitizedError(err, remoteAddr)
if strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "Bad credentials") ||
strings.Contains(err.Error(), "could not read Username") {
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("Authentication failed: %v.", err)))
} else if strings.Contains(err.Error(), "fatal:") {
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("Migration failed: %v.", err)))
} else {
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
}
}
}

+ 1
- 0
routers/api/v1/api.go View File

@@ -702,6 +702,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/issues/search", repo.SearchIssues)

m.Post("/migrate", reqToken(), bind(auth.MigrateRepoForm{}), repo.Migrate)
m.Post("/migrate/submit", reqToken(), bind(auth.MigrateRepoForm{}), repo.MigrateSubmit)

m.Group("/:username/:reponame", func() {
m.Combo("").Get(reqAnyRepoReader(), repo.Get).


+ 144
- 0
routers/api/v1/repo/migrate.go View File

@@ -6,6 +6,8 @@ package repo

import (
"bytes"
"code.gitea.io/gitea/modules/task"
"code.gitea.io/gitea/routers/response"
"errors"
"fmt"
"net/http"
@@ -216,3 +218,145 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA
}
}
}

func MigrateSubmit(ctx *context.APIContext, form auth.MigrateRepoForm) {
ctxUser, bizErr := checkContextUser(ctx, form.UID)
if bizErr != nil {
ctx.JSON(http.StatusOK, response.ResponseError(bizErr))
return
}

remoteAddr, err := form.ParseRemoteAddr(ctx.User)
if err != nil {
if models.IsErrInvalidCloneAddr(err) {
addrErr := err.(models.ErrInvalidCloneAddr)
switch {
case addrErr.IsURLError:
ctx.JSON(http.StatusOK, response.PARAM_ERROR)
case addrErr.IsPermissionDenied:
ctx.JSON(http.StatusOK, response.INSUFFICIENT_PERMISSION)
case addrErr.IsInvalidPath:
ctx.JSON(http.StatusOK, response.PARAM_ERROR)
default:
ctx.JSON(http.StatusOK, response.SYSTEM_ERROR)
}
} else {
ctx.JSON(http.StatusOK, response.SYSTEM_ERROR)
}
return
}

var gitServiceType = api.PlainGitService
u, err := url.Parse(form.CloneAddr)
if err == nil && strings.EqualFold(u.Host, "github.com") {
gitServiceType = api.GithubService
}

var opts = migrations.MigrateOptions{
OriginalURL: form.CloneAddr,
GitServiceType: gitServiceType,
CloneAddr: remoteAddr,
RepoName: form.RepoName,
Alias: form.Alias,
Description: form.Description,
Private: form.Private || setting.Repository.ForcePrivate,
Mirror: form.Mirror,
AuthUsername: form.AuthUsername,
AuthPassword: form.AuthPassword,
Wiki: form.Wiki,
Issues: form.Issues,
Milestones: form.Milestones,
Labels: form.Labels,
Comments: true,
PullRequests: form.PullRequests,
Releases: form.Releases,
}
if opts.Mirror {
opts.Issues = false
opts.Milestones = false
opts.Labels = false
opts.Comments = false
opts.PullRequests = false
opts.Releases = false
}

err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, opts.Alias)
if err != nil {
handleMigrateError4Api(ctx, ctxUser, remoteAddr, err)
return
}

err = task.MigrateRepository(ctx.User, ctxUser, opts)
if err == nil {
r := make(map[string]string)
r["OpenIUrl"] = strings.TrimSuffix(setting.AppURL, "/") + "/" + ctxUser.Name + "/" + opts.RepoName
r["OriginUrl"] = form.CloneAddr
ctx.JSON(http.StatusOK, response.SuccessWithData(r))
return
}

handleMigrateError4Api(ctx, ctxUser, remoteAddr, err)
}

func checkContextUser(ctx *context.APIContext, uid int64) (*models.User, *response.BizError) {
if uid == ctx.User.ID || uid == 0 {
return ctx.User, nil
}

org, err := models.GetUserByID(uid)
if models.IsErrUserNotExist(err) {
return ctx.User, nil
}

if err != nil {
return nil, response.SYSTEM_ERROR
}

// Check ownership of organization.
if !org.IsOrganization() {
return nil, nil
}
if !ctx.User.IsAdmin {
canCreate, err := org.CanCreateOrgRepo(ctx.User.ID)
if err != nil {
return nil, response.NewBizError(err)
} else if !canCreate {
return nil, response.INSUFFICIENT_PERMISSION
}
}
return org, nil
}

func handleMigrateError4Api(ctx *context.APIContext, repoOwner *models.User, remoteAddr string, err error) {
switch {
case models.IsErrRepoAlreadyExist(err):
ctx.JSON(http.StatusOK, response.Error(3, "The repository with the same name already exists."))
case migrations.IsRateLimitError(err):
ctx.JSON(http.StatusOK, response.ServerError("Remote visit addressed rate limitation."))
case migrations.IsTwoFactorAuthError(err):
ctx.JSON(http.StatusOK, response.ServerError("Remote visit required two factors authentication."))
case models.IsErrReachLimitOfRepo(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit())))
case models.IsErrNameReserved(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("The username '%s' is reserved.", err.(models.ErrNameReserved).Name)))
case models.IsErrNameCharsNotAllowed(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("The username '%s' contains invalid characters.", err.(models.ErrNameCharsNotAllowed).Name)))
case models.IsErrNamePatternNotAllowed(err):
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern)))
default:
err = util.URLSanitizedError(err, remoteAddr)
if strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "Bad credentials") ||
strings.Contains(err.Error(), "could not read Username") {
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("Authentication failed: %v.", err)))
} else if strings.Contains(err.Error(), "fatal:") {
ctx.JSON(http.StatusOK, response.ServerError(fmt.Sprintf("Migration failed: %v.", err)))
} else {
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
}
}
}

func QueryRepoSatus(ctx *context.APIContext, form auth.MigrateRepoForm) {

}

+ 6
- 0
routers/response/response_list.go View File

@@ -1,5 +1,11 @@
package response

//repo response
var RESOURCE_QUEUE_NOT_AVAILABLE = &BizError{Code: 1001, Err: "resource queue not available"}
var SPECIFICATION_NOT_EXIST = &BizError{Code: 1002, Err: "specification not exist"}
var SPECIFICATION_NOT_AVAILABLE = &BizError{Code: 1003, Err: "specification not available"}

//common response
var SYSTEM_ERROR = &BizError{Code: 9009, Err: "System error.Please try again later"}
var INSUFFICIENT_PERMISSION = &BizError{Code: 9003, Err: "insufficient permissions"}
var PARAM_ERROR = &BizError{Code: 9001, Err: "param error permissions"}

Loading…
Cancel
Save