From dd6d1dbf0f632379e7848577bcb399863fce2c59 Mon Sep 17 00:00:00 2001 From: chenyifan01 Date: Mon, 30 Jan 2023 17:16:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=BB=BA=E9=9D=9E=E5=90=AF=E6=99=BA?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=94=B3=E8=AF=B7=E9=A1=B5=E9=9D=A2=E6=8F=90?= =?UTF-8?q?=E4=BA=A402?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- models/tech_converge_info.go | 72 ++++++++++++++++++-- modules/structs/tech.go | 19 ++++-- options/locale/locale_en-US.ini | 7 ++ options/locale/locale_zh-CN.ini | 8 +++ routers/api/v1/api.go | 2 + routers/api/v1/repo/migrate.go | 142 ++------------------------------------ routers/api/v1/tech/repo.go | 110 +++++++++++++++++++++++++----- routers/response/error.go | 4 ++ services/repository/migrate.go | 146 ++++++++++++++++++++++++++++++++++++++++ services/repository/url.go | 8 ++- services/tech/tech.go | 36 ++++++++++ 11 files changed, 385 insertions(+), 169 deletions(-) create mode 100644 services/repository/migrate.go diff --git a/models/tech_converge_info.go b/models/tech_converge_info.go index d0639e10b..12a315fa2 100644 --- a/models/tech_converge_info.go +++ b/models/tech_converge_info.go @@ -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, + }) +} diff --git a/modules/structs/tech.go b/modules/structs/tech.go index 45738f959..7d3e6d760 100644 --- a/modules/structs/tech.go +++ b/modules/structs/tech.go @@ -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"` //简介 } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 375574132..d067ab266 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -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 diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 66ffb0983..d1f6aeee6 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -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 = 该项目已迁移到启智,请使用启智社区方式提交申请 + diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index fa91ff514..4d92d5ce6 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -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()) diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 2f28b0bd3..74e181a5b 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -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()) } diff --git a/routers/api/v1/tech/repo.go b/routers/api/v1/tech/repo.go index 80e62efa9..91be289da 100644 --- a/routers/api/v1/tech/repo.go +++ b/routers/api/v1/tech/repo.go @@ -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()) } diff --git a/routers/response/error.go b/routers/response/error.go index 685267da9..6b32fe7af 100644 --- a/routers/response/error.go +++ b/routers/response/error.go @@ -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} +} diff --git a/services/repository/migrate.go b/services/repository/migrate.go new file mode 100644 index 000000000..5536981b6 --- /dev/null +++ b/services/repository/migrate.go @@ -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) +} diff --git a/services/repository/url.go b/services/repository/url.go index e688b693e..a7642e0a1 100644 --- a/services/repository/url.go +++ b/services/repository/url.go @@ -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 "", "" } diff --git a/services/tech/tech.go b/services/tech/tech.go index 450a03567..9a4dadbc4 100644 --- a/services/tech/tech.go +++ b/services/tech/tech.go @@ -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 +}