@@ -1,7 +1,6 @@ | |||
package models | |||
import ( | |||
"fmt" | |||
"strconv" | |||
"strings" | |||
"time" | |||
@@ -17,7 +16,7 @@ const ( | |||
TechMigrateFailed = 4 | |||
) | |||
const DefaultTechStatus = 2 | |||
const DefaultTechApprovedStatus = TechShow | |||
type TechConvergeBaseInfo struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
@@ -61,6 +60,35 @@ func (t *TechConvergeBaseInfo) Brief() *TechConvergeBrief { | |||
AllInstitution: t.AllInstitution, | |||
} | |||
} | |||
func (t *TechConvergeBaseInfo) IsValidInstitution(institution string) bool { | |||
if t.AllInstitution == "" && t.Institution == "" { | |||
return false | |||
} | |||
allInstitution := make([]string, 0) | |||
if t.AllInstitution != "" { | |||
allInstitution = strings.Split(t.AllInstitution, ",") | |||
} | |||
if t.Institution != "" { | |||
allInstitution = append(allInstitution, t.Institution) | |||
} | |||
newInstitution := strings.Split(institution, ",") | |||
total := len(newInstitution) | |||
matched := 0 | |||
for _, n := range newInstitution { | |||
for _, s := range allInstitution { | |||
if s == n { | |||
matched++ | |||
break | |||
} | |||
} | |||
} | |||
if matched == total { | |||
return true | |||
} | |||
return false | |||
} | |||
type RepoConvergeInfo struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
@@ -106,7 +134,7 @@ type ErrTechConvergeBaseInfoNotExist struct { | |||
} | |||
func (err ErrTechConvergeBaseInfoNotExist) Error() string { | |||
return fmt.Sprintf("TechConvergeBaseInfo does not exist [id: %s]", err.ID) | |||
return "tech.tech_not_exist" | |||
} | |||
func IsErrTechConvergeBaseInfoNotExist(err error) bool { | |||
@@ -269,7 +297,7 @@ type FindTechOpt struct { | |||
} | |||
func FindTech(opt FindTechOpt) ([]*TechConvergeBaseInfo, error) { | |||
var cond builder.Cond | |||
var cond = builder.NewCond() | |||
if opt.TechNo != "" { | |||
cond = cond.And(builder.Like{"project_number", opt.TechNo}) | |||
} | |||
@@ -289,8 +317,8 @@ func FindTech(opt FindTechOpt) ([]*TechConvergeBaseInfo, error) { | |||
} | |||
func GetTechByTechNo(techNo string) (*TechConvergeBaseInfo, error) { | |||
var tech *TechConvergeBaseInfo | |||
has, err := x.Where("project_number = ?", techNo).Get(&tech) | |||
var tech = &TechConvergeBaseInfo{} | |||
has, err := x.Where("project_number = ?", techNo).Get(tech) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
@@ -299,3 +327,35 @@ func GetTechByTechNo(techNo string) (*TechConvergeBaseInfo, error) { | |||
return tech, nil | |||
} | |||
type GetRepoConvergeOpts struct { | |||
RepoId int64 | |||
BaseInfoId int64 | |||
Status []int | |||
} | |||
func GetRepoConverge(opts GetRepoConvergeOpts) ([]*RepoConvergeInfo, error) { | |||
r := make([]*RepoConvergeInfo, 0) | |||
cond := builder.NewCond() | |||
if opts.RepoId > 0 { | |||
cond = cond.And(builder.Eq{"repo_id": opts.RepoId}) | |||
} | |||
if opts.BaseInfoId > 0 { | |||
cond = cond.And(builder.Eq{"base_info_id": opts.BaseInfoId}) | |||
} | |||
if len(opts.Status) > 0 { | |||
cond = cond.And(builder.In("status", opts.Status)) | |||
} | |||
err := x.Where(cond).Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} | |||
func UpdateRepoConvergeStatus(id int64, status int) (int64, error) { | |||
return x.ID(id).Update(&RepoConvergeInfo{ | |||
Status: status, | |||
}) | |||
} |
@@ -1,11 +1,18 @@ | |||
package structs | |||
type TechRepo struct { | |||
Url string `json:"url"` | |||
type NotOpenITechRepo struct { | |||
Url string `json:"url" binding:"Required"` | |||
TechNo string `json:"no"` | |||
Institution string `json:"institution"` | |||
UID int64 `json:"uid"` //启智项目uid | |||
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"` | |||
Alias string `json:"alias" binding:"Required;AlphaDashDotChinese;MaxSize(100)"` | |||
Topics string `json:"topics"` //关键词 | |||
Description string `json:"description" binding:"MaxSize(255)"` | |||
} | |||
type OpenITechRepo struct { | |||
Url string `json:"url" binding:"Required"` | |||
TechNo string `json:"no"` | |||
Institution string `json:"institution"` | |||
uid string `json:"uid"` //启智项目uid | |||
repo_name string `json:"repo_name"` //启智项目名称 | |||
topics string `json:"topics"` //关键词 | |||
description string `json:"description"` //简介 | |||
} |
@@ -3363,3 +3363,10 @@ get_file_fail= Can not get the file content, please try again later. | |||
content_type_unsupported=The format of the file or file content is wrong. | |||
sql_err=Fail to process data, please try again later. | |||
[tech] | |||
incorrect_openi_format = The OpenI address format is incorrect | |||
openi_repo_not_exist = OpenI repository is not exists | |||
tech_not_exist = The project approval number does not exist | |||
institution_not_valid = The submitted contributing unit is not among the participating units of the technology project | |||
repo_converge_exists = The technology project [%s] already has [%s], please do not submit it again | |||
to_migrate_repo_exists = The project has been migrated to OpenI, please use the OpenI way to submit |
@@ -3383,5 +3383,13 @@ get_file_fail= 获取上传文件失败。 | |||
content_type_unsupported=上传文件的格式有误。 | |||
sql_err=数据处理错误,请稍后再试。 | |||
[tech] | |||
incorrect_openi_format = 启智项目地址格式错误 | |||
openi_repo_not_exist = 启智项目不存在 | |||
tech_not_exist = 项目立项编号不存在 | |||
institution_not_valid = 当前提交的贡献单位不在该科技项目的参与单位中 | |||
repo_converge_exists = 科技项目[%s]中已存在[%s],请勿重复提交 | |||
to_migrate_repo_exists = 该项目已迁移到启智,请使用启智社区方式提交申请 | |||
@@ -543,6 +543,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/filter", tech.GetFilterInfo) | |||
m.Get("/search", tech.SearchTechProjectInfo) | |||
m.Get("/repo_search", tech.SearchRepoInfo) | |||
m.Post("/openi", bind(api.OpenITechRepo{}), tech.CommitOpenIRepo) | |||
m.Post("/no_openi", bind(api.NotOpenITechRepo{}), tech.CommitNotOpenIRepo) | |||
}, reqToken()) | |||
@@ -6,8 +6,8 @@ package repo | |||
import ( | |||
"bytes" | |||
"code.gitea.io/gitea/modules/task" | |||
"code.gitea.io/gitea/routers/response" | |||
"code.gitea.io/gitea/services/repository" | |||
"errors" | |||
"fmt" | |||
"net/http" | |||
@@ -221,143 +221,9 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA | |||
func MigrateSubmit(ctx *context.APIContext, form auth.MigrateRepoForm) { | |||
log.Info("receive MigrateSubmit request") | |||
ctxUser, bizErr := checkContextUser(ctx, form.UID) | |||
if bizErr != nil { | |||
ctx.JSON(http.StatusOK, response.ResponseError(bizErr)) | |||
return | |||
} | |||
remoteAddr, err := form.ParseRemoteAddr(ctx.User) | |||
err := repository.MigrateSubmit(ctx.User, form) | |||
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, | |||
ctx.JSON(http.StatusOK, err) | |||
} | |||
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) { | |||
ctx.JSON(http.StatusOK, response.Success()) | |||
} |
@@ -2,25 +2,45 @@ package tech | |||
import ( | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/auth" | |||
"code.gitea.io/gitea/modules/context" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/routers/response" | |||
"code.gitea.io/gitea/services/repository" | |||
techService "code.gitea.io/gitea/services/tech" | |||
"fmt" | |||
"net/http" | |||
) | |||
//CommitOpenIRepo 新建启智项目申请页面提交 | |||
func CommitOpenIRepo(ctx *context.APIContext, form api.TechRepo) { | |||
func CommitOpenIRepo(ctx *context.APIContext, form api.OpenITechRepo) { | |||
//解析项目路径,查找项目 | |||
repo, err := repository.FindRepoByUrl(form.Url) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(err.Error())) | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
//查找项目编号 | |||
tech, err := models.GetTechByTechNo(form.TechNo) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(err.Error())) | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
//判断承接单位是否在科技项目的参与单位中 | |||
if !tech.IsValidInstitution(form.Institution) { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr("tech.institution_not_valid"))) | |||
return | |||
} | |||
//判断是否已经存在了该项目 | |||
exist, err := techService.IsValidRepoConvergeExists(repo.ID, tech.ID) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
if exist { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(fmt.Sprintf(ctx.Tr("tech.repo_converge_exists"), tech.ProjectName, repo.Alias))) | |||
return | |||
} | |||
@@ -31,27 +51,83 @@ func CommitOpenIRepo(ctx *context.APIContext, form api.TechRepo) { | |||
BaseInfoID: tech.ID, | |||
Institution: form.Institution, | |||
UID: ctx.User.ID, | |||
Status: models.DefaultTechStatus, | |||
Status: models.DefaultTechApprovedStatus, | |||
} | |||
err = rci.InsertOrUpdate() | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(err.Error())) | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
ctx.JSON(http.StatusOK, response.OuterSuccess()) | |||
return | |||
} | |||
//CommitNotOpenIRepo 新建非启智项目申请页面提交 | |||
func CommitNotOpenIRepo(ctx *context.APIContext, form api.TechRepo) { | |||
////查找项目编号 | |||
//tech, err := models.GetTechByTechNo(form.TechNo) | |||
//if err != nil { | |||
// ctx.JSON(http.StatusOK, response.OuterServerError(err.Error())) | |||
// return | |||
//} | |||
// | |||
////调用迁移接口 | |||
return | |||
func CommitNotOpenIRepo(ctx *context.APIContext, form api.NotOpenITechRepo) { | |||
//触发更新迁移状态 | |||
go techService.UpdateTechMigrateStatus() | |||
//查找项目编号 | |||
tech, err := models.GetTechByTechNo(form.TechNo) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
//判断承接单位是否在科技项目的参与单位中 | |||
if !tech.IsValidInstitution(form.Institution) { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr("tech.institution_not_valid"))) | |||
return | |||
} | |||
//调用迁移接口 | |||
bizErr := repository.MigrateSubmit(ctx.User, auth.MigrateRepoForm{ | |||
CloneAddr: form.Url, | |||
UID: form.UID, | |||
RepoName: form.RepoName, | |||
Alias: form.Alias, | |||
Description: form.Description, | |||
Labels: true, | |||
Mirror: true, | |||
}) | |||
if bizErr != nil { | |||
if bizErr.Code == 3 { | |||
ctx.JSON(http.StatusOK, response.OuterError(bizErr.Code, ctx.Tr("tech.to_migrate_repo_exists"))) | |||
return | |||
} | |||
ctx.JSON(http.StatusOK, response.OuterError(bizErr.Code, ctx.Tr(bizErr.Err))) | |||
return | |||
} | |||
repo, err := models.GetRepositoryByName(form.UID, form.RepoName) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
//判断是否已经存在了该项目 | |||
exist, err := techService.IsValidRepoConvergeExists(repo.ID, tech.ID) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
if exist { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(fmt.Sprintf(ctx.Tr("tech.repo_converge_exists"), tech.ProjectName, repo.Alias))) | |||
return | |||
} | |||
//写入数据库 | |||
rci := &models.RepoConvergeInfo{ | |||
RepoID: repo.ID, | |||
Url: form.Url, | |||
BaseInfoID: tech.ID, | |||
Institution: form.Institution, | |||
UID: ctx.User.ID, | |||
Status: models.DefaultTechApprovedStatus, | |||
} | |||
err = rci.InsertOrUpdate() | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, response.OuterServerError(ctx.Tr(err.Error()))) | |||
return | |||
} | |||
ctx.JSON(http.StatusOK, response.OuterSuccess()) | |||
} |
@@ -12,3 +12,7 @@ func (b BizError) Error() string { | |||
func NewBizError(err error) *BizError { | |||
return &BizError{Code: RESPONSE_CODE_ERROR_DEFAULT, Err: err.Error()} | |||
} | |||
func BuildBizError(code int, msg string) *BizError { | |||
return &BizError{Code: code, Err: msg} | |||
} |
@@ -0,0 +1,146 @@ | |||
package repository | |||
import ( | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/auth" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/migrations" | |||
"code.gitea.io/gitea/modules/setting" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/task" | |||
"code.gitea.io/gitea/modules/util" | |||
"code.gitea.io/gitea/routers/response" | |||
"errors" | |||
"fmt" | |||
"net/url" | |||
"strings" | |||
) | |||
func MigrateSubmit(currentUser *models.User, form auth.MigrateRepoForm) *response.BizError { | |||
log.Info("receive MigrateSubmit request") | |||
ctxUser, bizErr := checkMigrateUser(currentUser, form.UID) | |||
if bizErr != nil { | |||
return bizErr | |||
} | |||
remoteAddr, err := form.ParseRemoteAddr(currentUser) | |||
if err != nil { | |||
if models.IsErrInvalidCloneAddr(err) { | |||
addrErr := err.(models.ErrInvalidCloneAddr) | |||
switch { | |||
case addrErr.IsURLError: | |||
return response.PARAM_ERROR | |||
case addrErr.IsPermissionDenied: | |||
return response.INSUFFICIENT_PERMISSION | |||
case addrErr.IsInvalidPath: | |||
return response.PARAM_ERROR | |||
default: | |||
} | |||
} | |||
return response.NewBizError(err) | |||
} | |||
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(currentUser, ctxUser, opts.RepoName, opts.Alias) | |||
if err != nil { | |||
return handleMigrateError4Api(ctxUser, remoteAddr, err) | |||
} | |||
err = task.MigrateRepository(currentUser, ctxUser, opts) | |||
if err != nil { | |||
return handleMigrateError4Api(ctxUser, remoteAddr, err) | |||
} | |||
return nil | |||
} | |||
func checkMigrateUser(currentUser *models.User, uid int64) (*models.User, *response.BizError) { | |||
if uid == currentUser.ID || uid == 0 { | |||
return currentUser, nil | |||
} | |||
org, err := models.GetUserByID(uid) | |||
if models.IsErrUserNotExist(err) { | |||
return currentUser, nil | |||
} | |||
if err != nil { | |||
return nil, response.SYSTEM_ERROR | |||
} | |||
// Check ownership of organization. | |||
if !org.IsOrganization() { | |||
return nil, nil | |||
} | |||
if !currentUser.IsAdmin { | |||
canCreate, err := org.CanCreateOrgRepo(currentUser.ID) | |||
if err != nil { | |||
return nil, response.NewBizError(err) | |||
} else if !canCreate { | |||
return nil, response.INSUFFICIENT_PERMISSION | |||
} | |||
} | |||
return org, nil | |||
} | |||
func handleMigrateError4Api(repoOwner *models.User, remoteAddr string, err error) *response.BizError { | |||
switch { | |||
case models.IsErrRepoAlreadyExist(err): | |||
return response.BuildBizError(3, "The repository with the same name already exists.") | |||
case migrations.IsRateLimitError(err): | |||
return response.NewBizError(errors.New("Remote visit addressed rate limitation.")) | |||
case migrations.IsTwoFactorAuthError(err): | |||
return response.NewBizError(errors.New("Remote visit required two factors authentication.")) | |||
case models.IsErrReachLimitOfRepo(err): | |||
return response.NewBizError(errors.New(fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit()))) | |||
case models.IsErrNameReserved(err): | |||
return response.NewBizError(errors.New(fmt.Sprintf("The username '%s' is reserved.", err.(models.ErrNameReserved).Name))) | |||
case models.IsErrNameCharsNotAllowed(err): | |||
return response.NewBizError(errors.New(fmt.Sprintf("The username '%s' contains invalid characters.", err.(models.ErrNameCharsNotAllowed).Name))) | |||
case models.IsErrNamePatternNotAllowed(err): | |||
return response.NewBizError(errors.New(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") { | |||
return response.NewBizError(errors.New((fmt.Sprintf("Authentication failed: %v.", err)))) | |||
} else if strings.Contains(err.Error(), "fatal:") { | |||
return response.NewBizError(errors.New((fmt.Sprintf("Migration failed: %v.", err)))) | |||
} | |||
} | |||
return response.NewBizError(err) | |||
} |
@@ -3,6 +3,7 @@ package repository | |||
import ( | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/setting" | |||
"errors" | |||
"net/url" | |||
"strings" | |||
) | |||
@@ -10,10 +11,13 @@ import ( | |||
func FindRepoByUrl(url string) (*models.Repository, error) { | |||
ownerName, repoName := parseOpenIUrl(url) | |||
if ownerName == "" || repoName == "" { | |||
return nil, nil | |||
return nil, errors.New("tech.incorrect_openi_format") | |||
} | |||
r, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) | |||
if err != nil { | |||
if models.IsErrRepoNotExist(err) { | |||
return nil, errors.New("tech.openi_repo_not_exist") | |||
} | |||
return nil, err | |||
} | |||
return r, nil | |||
@@ -25,7 +29,7 @@ func parseOpenIUrl(u string) (string, string) { | |||
if err != nil { | |||
return "", "" | |||
} | |||
if url.Host != setting.AppURL { | |||
if !strings.Contains(setting.AppURL, url.Host) { | |||
return "", "" | |||
} | |||
@@ -13,3 +13,39 @@ func FindTech(opt models.FindTechOpt) ([]*models.TechConvergeBrief, error) { | |||
} | |||
return r, nil | |||
} | |||
func IsValidRepoConvergeExists(repoId, baseInfoId int64) (bool, error) { | |||
list, err := models.GetRepoConverge(models.GetRepoConvergeOpts{ | |||
Status: []int{models.TechHide, models.TechShow, models.TechMigrating}, | |||
RepoId: repoId, | |||
BaseInfoId: baseInfoId, | |||
}) | |||
if err != nil { | |||
return false, err | |||
} | |||
return len(list) > 0, nil | |||
} | |||
func UpdateTechMigrateStatus() error { | |||
migratingRepos, err := models.GetRepoConverge(models.GetRepoConvergeOpts{ | |||
Status: []int{models.TechMigrating}, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
for _, r := range migratingRepos { | |||
repo, err := models.GetRepositoryByID(r.RepoID) | |||
if err != nil { | |||
if models.IsErrRepoNotExist(err) { | |||
models.UpdateRepoConvergeStatus(r.ID, models.TechMigrateFailed) | |||
continue | |||
} | |||
continue | |||
} | |||
if repo.Status == models.RepositoryReady { | |||
models.UpdateRepoConvergeStatus(r.ID, models.DefaultTechApprovedStatus) | |||
continue | |||
} | |||
} | |||
return nil | |||
} |