From c0a5c8a48c47970961247934e92e026f1c18cbaa Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Wed, 2 Jun 2021 18:00:59 +0800 Subject: [PATCH 01/17] add interface --- routers/repo/cloudbrain.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 8d8e97377..55d809ec9 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -23,6 +23,7 @@ const ( tplCloudBrainIndex base.TplName = "repo/cloudbrain/index" tplCloudBrainNew base.TplName = "repo/cloudbrain/new" tplCloudBrainShow base.TplName = "repo/cloudbrain/show" + tplCloudBrainShowModels base.TplName = "repo/cloudbrain/show_models" ) var ( @@ -332,6 +333,24 @@ func CloudBrainDel(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain") } +func CloudBrainGetModels(ctx *context.Context) { + ctx.Data["PageIsCloudBrain"] = true + + var jobID = ctx.Params(":jobid") + task, err := models.GetCloudbrainByJobID(jobID) + if err != nil { + log.Error("no such job!") + ctx.RenderWithErr("no such job!", tplCloudBrainIndex, nil) + return + } + + + + ctx.Data["task"] = task + ctx.Data["jobID"] = jobID + ctx.HTML(200, tplCloudBrainShowModels) +} + func GetRate(ctx *context.Context) { var jobID = ctx.Params(":jobid") job, err := models.GetCloudbrainByJobID(jobID) From 42aa1404bbaaa246e3ce56a33cade3eda9d86f05 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Tue, 8 Jun 2021 16:33:43 +0800 Subject: [PATCH 02/17] 2 --- routers/repo/cloudbrain.go | 18 +++++++++++++++++- routers/routes/routes.go | 6 ++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 55d809ec9..154dbb402 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -2,8 +2,10 @@ package repo import ( "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/storage" "encoding/json" "errors" + "net/http" "os" "os/exec" "strconv" @@ -333,7 +335,7 @@ func CloudBrainDel(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain") } -func CloudBrainGetModels(ctx *context.Context) { +func CloudBrainShowModels(ctx *context.Context) { ctx.Data["PageIsCloudBrain"] = true var jobID = ctx.Params(":jobid") @@ -344,6 +346,7 @@ func CloudBrainGetModels(ctx *context.Context) { return } + //get dirs ctx.Data["task"] = task @@ -351,6 +354,19 @@ func CloudBrainGetModels(ctx *context.Context) { ctx.HTML(200, tplCloudBrainShowModels) } +func CloudBrainDownloadModel(ctx *context.Context) { + filePath := ctx.Query("file_path") + fileName := ctx.Query("file_name") + url, err := storage.Attachments.PresignedGetURL(filePath, fileName) + if err != nil { + log.Error("PresignedGetURL failed: %v", err.Error()) + ctx.ServerError("PresignedGetURL", err) + return + } + + http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) +} + func GetRate(ctx *context.Context) { var jobID = ctx.Params(":jobid") job, err := models.GetCloudbrainByJobID(jobID) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index e8e33104d..81f15f27d 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -910,9 +910,11 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/commit_image", reqRepoCloudBrainWriter, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage) m.Post("/stop", reqRepoCloudBrainWriter, repo.CloudBrainStop) m.Post("/del", reqRepoCloudBrainWriter, repo.CloudBrainDel) - m.Get("/rate", reqRepoCloudBrainWriter, repo.GetRate) + m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate) + m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels) + m.Get("/download_model", reqRepoCloudBrainReader, repo.CloudBrainDownloadModel) }) - m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew) + m.Get("/create", reqRepoCloudBrainReader, repo.CloudBrainNew) m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) }, context.RepoRef()) From 70e2aabdca46e3199629f32d0fbcf4e8c7af1f47 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Tue, 15 Jun 2021 15:49:07 +0800 Subject: [PATCH 03/17] mod req --- routers/repo/cloudbrain.go | 12 ++++++++++++ routers/repo/dir.go | 15 ++++++++++----- templates/repo/datasets/dirs/dir_list.tmpl | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 154dbb402..7cac900c6 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -349,11 +349,23 @@ func CloudBrainShowModels(ctx *context.Context) { //get dirs + ctx.Data["task"] = task ctx.Data["jobID"] = jobID ctx.HTML(200, tplCloudBrainShowModels) } +func getModelDirs(uuid string, parentDir string) (string, error) { + var req string + if parentDir == "" { + req = "uuid=" + uuid + } else { + req = "uuid=" + uuid + "&parentDir=" + parentDir + } + + return getDirs(req) +} + func CloudBrainDownloadModel(ctx *context.Context) { filePath := ctx.Query("file_path") fileName := ctx.Query("file_name") diff --git a/routers/repo/dir.go b/routers/repo/dir.go index 388af34ec..ea1f80498 100755 --- a/routers/repo/dir.go +++ b/routers/repo/dir.go @@ -58,7 +58,7 @@ func DirIndex(ctx *context.Context) { dirArray = []string{attachment.Name} } - dirs, err := getDirs(uuid, parentDir) + dirs, err := getDatasetDirs(uuid, parentDir) if err != nil { log.Error("getDirs failed:", err.Error()) ctx.ServerError("getDirs failed:", err) @@ -75,13 +75,13 @@ func DirIndex(ctx *context.Context) { ctx.Data["Path"] = dirArray ctx.Data["Dirs"] = fileInfos + ctx.Data["Uuid"] = uuid ctx.Data["PageIsDataset"] = true ctx.HTML(200, tplDirIndex) } -func getDirs(uuid string, parentDir string) (string, error) { - var dirs string +func getDatasetDirs(uuid string, parentDir string) (string, error) { var req string if parentDir == "" { req = "uuid=" + uuid @@ -89,7 +89,13 @@ func getDirs(uuid string, parentDir string) (string, error) { req = "uuid=" + uuid + "&parentDir=" + parentDir } - url := setting.DecompressAddress + "/dirs?" + req + return getDirs(req) +} + +func getDirs(req string) (string, error) { + var dirs string + + url := setting.DecompressAddress + "/dirs/dataset?" + req reqHttp, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { log.Error("http.NewRequest failed:", err.Error()) @@ -127,6 +133,5 @@ func getDirs(uuid string, parentDir string) (string, error) { } dirs = resp.FileInfos - return dirs, nil } diff --git a/templates/repo/datasets/dirs/dir_list.tmpl b/templates/repo/datasets/dirs/dir_list.tmpl index 98232e17e..9d10f509c 100755 --- a/templates/repo/datasets/dirs/dir_list.tmpl +++ b/templates/repo/datasets/dirs/dir_list.tmpl @@ -6,7 +6,7 @@ - + {{if .IsDir}} {{svg "octicon-file-directory" 16}}{{else}}{{svg "octicon-file" 16}}{{end}} {{.FileName}} From ffb7b870977e343579c2079b4df1599b91ea8ba8 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Tue, 15 Jun 2021 17:48:08 +0800 Subject: [PATCH 04/17] download-model --- modules/storage/minio.go | 2 +- routers/repo/attachment.go | 2 +- routers/repo/cloudbrain.go | 34 ++++++++++++++++------ routers/repo/dir.go | 15 ++++++---- templates/repo/datasets/dirs/dir_list.tmpl | 2 +- 5 files changed, 38 insertions(+), 17 deletions(-) mode change 100644 => 100755 modules/storage/minio.go diff --git a/modules/storage/minio.go b/modules/storage/minio.go old mode 100644 new mode 100755 index 83a60f376..b14442d56 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -83,7 +83,7 @@ func (m *MinioStorage) PresignedGetURL(path string, fileName string) (string, er reqParams.Set("response-content-disposition", "attachment; filename=\""+fileName+"\"") var preURL *url.URL - preURL, err := m.client.PresignedGetObject(m.bucket, m.buildMinioPath(path), PresignedGetUrlExpireTime, reqParams) + preURL, err := m.client.PresignedGetObject(m.bucket, path, PresignedGetUrlExpireTime, reqParams) if err != nil { return "", err } diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 086965bdf..b59f4ffc7 100755 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -205,7 +205,7 @@ func GetAttachment(ctx *context.Context) { if setting.Attachment.StoreType == storage.MinioStorageType { url := "" if typeCloudBrain == models.TypeCloudBrainOne { - url, err = storage.Attachments.PresignedGetURL(attach.RelativePath(), attach.Name) + url, err = storage.Attachments.PresignedGetURL(setting.Attachment.Minio.BasePath + attach.RelativePath(), attach.Name) if err != nil { ctx.ServerError("PresignedGetURL", err) return diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 7cac900c6..e70944150 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -338,37 +338,53 @@ func CloudBrainDel(ctx *context.Context) { func CloudBrainShowModels(ctx *context.Context) { ctx.Data["PageIsCloudBrain"] = true - var jobID = ctx.Params(":jobid") + jobID := ctx.Params(":jobid") + parentDir := ctx.Query("parentDir") task, err := models.GetCloudbrainByJobID(jobID) if err != nil { log.Error("no such job!") - ctx.RenderWithErr("no such job!", tplCloudBrainIndex, nil) + ctx.ServerError("no such job:", err) return } //get dirs + dirs, err := getModelDirs(task.JobName, parentDir) + if err != nil { + log.Error("getModelDirs failed:", err.Error()) + ctx.ServerError("getModelDirs failed:", err) + return + } + var fileInfos []FileInfo + err = json.Unmarshal([]byte(dirs), &fileInfos) + if err != nil { + log.Error("json.Unmarshal failed:", err.Error()) + ctx.ServerError("json.Unmarshal failed:", err) + return + } - + ctx.Data["Dirs"] = fileInfos ctx.Data["task"] = task - ctx.Data["jobID"] = jobID ctx.HTML(200, tplCloudBrainShowModels) } -func getModelDirs(uuid string, parentDir string) (string, error) { +func getModelDirs(jobName string, parentDir string) (string, error) { var req string + modelActualPath := setting.JobPath + jobName + "/model/" if parentDir == "" { - req = "uuid=" + uuid + req = "baseDir=" + modelActualPath } else { - req = "uuid=" + uuid + "&parentDir=" + parentDir + req = "baseDir=" + modelActualPath + "&parentDir=" + parentDir } return getDirs(req) } func CloudBrainDownloadModel(ctx *context.Context) { - filePath := ctx.Query("file_path") - fileName := ctx.Query("file_name") + parentDir := ctx.Query("parentDir") + fileName := ctx.Query("fileName") + jobName := ctx.Query("jobName") + filePath := "jobs/" +jobName + "/model/" + parentDir url, err := storage.Attachments.PresignedGetURL(filePath, fileName) if err != nil { log.Error("PresignedGetURL failed: %v", err.Error()) diff --git a/routers/repo/dir.go b/routers/repo/dir.go index ea1f80498..d1dfbcd11 100755 --- a/routers/repo/dir.go +++ b/routers/repo/dir.go @@ -60,8 +60,8 @@ func DirIndex(ctx *context.Context) { dirs, err := getDatasetDirs(uuid, parentDir) if err != nil { - log.Error("getDirs failed:", err.Error()) - ctx.ServerError("getDirs failed:", err) + log.Error("getDatasetDirs failed:", err.Error()) + ctx.ServerError("getDatasetDirs failed:", err) return } @@ -83,10 +83,15 @@ func DirIndex(ctx *context.Context) { func getDatasetDirs(uuid string, parentDir string) (string, error) { var req string + dataActualPath := setting.Attachment.Minio.RealPath + + setting.Attachment.Minio.Bucket + "/" + + setting.Attachment.Minio.BasePath + + models.AttachmentRelativePath(uuid) + + uuid + "/" if parentDir == "" { - req = "uuid=" + uuid + req = "baseDir=" + dataActualPath } else { - req = "uuid=" + uuid + "&parentDir=" + parentDir + req = "baseDir=" + dataActualPath + "&parentDir=" + parentDir } return getDirs(req) @@ -95,7 +100,7 @@ func getDatasetDirs(uuid string, parentDir string) (string, error) { func getDirs(req string) (string, error) { var dirs string - url := setting.DecompressAddress + "/dirs/dataset?" + req + url := setting.DecompressAddress + "/dirs?" + req reqHttp, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { log.Error("http.NewRequest failed:", err.Error()) diff --git a/templates/repo/datasets/dirs/dir_list.tmpl b/templates/repo/datasets/dirs/dir_list.tmpl index 9d10f509c..975dccef0 100755 --- a/templates/repo/datasets/dirs/dir_list.tmpl +++ b/templates/repo/datasets/dirs/dir_list.tmpl @@ -6,7 +6,7 @@ - + {{if .IsDir}} {{svg "octicon-file-directory" 16}}{{else}}{{svg "octicon-file" 16}}{{end}} {{.FileName}} From 97a8ba270430a7089104533af35853a2a9490174 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Thu, 17 Jun 2021 09:43:42 +0800 Subject: [PATCH 05/17] html --- routers/repo/cloudbrain.go | 3 +- templates/repo/cloudbrain/index.tmpl | 10 +++---- .../repo/cloudbrain/models/dir_list.tmpl | 27 +++++++++++++++++ templates/repo/cloudbrain/models/index.tmpl | 29 +++++++++++++++++++ 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100755 templates/repo/cloudbrain/models/dir_list.tmpl create mode 100755 templates/repo/cloudbrain/models/index.tmpl diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index e70944150..4b3162c28 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -25,7 +25,7 @@ const ( tplCloudBrainIndex base.TplName = "repo/cloudbrain/index" tplCloudBrainNew base.TplName = "repo/cloudbrain/new" tplCloudBrainShow base.TplName = "repo/cloudbrain/show" - tplCloudBrainShowModels base.TplName = "repo/cloudbrain/show_models" + tplCloudBrainShowModels base.TplName = "repo/cloudbrain/models/index" ) var ( @@ -365,6 +365,7 @@ func CloudBrainShowModels(ctx *context.Context) { ctx.Data["Dirs"] = fileInfos ctx.Data["task"] = task + ctx.Data["JobID"] = jobID ctx.HTML(200, tplCloudBrainShowModels) } diff --git a/templates/repo/cloudbrain/index.tmpl b/templates/repo/cloudbrain/index.tmpl index 9a58a05a6..f48f063e8 100755 --- a/templates/repo/cloudbrain/index.tmpl +++ b/templates/repo/cloudbrain/index.tmpl @@ -248,7 +248,7 @@ -
+
{{.Status}}
@@ -257,11 +257,11 @@ {{svg "octicon-flame" 16}} {{TimeSinceUnix .CreatedUnix $.Lang}}
- -
+ +
- - 查看 + + 模型下载
diff --git a/templates/repo/cloudbrain/models/dir_list.tmpl b/templates/repo/cloudbrain/models/dir_list.tmpl new file mode 100755 index 000000000..db397f13e --- /dev/null +++ b/templates/repo/cloudbrain/models/dir_list.tmpl @@ -0,0 +1,27 @@ +{{if .Dirs}} + + + {{range .Dirs}} + + + + + + {{end}} + +
+ + + + {{if .IsDir}} {{svg "octicon-file-directory" 16}}{{else}}{{svg "octicon-file" 16}}{{end}} {{.FileName}} + + + + + {{.Size | FileSize}} + + + {{.ModTime}} +
+ +{{end}} diff --git a/templates/repo/cloudbrain/models/index.tmpl b/templates/repo/cloudbrain/models/index.tmpl new file mode 100755 index 000000000..3b53ad78e --- /dev/null +++ b/templates/repo/cloudbrain/models/index.tmpl @@ -0,0 +1,29 @@ +{{template "base/head" .}} +
+ {{template "repo/header" .}} +
+
+
+
+

+ {{ range $index, $item := .Path }}{{ $item }}/{{ end }} +

+
+
+
+ +
+
+
+
+ {{template "repo/cloudbrain/models/dir_list" .}} +
+
+
+
+
+
+ + + +{{template "base/footer" .}} From 4082282eae4d700232d5025cf692fab8d3a3fab4 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Thu, 17 Jun 2021 09:50:14 +0800 Subject: [PATCH 06/17] add type in explore dataset --- templates/explore/dataset_list.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/explore/dataset_list.tmpl b/templates/explore/dataset_list.tmpl index 9200274a9..48ae78127 100755 --- a/templates/explore/dataset_list.tmpl +++ b/templates/explore/dataset_list.tmpl @@ -25,7 +25,7 @@ {{range .Datasets}}
- + {{.Repo.OwnerName}} / {{.Title}}
From 78b02e4264114b70861c3b11f5171e99d3d01a9d Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Thu, 17 Jun 2021 11:44:24 +0800 Subject: [PATCH 07/17] show model --- routers/repo/cloudbrain.go | 2 ++ templates/repo/cloudbrain/models/dir_list.tmpl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 4b3162c28..2ea0e98ab 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -340,6 +340,7 @@ func CloudBrainShowModels(ctx *context.Context) { jobID := ctx.Params(":jobid") parentDir := ctx.Query("parentDir") + dirArray := strings.Split(parentDir, "/") task, err := models.GetCloudbrainByJobID(jobID) if err != nil { log.Error("no such job!") @@ -363,6 +364,7 @@ func CloudBrainShowModels(ctx *context.Context) { return } + ctx.Data["Path"] = dirArray ctx.Data["Dirs"] = fileInfos ctx.Data["task"] = task ctx.Data["JobID"] = jobID diff --git a/templates/repo/cloudbrain/models/dir_list.tmpl b/templates/repo/cloudbrain/models/dir_list.tmpl index db397f13e..a9683de77 100755 --- a/templates/repo/cloudbrain/models/dir_list.tmpl +++ b/templates/repo/cloudbrain/models/dir_list.tmpl @@ -6,7 +6,7 @@ - + {{if .IsDir}} {{svg "octicon-file-directory" 16}}{{else}}{{svg "octicon-file" 16}}{{end}} {{.FileName}} From a2c624e5a748d590b15c665ce040ec771fabf1e4 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Thu, 17 Jun 2021 15:54:31 +0800 Subject: [PATCH 08/17] fix-114 --- templates/repo/datasets/index.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/datasets/index.tmpl b/templates/repo/datasets/index.tmpl index 721ad61eb..5ab2570c3 100755 --- a/templates/repo/datasets/index.tmpl +++ b/templates/repo/datasets/index.tmpl @@ -76,8 +76,8 @@ {{.i18n.Tr "repo.issues.filter_sort"}}
From b7876d062c7cef16529cf00a3bb3a02c5a7eb8bd Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Mon, 21 Jun 2021 15:38:14 +0800 Subject: [PATCH 09/17] adjust --- templates/repo/cloudbrain/index.tmpl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/templates/repo/cloudbrain/index.tmpl b/templates/repo/cloudbrain/index.tmpl index f48f063e8..60ce3c202 100755 --- a/templates/repo/cloudbrain/index.tmpl +++ b/templates/repo/cloudbrain/index.tmpl @@ -257,15 +257,6 @@ {{svg "octicon-flame" 16}} {{TimeSinceUnix .CreatedUnix $.Lang}}
- -
- - - 模型下载 - - -
-
@@ -304,6 +295,15 @@
+ +
+ + + 模型下载 + + +
+ 提交镜像 From 1ab86a59ad174a310893346b2a5a3eb5f95bda34 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Tue, 22 Jun 2021 14:53:12 +0800 Subject: [PATCH 10/17] fix-119 --- routers/repo/cloudbrain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 8d8e97377..084b78931 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -341,7 +341,7 @@ func GetRate(ctx *context.Context) { } if job.JobType == string(models.JobTypeBenchmark) { - ctx.Redirect(setting.BenchmarkServerHost) + ctx.Redirect(setting.BenchmarkServerHost + "?username=" + ctx.User.Name) } else if job.JobType == string(models.JobTypeSnn4imagenet) { ctx.Redirect(setting.Snn4imagenetServerHost) } else { From 3d1a8f9b8389abf1f41f1fe84f709513e1b0b79a Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Tue, 29 Jun 2021 19:01:07 +0800 Subject: [PATCH 11/17] log --- modules/log/logger.go | 38 +++++++++++++++++++++++++++++++------- routers/repo/cloudbrain.go | 26 +++++++++++++------------- routers/routes/routes.go | 22 +++++++++++++++++++++- 3 files changed, 65 insertions(+), 21 deletions(-) mode change 100644 => 100755 modules/log/logger.go diff --git a/modules/log/logger.go b/modules/log/logger.go old mode 100644 new mode 100755 index 9704ffd3d..c9ed8fb2a --- a/modules/log/logger.go +++ b/modules/log/logger.go @@ -67,19 +67,43 @@ func (l *Logger) Log(skip int, level Level, format string, v ...interface{}) err caller = fn.Name() + "()" } } - msg := format - if len(v) > 0 { - msg = ColorSprintf(format, v...) - } + stack := "" if l.GetStacktraceLevel() <= level { stack = Stack(skip + 1) } - return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, stack) + + msg := format + if len(v) > 0 { + switch v[len(v)-1].(type) { + case string: + if !strings.Contains(v[len(v)-1].(string), "-") { + //has no msgID + msg = ColorSprintf(format, v...) + return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, "", stack) + } else { + if len(v) > 1 { + args := make([]interface{}, len(v)-1) + for i := 0; i < len(v)-1; i++ { + args[i] = v[i] + } + msg = ColorSprintf(format, args...) + } + return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, v[len(v)-1].(string), stack) + } + default: + //has no msgID + msg = ColorSprintf(format, v...) + return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, "", stack) + } + } else { + //has no msgID + return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, "", stack) + } } // SendLog sends a log event at the provided level with the information given -func (l *Logger) SendLog(level Level, caller, filename string, line int, msg string, stack string) error { +func (l *Logger) SendLog(level Level, caller, filename string, line int, msg, msgID, stack string) error { if l.GetLevel() > level { return nil } @@ -88,7 +112,7 @@ func (l *Logger) SendLog(level Level, caller, filename string, line int, msg str caller: caller, filename: filename, line: line, - msg: msg, + msg: msg + "[" + msgID + "]", time: time.Now(), stacktrace: stack, } diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 2117828ca..a2a65fd81 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -96,7 +96,7 @@ func CloudBrainNew(ctx *context.Context) { result, err := cloudbrain.GetImages() if err != nil { ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetImages failed:", err.Error()) + log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["msgID"]) } for i, payload := range result.Payload.ImageInfo { @@ -112,7 +112,7 @@ func CloudBrainNew(ctx *context.Context) { resultPublic, err := cloudbrain.GetPublicImages() if err != nil { ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetPublicImages failed:", err.Error()) + log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["msgID"]) } for i, payload := range resultPublic.Payload.ImageInfo { @@ -164,7 +164,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath if jobType != string(models.JobTypeBenchmark) && jobType != string(models.JobTypeDebug) && jobType != string(models.JobTypeSnn4imagenet) { - log.Error("jobtype error:", jobType) + log.Error("jobtype error:", jobType, ctx.Data["msgID"]) ctx.RenderWithErr("jobtype error", tplCloudBrainNew, &form) return } @@ -267,7 +267,7 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain ImageTag: form.Tag, }) if err != nil { - log.Error("CommitImage(%s) failed:", task.JobName, err.Error()) + log.Error("CommitImage(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "result_code": "-1", "error_msg": "CommitImage failed", @@ -290,14 +290,14 @@ func CloudBrainStop(ctx *context.Context) { } if task.Status == string(models.JobStopped) { - log.Error("the job(%s) has been stopped", task.JobName) + log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"]) ctx.ServerError("the job has been stopped", errors.New("the job has been stopped")) return } err = cloudbrain.StopJob(jobID) if err != nil { - log.Error("StopJob(%s) failed:%v", task.JobName, err.Error()) + log.Error("StopJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"]) ctx.ServerError("StopJob failed", err) return } @@ -321,7 +321,7 @@ func CloudBrainDel(ctx *context.Context) { } if task.Status != string(models.JobStopped) { - log.Error("the job(%s) has not been stopped", task.JobName) + log.Error("the job(%s) has not been stopped", task.JobName, ctx.Data["msgID"]) ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped")) return } @@ -343,7 +343,7 @@ func CloudBrainShowModels(ctx *context.Context) { dirArray := strings.Split(parentDir, "/") task, err := models.GetCloudbrainByJobID(jobID) if err != nil { - log.Error("no such job!") + log.Error("no such job!", ctx.Data["msgID"]) ctx.ServerError("no such job:", err) return } @@ -351,7 +351,7 @@ func CloudBrainShowModels(ctx *context.Context) { //get dirs dirs, err := getModelDirs(task.JobName, parentDir) if err != nil { - log.Error("getModelDirs failed:", err.Error()) + log.Error("getModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) ctx.ServerError("getModelDirs failed:", err) return } @@ -359,7 +359,7 @@ func CloudBrainShowModels(ctx *context.Context) { var fileInfos []FileInfo err = json.Unmarshal([]byte(dirs), &fileInfos) if err != nil { - log.Error("json.Unmarshal failed:", err.Error()) + log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) ctx.ServerError("json.Unmarshal failed:", err) return } @@ -390,7 +390,7 @@ func CloudBrainDownloadModel(ctx *context.Context) { filePath := "jobs/" +jobName + "/model/" + parentDir url, err := storage.Attachments.PresignedGetURL(filePath, fileName) if err != nil { - log.Error("PresignedGetURL failed: %v", err.Error()) + log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) ctx.ServerError("PresignedGetURL", err) return } @@ -411,13 +411,13 @@ func GetRate(ctx *context.Context) { } else if job.JobType == string(models.JobTypeSnn4imagenet) { ctx.Redirect(setting.Snn4imagenetServerHost) } else { - log.Error("JobType error:", job.JobType) + log.Error("JobType error:%s", job.JobType, ctx.Data["msgID"]) } } func downloadCode(repo *models.Repository, codePath string) error { if err := git.Clone(repo.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil { - log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err) + log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err, ctx.Data["msgID"]) return err } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 81f15f27d..d994ec5bf 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -49,6 +49,7 @@ import ( "gitea.com/macaron/session" "gitea.com/macaron/toolbox" "github.com/prometheus/client_golang/prometheus" + gouuid "github.com/satori/go.uuid" "github.com/tstranex/u2f" ) @@ -85,7 +86,7 @@ func setupAccessLogger(m *macaron.Macaron) { log.Error("Could not set up macaron access logger: %v", err.Error()) } - err = logger.SendLog(log.INFO, "", "", 0, buf.String(), "") + err = logger.SendLog(log.INFO, "", "", 0, buf.String(), ctx.Data["msgID"].(string), "") if err != nil { log.Error("Could not set up macaron access logger: %v", err.Error()) } @@ -107,6 +108,24 @@ func RouterHandler(level log.Level) func(ctx *macaron.Context) { } } +// SetLogMsgID set msgID in log +func SetLogMsgID() func(ctx *macaron.Context) { + return func(ctx *macaron.Context) { + start := time.Now() + + uuid := gouuid.NewV4().String() + ctx.Data["MsgID"] = uuid + + log.Info("Started %s %s for %s", log.ColoredMethod(ctx.Req.Method), ctx.Req.URL.RequestURI(), ctx.RemoteAddr(), ctx.Data["MsgID"]) + + rw := ctx.Resp.(macaron.ResponseWriter) + ctx.Next() + + status := rw.Status() + log.Info("Completed %s %s %v %s in %v", log.ColoredMethod(ctx.Req.Method), ctx.Req.URL.RequestURI(), log.ColoredStatus(status), log.ColoredStatus(status, http.StatusText(rw.Status())), log.ColoredTime(time.Since(start)), ctx.Data["MsgID"]) + } +} + // NewMacaron initializes Macaron instance. func NewMacaron() *macaron.Macaron { gob.Register(&u2f.Challenge{}) @@ -125,6 +144,7 @@ func NewMacaron() *macaron.Macaron { m.Use(macaron.Logger()) } } + m.Use(SetLogMsgID()) // Access Logger is similar to Router Log but more configurable and by default is more like the NCSA Common Log format if setting.EnableAccessLog { setupAccessLogger(m) From 488ebee8443e162ee9fccbcf92d16b06960cd696 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Wed, 30 Jun 2021 16:28:05 +0800 Subject: [PATCH 12/17] add msgid in log --- routers/repo/blockchain.go | 18 +++++++++--------- routers/repo/cloudbrain.go | 2 +- routers/routes/routes.go | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/routers/repo/blockchain.go b/routers/repo/blockchain.go index d650e71ca..dc3fcd848 100755 --- a/routers/repo/blockchain.go +++ b/routers/repo/blockchain.go @@ -28,14 +28,14 @@ const ( func BlockChainIndex(ctx *context.Context) { repo := ctx.Repo.Repository if repo.ContractAddress == "" || ctx.User.PublicKey == "" { - log.Error("the repo(%d) or the user(%d) has not been initialized in block_chain", repo.RepoID, ctx.User.ID) + log.Error("the repo(%d) or the user(%d) has not been initialized in block_chain", repo.RepoID, ctx.User.ID, ctx.Data["msgID"]) ctx.HTML(http.StatusInternalServerError, tplBlockChainIndex) return } res, err := blockchain.GetBalance(repo.ContractAddress, ctx.User.PublicKey) if err != nil { - log.Error("GetBalance(%s) failed:%v", ctx.User.PublicKey, err) + log.Error("GetBalance(%s) failed:%s", ctx.User.PublicKey, err, ctx.Data["msgID"]) ctx.HTML(http.StatusInternalServerError, tplBlockChainIndex) return } @@ -52,7 +52,7 @@ func HandleBlockChainInitNotify(ctx *context.Context) { repo, err := models.GetRepositoryByID(req.RepoId) if err != nil { - log.Error("GetRepositoryByID failed:", err.Error()) + log.Error("GetRepositoryByID failed:%v", err.Error(), ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "internal error", @@ -61,7 +61,7 @@ func HandleBlockChainInitNotify(ctx *context.Context) { } if repo.BlockChainStatus == models.RepoBlockChainSuccess && len(repo.ContractAddress) != 0 { - log.Error("the repo has been RepoBlockChainSuccess:", req.RepoId) + log.Error("the repo has been RepoBlockChainSuccess:%d", req.RepoId, ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "the repo has been RepoBlockChainSuccess", @@ -73,7 +73,7 @@ func HandleBlockChainInitNotify(ctx *context.Context) { repo.ContractAddress = req.ContractAddress if err = models.UpdateRepositoryCols(repo, "block_chain_status", "contract_address"); err != nil { - log.Error("UpdateRepositoryCols failed:", err.Error()) + log.Error("UpdateRepositoryCols failed:%v", err.Error(), ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "internal error", @@ -91,7 +91,7 @@ func HandleBlockChainCommitNotify(ctx *context.Context) { var req BlockChainCommitNotify data, _ := ctx.Req.Body().Bytes() if err := json.Unmarshal(data, &req); err != nil { - log.Error("json.Unmarshal failed:", err.Error()) + log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "response data error", @@ -101,7 +101,7 @@ func HandleBlockChainCommitNotify(ctx *context.Context) { blockChain, err := models.GetBlockChainByCommitID(req.CommitID) if err != nil { - log.Error("GetRepositoryByID failed:", err.Error()) + log.Error("GetRepositoryByID failed:%v", err.Error(), ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "internal error", @@ -110,7 +110,7 @@ func HandleBlockChainCommitNotify(ctx *context.Context) { } if blockChain.Status == models.BlockChainCommitSuccess { - log.Error("the commit has been BlockChainCommitReady:", blockChain.RepoID) + log.Error("the commit has been BlockChainCommitReady:%s", blockChain.RepoID, ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "the commit has been BlockChainCommitReady", @@ -122,7 +122,7 @@ func HandleBlockChainCommitNotify(ctx *context.Context) { blockChain.TransactionHash = req.TransactionHash if err = models.UpdateBlockChainCols(blockChain, "status", "transaction_hash"); err != nil { - log.Error("UpdateBlockChainCols failed:", err.Error()) + log.Error("UpdateBlockChainCols failed:%v", err.Error(), ctx.Data["msgID"]) ctx.JSON(200, map[string]string{ "code": "-1", "message": "internal error", diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index a2a65fd81..27642d7bb 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -417,7 +417,7 @@ func GetRate(ctx *context.Context) { func downloadCode(repo *models.Repository, codePath string) error { if err := git.Clone(repo.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil { - log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err, ctx.Data["msgID"]) + log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err) return err } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index d994ec5bf..4f1f6f314 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -108,7 +108,7 @@ func RouterHandler(level log.Level) func(ctx *macaron.Context) { } } -// SetLogMsgID set msgID in log +// SetLogMsgID set msgID in Context func SetLogMsgID() func(ctx *macaron.Context) { return func(ctx *macaron.Context) { start := time.Now() From dac3b45a1f8440688c690cbb55adad135d49d641 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Thu, 8 Jul 2021 16:53:06 +0800 Subject: [PATCH 13/17] support chinese file_name download --- routers/repo/download.go | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 routers/repo/download.go diff --git a/routers/repo/download.go b/routers/repo/download.go old mode 100644 new mode 100755 index 7ef0574b1..5b8982102 --- a/routers/repo/download.go +++ b/routers/repo/download.go @@ -8,6 +8,7 @@ package repo import ( "fmt" "io" + "net/url" "path" "strings" @@ -32,6 +33,7 @@ func ServeData(ctx *context.Context, name string, reader io.Reader) error { // Google Chrome dislike commas in filenames, so let's change it to a space name = strings.Replace(name, ",", " ", -1) + name = url.QueryEscape(name) if base.IsTextFile(buf) || ctx.QueryBool("render") { cs, err := charset.DetectEncoding(buf) From 4a72e50071da1dbe90235bb9338934792187b22f Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Tue, 13 Jul 2021 17:47:32 +0800 Subject: [PATCH 14/17] mod error judge --- models/cloudbrain.go | 2 +- modules/cloudbrain/resty.go | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/models/cloudbrain.go b/models/cloudbrain.go index c8000c5a6..15790faa7 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -300,7 +300,7 @@ type CommitImageResult struct { Payload map[string]interface{} `json:"payload"` } -type StopJobResult struct { +type CloudBrainResult struct { Code string `json:"code"` Msg string `json:"msg"` } diff --git a/modules/cloudbrain/resty.go b/modules/cloudbrain/resty.go index ed6157776..fa9b25011 100755 --- a/modules/cloudbrain/resty.go +++ b/modules/cloudbrain/resty.go @@ -2,6 +2,7 @@ package cloudbrain import ( "code.gitea.io/gitea/modules/log" + "encoding/json" "fmt" "code.gitea.io/gitea/models" @@ -143,14 +144,26 @@ sendjob: return nil, fmt.Errorf("resty GetImages: %v", err) } - if getImagesResult.Code == "S401" && retry < 1 { + var response models.CloudBrainResult + err = json.Unmarshal(res.Body(), &response) + if err != nil { + log.Error("json.Unmarshal failed: %s", err.Error()) + return &getImagesResult, fmt.Errorf("json.Unmarshal failed: %s", err.Error()) + } + + if response.Code == "S401" && retry < 1 { retry++ _ = loginCloudbrain() goto sendjob } + if len(response.Code) != 0 { + log.Error("getImagesResult failed(%s): %s", response.Code, response.Msg) + return &getImagesResult, fmt.Errorf("getImagesResult failed(%s): %s", response.Code, response.Msg) + } + if getImagesResult.Code != Success { - return &getImagesResult, fmt.Errorf("getImgesResult err: %s", res.String()) + return &getImagesResult, fmt.Errorf("getImagesResult err: %s", res.String()) } return &getImagesResult, nil @@ -223,7 +236,7 @@ sendjob: func StopJob(jobID string) error { checkSetting() client := getRestyClient() - var result models.StopJobResult + var result models.CloudBrainResult retry := 0 From 7b637e9fa02d1118c63ee575744f5be43ec84430 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Wed, 14 Jul 2021 15:19:16 +0800 Subject: [PATCH 15/17] fix-81 --- options/locale/locale_zh-CN.ini | 1 + routers/org/home.go | 1 + templates/org/navber.tmpl | 32 ++++++++++++++++++-------------- 3 files changed, 20 insertions(+), 14 deletions(-) mode change 100644 => 100755 routers/org/home.go mode change 100644 => 100755 templates/org/navber.tmpl diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 8c0509752..a8f1455e7 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1819,6 +1819,7 @@ org_full_name_holder=组织全名 org_name_helper=组织名字应该简单明了。 create_org=创建组织 repo_updated=最后更新于 +home=组织主页 people=组织成员 teams=组织团队 lower_members=名成员 diff --git a/routers/org/home.go b/routers/org/home.go old mode 100644 new mode 100755 index fa61218d3..b11c179c1 --- a/routers/org/home.go +++ b/routers/org/home.go @@ -20,6 +20,7 @@ const ( // Home show organization home page func Home(ctx *context.Context) { ctx.SetParams(":org", ctx.Params(":username")) + ctx.Data["PageIsOrgHome"] = true context.HandleOrgAssignment(ctx) if ctx.Written() { return diff --git a/templates/org/navber.tmpl b/templates/org/navber.tmpl old mode 100644 new mode 100755 index 74ecb13f8..9ff92845e --- a/templates/org/navber.tmpl +++ b/templates/org/navber.tmpl @@ -1,14 +1,16 @@
@@ -18,15 +20,17 @@
From 521c62649ef1de3d5c103fa2d4312f8565b4cd32 Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Fri, 16 Jul 2021 15:20:56 +0800 Subject: [PATCH 16/17] fix 140 --- routers/user/auth.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routers/user/auth.go b/routers/user/auth.go index 421598347..fe49b7b12 100755 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -535,7 +535,10 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR log.Error("Unable to store session: %v", err) } - // Language setting of the user overwrites the one previously set + // Language setting of the user use the one previously set + if len(ctx.GetCookie("lang")) != 0 { + u.Language = ctx.GetCookie("lang") + } // If the user does not have a locale set, we save the current one. if len(u.Language) == 0 { u.Language = ctx.Locale.Language() From 4192a9571487409e92af11d64b654c00c22c9bbf Mon Sep 17 00:00:00 2001 From: lewis <747342561@qq.com> Date: Mon, 19 Jul 2021 16:45:59 +0800 Subject: [PATCH 17/17] fix-143 --- models/cloudbrain.go | 8 ++++++-- models/error.go | 12 ++++++++++++ routers/repo/cloudbrain.go | 15 ++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/models/cloudbrain.go b/models/cloudbrain.go index 15790faa7..f9c0fb4e0 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -2,7 +2,6 @@ package models import ( "encoding/json" - "errors" "fmt" "time" "xorm.io/xorm" @@ -569,7 +568,7 @@ func getRepoCloudBrain(cb *Cloudbrain) (*Cloudbrain, error) { if err != nil { return nil, err } else if !has { - return nil, errors.New("cloudbrain task is not found") + return nil, ErrJobNotExist{} } return cb, nil } @@ -609,3 +608,8 @@ func deleteJob(e Engine, job *Cloudbrain) error { _, err := e.ID(job.ID).Delete(job) return err } + +func GetCloudbrainByName(jobName string) (*Cloudbrain, error) { + cb := &Cloudbrain{JobName: jobName} + return getRepoCloudBrain(cb) +} diff --git a/models/error.go b/models/error.go index 66bb74de0..9d1c68658 100755 --- a/models/error.go +++ b/models/error.go @@ -1987,3 +1987,15 @@ func IsErrFileChunkNotExist(err error) bool { _, ok := err.(ErrFileChunkNotExist) return ok } + +type ErrJobNotExist struct { +} + +func IsErrJobNotExist(err error) bool { + _, ok := err.(ErrJobNotExist) + return ok +} + +func (err ErrJobNotExist) Error() string { + return fmt.Sprintf("the job does not exist") +} diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 27642d7bb..1088f47d3 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -168,11 +168,24 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { ctx.RenderWithErr("jobtype error", tplCloudBrainNew, &form) return } + + _, err := models.GetCloudbrainByName(jobName) + if err == nil { + log.Error("the job name did already exist", ctx.Data["MsgID"]) + ctx.RenderWithErr("the job name did already exist", tplCloudBrainNew, &form) + return + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + ctx.RenderWithErr("system error", tplCloudBrainNew, &form) + return + } + } repo := ctx.Repo.Repository downloadCode(repo, codePath) modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath - err := os.MkdirAll(modelPath, os.ModePerm) + err = os.MkdirAll(modelPath, os.ModePerm) if err != nil { ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) return