From dd0adb089376d98308eb971590788869c9874c3e Mon Sep 17 00:00:00 2001 From: chenyifan01 Date: Fri, 21 Oct 2022 17:50:05 +0800 Subject: [PATCH 01/11] #2924 add migrate submit api --- models/repo.go | 1 + modules/convert/convert.go | 1 + modules/structs/org.go | 1 + modules/structs/repo.go | 1 + routers/api/v1/admin/migrate_submit.go | 155 +++++++++++++++++++++++++++++++++ routers/api/v1/api.go | 1 + routers/api/v1/repo/migrate.go | 144 ++++++++++++++++++++++++++++++ routers/response/response_list.go | 6 ++ 8 files changed, 310 insertions(+) create mode 100644 routers/api/v1/admin/migrate_submit.go diff --git a/models/repo.go b/models/repo.go index 2c4fda39b..6009c776f 100755 --- a/models/repo.go +++ b/models/repo.go @@ -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), } } diff --git a/modules/convert/convert.go b/modules/convert/convert.go index a542fe78b..9eb2c519d 100755 --- a/modules/convert/convert.go +++ b/modules/convert/convert.go @@ -311,6 +311,7 @@ func ToOrganization(org *models.User) *api.Organization { Location: org.Location, Visibility: org.Visibility.String(), RepoAdminChangeTeamAccess: org.RepoAdminChangeTeamAccess, + NumRepos: org.NumRepos, } } diff --git a/modules/structs/org.go b/modules/structs/org.go index 4b79a4e70..191843f87 100644 --- a/modules/structs/org.go +++ b/modules/structs/org.go @@ -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 diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 6e9ece4b0..03741d03b 100755 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -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 diff --git a/routers/api/v1/admin/migrate_submit.go b/routers/api/v1/admin/migrate_submit.go new file mode 100644 index 000000000..7680de0a0 --- /dev/null +++ b/routers/api/v1/admin/migrate_submit.go @@ -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())) + } + } +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 8e1d725ed..4160c2430 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -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). diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index fd0db7814..ed6ca69e2 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -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) { + +} diff --git a/routers/response/response_list.go b/routers/response/response_list.go index 6514f3edd..138b0e294 100644 --- a/routers/response/response_list.go +++ b/routers/response/response_list.go @@ -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"} From 7e07546f565c3f77d1ce24e953d2d962e233b1cb Mon Sep 17 00:00:00 2001 From: chenyifan01 Date: Wed, 26 Oct 2022 09:56:46 +0800 Subject: [PATCH 02/11] add log --- routers/api/v1/repo/migrate.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index ed6ca69e2..2f28b0bd3 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -220,6 +220,7 @@ 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)) From 76235195960ab724561f43d600d6ab3baf12f4a7 Mon Sep 17 00:00:00 2001 From: zhoupzh Date: Mon, 31 Oct 2022 18:27:16 +0800 Subject: [PATCH 03/11] fix issue --- options/locale/locale_en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 3d99ae138..9fa51fd8e 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1217,7 +1217,7 @@ cloudbrain.benchmark.evaluate_train=Train Script cloudbrain.benchmark.evaluate_test=Test Script cloudbrain.benchmark.types={"type":[{"id":1,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=detection","first":"Target detection","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=reid","first":"Target re-identification","second":[{"id":1,"value":"Vehicle re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"Image-based person re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=tracking","first":"Multi-target tracking","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]} cloudbrain.morethanonejob=You already have a running or waiting task, create it after that task is over. -cloudbrain.morethanonejob1=You have created a equivalent task that is waiting or running, please wait for the task to finish before creating it. +cloudbrain.morethanonejob1=You have created an equivalent task that is waiting or running, please wait for the task to finish before creating it. cloudbrain.morethanonejob2=You can view all your Cloud Brain tasks in Home > Cloudbrain Task . modelarts.infer_job_model = Model From b873b1edfe55964fb5de9e8598d2f3f8c3e05ded Mon Sep 17 00:00:00 2001 From: zhoupzh Date: Tue, 1 Nov 2022 09:52:07 +0800 Subject: [PATCH 04/11] fix issue --- templates/custom/max_log.tmpl | 6 +++--- templates/repo/grampus/trainjob/show.tmpl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/custom/max_log.tmpl b/templates/custom/max_log.tmpl index 5e4a99905..8dabb65b1 100644 --- a/templates/custom/max_log.tmpl +++ b/templates/custom/max_log.tmpl @@ -1,11 +1,11 @@
-
- \ No newline at end of file + + \ No newline at end of file diff --git a/web_src/js/features/cloudrbanin.js b/web_src/js/features/cloudrbanin.js index c5fb6cdc4..b2c4869da 100644 --- a/web_src/js/features/cloudrbanin.js +++ b/web_src/js/features/cloudrbanin.js @@ -529,7 +529,7 @@ function userSearchControll() { : params.get("jobStatus").toUpperCase(); const dropdownValueArray = [cluster, aiCenter, jobType, listType, jobStatus]; $("#userCloud .default.text ").each(function (index, e) { - $(e).text(dropdownValueArray[index]); + index != 1 && $(e).text(dropdownValueArray[index]); }); } @@ -564,7 +564,7 @@ function AdaminSearchControll() { : params.get("jobStatus").toUpperCase(); const dropdownValueArray = [cluster, aiCenter, jobType, listType, jobStatus]; $("#adminCloud .default.text ").each(function (index, e) { - $(e).text(dropdownValueArray[index]); + index != 1 && $(e).text(dropdownValueArray[index]); }); } userSearchControll(); From d5e040c7f29317ea4a4349544d904400d3e91a09 Mon Sep 17 00:00:00 2001 From: zhoupzh Date: Tue, 1 Nov 2022 15:57:53 +0800 Subject: [PATCH 11/11] fix issue --- web_src/js/features/cloudbrainShow.js | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/cloudbrainShow.js b/web_src/js/features/cloudbrainShow.js index affae8f8f..26d9e49bf 100644 --- a/web_src/js/features/cloudbrainShow.js +++ b/web_src/js/features/cloudbrainShow.js @@ -147,6 +147,7 @@ export default async function initCloudrainSow() { let logContentDom = document.querySelector(`#log${max}${version_name}`); let ID = $(`#accordion${version_name}`).data("jobid"); let repoPath = $(`#accordion${version_name}`).data("repopath"); + let start_line = $(`#log${version_name} input[name=end_line${max}]`).val(); $(`#log_file${max}${version_name}`).siblings("pre").remove(); $(`#log${max}${version_name} .ui.inverted.active.dimmer`).css({ "background-color": "#fff", @@ -178,7 +179,45 @@ export default async function initCloudrainSow() { }, 1000); } } - scrollAnimation(logContentDom, logContentDom.scrollTop, 0); + $.get( + `/api/v1/repos/${repoPath}/${ID}/log?version_name=${version_name}&base_line=${data.StartLine}&lines=${lines}&order=asc`, + (data) => { + $(`#log${max}${version_name} .ui.inverted.active.dimmer`).css( + "display", + "none" + ); + if (data.Lines == 0) { + if (max) { + $("body").toast({ + class: "black", + message: `您已翻阅至日志顶部,请稍后再试!`, + }); + } else { + $(`.message${version_name} #header`).text("您已翻阅至日志顶部"); + $(`.message${version_name}`).css("display", "block"); + setTimeout(function () { + $(`.message${version_name}`).css("display", "none"); + }, 1000); + } + } else { + if (start_line === data.StartLine || start_line === "") { + return; + } else { + $(`#log${version_name} input[name=start_line${max}]`).val( + data.StartLine + ); + $(`#log${max}${version_name}`).prepend("
" + data.Content);
+              }
+            }
+          }
+        ).fail(function (err) {
+          $(`#log${max}${version_name} .ui.inverted.active.dimmer`).css(
+            "display",
+            "none"
+          );
+          console.log(err);
+        });
+        scrollAnimation(logContentDom, logContentDom.scrollTop, 10);
       }
     ).fail((err) => {
       $(`#log${max}${version_name} .ui.inverted.active.dimmer`).css(