diff --git a/models/cloudbrain.go b/models/cloudbrain.go index 7a2966f74..0a6936851 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -72,11 +72,11 @@ type CloudBrainLoginResult struct { type TaskRole struct { Name string `json:"name"` - TaskNumber int `json:"taskNumber"` - MinSucceededTaskCount int `json:"minSucceededTaskCount"` - MinFailedTaskCount int `json:"minFailedTaskCount"` - CPUNumber int `json:"cpuNumber"` - GPUNumber int `json:"gpuNumber"` + TaskNumber int `json:"taskNumber"` + MinSucceededTaskCount int `json:"minSucceededTaskCount"` + MinFailedTaskCount int `json:"minFailedTaskCount"` + CPUNumber int `json:"cpuNumber"` + GPUNumber int `json:"gpuNumber"` MemoryMB int `json:"memoryMB"` ShmMB int `json:"shmMB"` Command string `json:"command"` @@ -123,8 +123,9 @@ type GetImagesResult struct { } type GetImagesPayload struct { - Count int `json:"count"` - ImageInfo []*ImageInfo `json:"rows"` + Count int `json:"count"` + TotalPages int `json:"totalPages,omitempty"` + ImageInfo []*ImageInfo `json:"rows"` } type CloudbrainsOptions struct { @@ -298,6 +299,25 @@ type ResourceSpec struct { ShareMemMiB int `json:"shareMemMiB"` } +type FlavorInfos struct { + FlavorInfo []*FlavorInfo `json:"flavor_info"` +} + +type FlavorInfo struct { + Id int `json:"id"` + Value string `json:"value"` +} + +type PoolInfos struct { + PoolInfo []*PoolInfo `json:"pool_info"` +} + +type PoolInfo struct { + PoolId string `json:"pool_id"` + PoolName string `json:"pool_name"` + PoolType string `json:"pool_type"` +} + type CommitImageParams struct { Ip string `json:"ip"` TaskContainerId string `json:"taskContainerId"` diff --git a/models/file_chunk.go b/models/file_chunk.go index 9f513bd34..fc2beef56 100755 --- a/models/file_chunk.go +++ b/models/file_chunk.go @@ -87,7 +87,7 @@ func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) { return fileChunk, nil } -// UpdateAttachment updates the given attachment in database +// UpdateFileChunk updates the given file_chunk in database func UpdateFileChunk(fileChunk *FileChunk) error { return updateFileChunk(x, fileChunk) } @@ -98,3 +98,13 @@ func updateFileChunk(e Engine, fileChunk *FileChunk) error { _, err := sess.Cols("is_uploaded").Update(fileChunk) return err } + +// DeleteFileChunk delete the given file_chunk in database +func DeleteFileChunk(fileChunk *FileChunk) error { + return deleteFileChunk(x, fileChunk) +} + +func deleteFileChunk(e Engine, fileChunk *FileChunk) error { + _, err := e.ID(fileChunk.ID).Delete(fileChunk) + return err +} diff --git a/modules/cloudbrain/resty.go b/modules/cloudbrain/resty.go index fa9b25011..4e30ea0e4 100755 --- a/modules/cloudbrain/resty.go +++ b/modules/cloudbrain/resty.go @@ -1,9 +1,11 @@ package cloudbrain import ( - "code.gitea.io/gitea/modules/log" "encoding/json" "fmt" + "strings" + + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/setting" @@ -11,13 +13,16 @@ import ( ) var ( - restyClient *resty.Client - HOST string - TOKEN string + restyClient *resty.Client + HOST string + TOKEN string + ImagesUrlMap = map[string]string{Public: "/rest-server/api/v1/image/public/list/", Custom: "/rest-server/api/v1/image/list/"} ) const ( JobHasBeenStopped = "S410" + Public = "public" + Custom = "custom" ) func getRestyClient() *resty.Client { @@ -77,6 +82,12 @@ sendjob: Post(HOST + "/rest-server/api/v1/jobs/") if err != nil { + if res != nil { + var response models.CloudBrainResult + json.Unmarshal(res.Body(), &response) + log.Error("code(%s), msg(%s)", response.Code, response.Msg) + return nil, fmt.Errorf(response.Msg) + } return nil, fmt.Errorf("resty create job: %s", err) } @@ -126,6 +137,16 @@ sendjob: } func GetImages() (*models.GetImagesResult, error) { + + return GetImagesPageable(1, 100, Custom, "") + +} + +func GetPublicImages() (*models.GetImagesResult, error) { + return GetImagesPageable(1, 100, Public, "") +} + +func GetImagesPageable(page int, size int, imageType string, name string) (*models.GetImagesResult, error) { checkSetting() client := getRestyClient() var getImagesResult models.GetImagesResult @@ -136,9 +157,9 @@ sendjob: res, err := client.R(). SetHeader("Content-Type", "application/json"). SetAuthToken(TOKEN). - SetQueryString("pageIndex=1&pageSize=100"). + SetQueryString(getQueryString(page, size, name)). SetResult(&getImagesResult). - Get(HOST + "/rest-server/api/v1/image/list/") + Get(HOST + ImagesUrlMap[imageType]) if err != nil { return nil, fmt.Errorf("resty GetImages: %v", err) @@ -157,48 +178,30 @@ sendjob: 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("getImagesResult err: %s", res.String()) } + getImagesResult.Payload.TotalPages = getTotalPages(getImagesResult, size) return &getImagesResult, nil } -func GetPublicImages() (*models.GetImagesResult, error) { - checkSetting() - client := getRestyClient() - var getImagesResult models.GetImagesResult - - retry := 0 - -sendjob: - res, err := client.R(). - SetHeader("Content-Type", "application/json"). - SetAuthToken(TOKEN). - SetQueryString("pageIndex=1&pageSize=100"). - SetResult(&getImagesResult). - Get(HOST + "/rest-server/api/v1/image/public/list/") - - if err != nil { - return nil, fmt.Errorf("resty GetPublicImages: %v", err) - } - - if getImagesResult.Code == "S401" && retry < 1 { - retry++ - _ = loginCloudbrain() - goto sendjob +func getTotalPages(getImagesResult models.GetImagesResult, size int) int { + totalCount := getImagesResult.Payload.Count + var totalPages int + if totalCount%size != 0 { + totalPages = totalCount/size + 1 + } else { + totalPages = totalCount / size } + return totalPages +} - if getImagesResult.Code != Success { - return &getImagesResult, fmt.Errorf("getImgesResult err: %s", res.String()) +func getQueryString(page int, size int, name string) string { + if strings.TrimSpace(name) == "" { + return fmt.Sprintf("pageIndex=%d&pageSize=%d", page, size) } - - return &getImagesResult, nil + return fmt.Sprintf("pageIndex=%d&pageSize=%d&name=%s", page, size, name) } func CommitImage(jobID string, params models.CommitImageParams) error { diff --git a/modules/modelarts/modelarts.go b/modules/modelarts/modelarts.go index 367fce061..a5cb8388b 100755 --- a/modules/modelarts/modelarts.go +++ b/modules/modelarts/modelarts.go @@ -2,6 +2,7 @@ package modelarts import ( "code.gitea.io/gitea/modules/setting" + "encoding/json" "path" "code.gitea.io/gitea/models" @@ -12,30 +13,31 @@ import ( const ( storageTypeOBS = "obs" autoStopDuration = 4 * 60 * 60 - flavor = "modelarts.kat1.xlarge" - //profileID = "Python3-ascend910-arm" - profileID = "efa847c0-7359-11eb-b34f-0255ac100057" - poolID = "pool1328035d" - poolName = "train-private-1" - poolType = "USER_DEFINED" DataSetMountPath = "/home/ma-user/work" NotebookEnv = "Python3" NotebookType = "Ascend" - FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" +) + +var ( + poolInfos *models.PoolInfos + FlavorInfos *models.FlavorInfos ) func GenerateTask(ctx *context.Context, jobName, uuid, description string) error { dataActualPath := setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" + if poolInfos == nil { + json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) + } jobResult, err := CreateJob(models.CreateNotebookParams{ JobName: jobName, Description: description, - ProfileID: profileID, - Flavor: flavor, + ProfileID: setting.ProfileID, + Flavor: setting.Flavor, Pool: models.Pool{ - ID: poolID, - Name: poolName, - Type: poolType, + ID: poolInfos.PoolInfo[0].PoolId, + Name: poolInfos.PoolInfo[0].PoolName, + Type: poolInfos.PoolInfo[0].PoolType, }, Spec: models.Spec{ Storage: models.Storage{ diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 986a18313..142369f88 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -473,6 +473,10 @@ var ( ModelArtsUsername string ModelArtsPassword string ModelArtsDomain string + ProfileID string + PoolInfos string + Flavor string + FlavorInfos string ) // DateLang transforms standard language locale name to corresponding value in datetime plugin. @@ -1182,6 +1186,10 @@ func NewContext() { ModelArtsUsername = sec.Key("USERNAME").MustString("") ModelArtsPassword = sec.Key("PASSWORD").MustString("") ModelArtsDomain = sec.Key("DOMAIN").MustString("cn-south-222") + ProfileID = sec.Key("PROFILE_ID").MustString("") + PoolInfos = sec.Key("POOL_INFOS").MustString("") + Flavor = sec.Key("FLAVOR").MustString("") + FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("") } func loadInternalToken(sec *ini.Section) string { diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go old mode 100644 new mode 100755 diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index b81dc9694..61a233589 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -223,6 +223,7 @@ issues.in_your_repos = In your repositories repos = Repositories users = Users organizations = Organizations +images = CloudImages search = Search code = Code repo_no_results = No matching repositories found. @@ -767,6 +768,7 @@ cloudbrain2 = cloudbrain2 cloudbrain_selection = select cloudbrain cloudbrain_platform_selection = Select the cloudbrain platform you want to use: confirm_choice = confirm +cloudbran1_tips = Only data in zip format can create cloudbrain tasks template.items = Template Items template.git_content = Git Content (Default Branch) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 5ac54f6c8..89db6536c 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -224,6 +224,7 @@ issues.in_your_repos=属于该用户项目的 repos=项目 users=用户 organizations=组织 +images = 云脑镜像 search=搜索 code=代码 repo_no_results=未找到匹配的项目。 @@ -478,7 +479,7 @@ add_new_email=添加新的邮箱地址 add_new_openid=添加新的 OpenID URI add_email=增加电子邮件地址 add_openid=添加 OpenID URI -add_email_confirmation_sent=一封新的确认邮件已经被发送至 %s,请检查您的收件箱并在 %s 内完成确认注册操作。 +add_email_confirmation_sent=一封新的确认邮件已经被发送至 %s,请检查您的收件箱并在 %s 内完成确认操作。 add_email_success=新的电子邮件地址已添加。 email_preference_set_success=电子邮件首选项已成功设置。 add_openid_success=新的 OpenID 地址已添加。 @@ -769,6 +770,7 @@ cloudbrain2=云脑2 cloudbrain_selection=云脑选择 cloudbrain_platform_selection=选择您准备使用的云脑平台: confirm_choice=确定 +cloudbran1_tips=只有zip格式的数据集才能发起云脑任务 template.items=模板选项 template.git_content=Git数据(默认分支) diff --git a/routers/home.go b/routers/home.go index 9ff860c09..2fc9db023 100755 --- a/routers/home.go +++ b/routers/home.go @@ -32,7 +32,8 @@ const ( // tplExploreOrganizations explore organizations page template tplExploreOrganizations base.TplName = "explore/organizations" // tplExploreCode explore code page template - tplExploreCode base.TplName = "explore/code" + tplExploreCode base.TplName = "explore/code" + tplExploreImages base.TplName = "explore/images" ) // Home render home page @@ -475,6 +476,10 @@ func ExploreCode(ctx *context.Context) { ctx.HTML(200, tplExploreCode) } +func ExploreImages(ctx *context.Context) { + ctx.HTML(200, tplExploreImages) +} + // NotFound render 404 page func NotFound(ctx *context.Context) { ctx.Data["Title"] = "Page Not Found" diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index fea7a3384..49c72b1c3 100755 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -483,16 +483,25 @@ func GetSuccessChunks(ctx *context.Context) { if typeCloudBrain == models.TypeCloudBrainOne { chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID) if err != nil { - ctx.ServerError("GetPartInfos failed", err) - return + log.Error("GetPartInfos failed:%v", err.Error()) } } else { chunks, err = storage.GetObsPartInfos(fileChunk.UUID, fileChunk.UploadID) if err != nil { - ctx.ServerError("GetObsPartInfos failed", err) - return + log.Error("GetObsPartInfos failed:%v", err.Error()) } } + + if err != nil { + models.DeleteFileChunk(fileChunk) + ctx.JSON(200, map[string]string{ + "uuid": "", + "uploaded": "0", + "uploadID": "", + "chunks": "", + }) + return + } } var attachID int64 diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index f6f796e14..2e5e3d2e3 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -1,17 +1,21 @@ package repo import ( - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/storage" + "bufio" "encoding/json" "errors" + "io" "net/http" "os" "os/exec" + "regexp" "strconv" "strings" "time" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" @@ -22,10 +26,10 @@ import ( ) const ( - tplCloudBrainIndex base.TplName = "repo/cloudbrain/index" - tplCloudBrainNew base.TplName = "repo/cloudbrain/new" - tplCloudBrainShow base.TplName = "repo/cloudbrain/show" - tplCloudBrainShowModels base.TplName = "repo/cloudbrain/models/index" + tplCloudBrainIndex base.TplName = "repo/cloudbrain/index" + tplCloudBrainNew base.TplName = "repo/cloudbrain/new" + tplCloudBrainShow base.TplName = "repo/cloudbrain/show" + tplCloudBrainShowModels base.TplName = "repo/cloudbrain/models/index" ) var ( @@ -86,17 +90,27 @@ func cutString(str string, lens int) string { return str[:lens] } -func CloudBrainNew(ctx *context.Context) { - ctx.Data["PageIsCloudBrain"] = true +func jobNamePrefixValid(s string) string { + lowStr := strings.ToLower(s) + re := regexp.MustCompile(`[^a-z0-9_\\-]+`) + + removeSpecial := re.ReplaceAllString(lowStr, "") + + re = regexp.MustCompile(`^[_\\-]+`) + return re.ReplaceAllString(removeSpecial, "") +} + +func cloudBrainNewDataPrepare(ctx *context.Context) error{ + ctx.Data["PageIsCloudBrain"] = true t := time.Now() - var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] ctx.Data["job_name"] = jobName result, err := cloudbrain.GetImages() if err != nil { ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["msgID"]) + log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["MsgID"]) } for i, payload := range result.Payload.ImageInfo { @@ -112,7 +126,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(), ctx.Data["msgID"]) + log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["MsgID"]) } for i, payload := range resultPublic.Payload.ImageInfo { @@ -127,8 +141,8 @@ func CloudBrainNew(ctx *context.Context) { attachs, err := models.GetAllUserAttachments(ctx.User.ID) if err != nil { - ctx.ServerError("GetAllUserAttachments failed:", err) - return + log.Error("GetAllUserAttachments failed: %v", err, ctx.Data["MsgID"]) + return err } ctx.Data["attachments"] = attachs @@ -155,6 +169,16 @@ func CloudBrainNew(ctx *context.Context) { ctx.Data["resource_specs"] = cloudbrain.ResourceSpecs.ResourceSpec ctx.Data["snn4imagenet_path"] = cloudbrain.Snn4imagenetMountPath ctx.Data["is_snn4imagenet_enabled"] = setting.IsSnn4imagenetEnabled + + return nil +} + +func CloudBrainNew(ctx *context.Context) { + err := cloudBrainNewDataPrepare(ctx) + if err != nil { + ctx.ServerError("get new cloudbrain info failed", err) + return + } ctx.HTML(200, tplCloudBrainNew) } @@ -170,7 +194,8 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { resourceSpecId := form.ResourceSpecId if jobType != string(models.JobTypeBenchmark) && jobType != string(models.JobTypeDebug) && jobType != string(models.JobTypeSnn4imagenet) { - log.Error("jobtype error:", jobType, ctx.Data["msgID"]) + log.Error("jobtype error:", jobType, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr("jobtype error", tplCloudBrainNew, &form) return } @@ -178,11 +203,13 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { _, err := models.GetCloudbrainByName(jobName) if err == nil { log.Error("the job name did already exist", ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) 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"]) + cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr("system error", tplCloudBrainNew, &form) return } @@ -193,6 +220,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath err = os.MkdirAll(modelPath, os.ModePerm) if err != nil { + cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) return } @@ -216,6 +244,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, jobType, gpuQueue, resourceSpecId) if err != nil { + cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) return } @@ -390,6 +419,38 @@ func CloudBrainShowModels(ctx *context.Context) { ctx.HTML(200, tplCloudBrainShowModels) } +func GetPublicImages(ctx *context.Context) { + + getImages(ctx, cloudbrain.Public) + +} + +func GetCustomImages(ctx *context.Context) { + + getImages(ctx, cloudbrain.Custom) + +} + +func getImages(ctx *context.Context, imageType string) { + log.Info("Get images begin") + + page := ctx.QueryInt("page") + size := ctx.QueryInt("size") + name := ctx.Query("name") + getImagesResult, err := cloudbrain.GetImagesPageable(page, size, imageType, name) + if err != nil { + log.Error("Can not get images:%v", err) + ctx.JSON(http.StatusOK, models.GetImagesPayload{ + Count: 0, + TotalPages: 0, + ImageInfo: []*models.ImageInfo{}, + }) + } else { + ctx.JSON(http.StatusOK, getImagesResult.Payload) + } + log.Info("Get images end") +} + func getModelDirs(jobName string, parentDir string) (string, error) { var req string modelActualPath := setting.JobPath + jobName + "/model/" @@ -406,7 +467,7 @@ func CloudBrainDownloadModel(ctx *context.Context) { parentDir := ctx.Query("parentDir") fileName := ctx.Query("fileName") jobName := ctx.Query("jobName") - filePath := "jobs/" +jobName + "/model/" + parentDir + filePath := "jobs/" + jobName + "/model/" + parentDir url, err := storage.Attachments.PresignedGetURL(filePath, fileName) if err != nil { log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) @@ -440,6 +501,45 @@ func downloadCode(repo *models.Repository, codePath string) error { return err } + configFile, err := os.OpenFile(codePath + "/.git/config", os.O_RDWR, 0666) + if err != nil { + log.Error("open file(%s) failed:%v", codePath + "/,git/config", err) + return err + } + + defer configFile.Close() + + pos := int64(0) + reader := bufio.NewReader(configFile) + for { + line, err := reader.ReadString('\n') + if err != nil { + if err == io.EOF { + log.Error("not find the remote-url") + return nil + } else { + log.Error("read error: %v", err) + return err + } + } + + if strings.Contains(line, "url") && strings.Contains(line, ".git"){ + originUrl := "\turl = " + repo.CloneLink().HTTPS + "\n" + if len(line) > len(originUrl) { + originUrl += strings.Repeat( " ", len(line) - len(originUrl)) + } + bytes := []byte(originUrl) + _, err := configFile.WriteAt(bytes, pos) + if err != nil { + log.Error("WriteAt failed:%v", err) + return err + } + break + } + + pos += int64(len(line)) + } + return nil } diff --git a/routers/repo/modelarts.go b/routers/repo/modelarts.go index 5ee566322..2dc327d33 100755 --- a/routers/repo/modelarts.go +++ b/routers/repo/modelarts.go @@ -2,6 +2,7 @@ package repo import ( "code.gitea.io/gitea/modules/modelarts" + "encoding/json" "errors" "github.com/unknwon/com" "strconv" @@ -71,7 +72,7 @@ func ModelArtsNew(ctx *context.Context) { ctx.Data["PageIsCloudBrain"] = true t := time.Now() - var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] ctx.Data["job_name"] = jobName attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID) @@ -84,7 +85,10 @@ func ModelArtsNew(ctx *context.Context) { ctx.Data["dataset_path"] = modelarts.DataSetMountPath ctx.Data["env"] = modelarts.NotebookEnv ctx.Data["notebook_type"] = modelarts.NotebookType - ctx.Data["flavor"] = modelarts.FlavorInfo + if modelarts.FlavorInfos == nil { + json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos) + } + ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo ctx.HTML(200, tplModelArtsNew) } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index b3565878e..84e2c7487 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -6,13 +6,14 @@ package routes import ( "bytes" - "code.gitea.io/gitea/routers/secure" "encoding/gob" "net/http" "path" "text/template" "time" + "code.gitea.io/gitea/routers/secure" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/context" @@ -313,11 +314,14 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("", func(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + "/explore/repos") }) + m.Get("/images/public", repo.GetPublicImages) + m.Get("/images/custom", repo.GetCustomImages) m.Get("/repos", routers.ExploreRepos) m.Get("/datasets", routers.ExploreDatasets) m.Get("/users", routers.ExploreUsers) m.Get("/organizations", routers.ExploreOrganizations) m.Get("/code", routers.ExploreCode) + m.Get("/images", routers.ExploreImages) }, ignSignIn) m.Combo("/install", routers.InstallInit).Get(routers.Install). Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index a385f2cac..3333a8cc4 100755 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -90,23 +90,12 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { } ctx.User.FullName = form.FullName - ctx.User.Email = form.Email + ctx.User.KeepEmailPrivate = form.KeepEmailPrivate ctx.User.Website = form.Website ctx.User.Location = form.Location ctx.User.Language = form.Language ctx.User.Description = form.Description - isUsed, err := models.IsEmailUsed(form.Email) - if err != nil { - ctx.ServerError("IsEmailUsed", err) - return - } - - if isUsed { - ctx.Flash.Error(ctx.Tr("form.email_been_used")) - ctx.Redirect(setting.AppSubURL + "/user/settings") - return - } if err := models.UpdateUserSetting(ctx.User); err != nil { if _, ok := err.(models.ErrEmailAlreadyUsed); ok { diff --git a/services/mailer/mail.go b/services/mailer/mail.go old mode 100644 new mode 100755 index dd5af445b..e9395f130 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -59,7 +59,7 @@ func SendTestMail(email string) error { func SendUserMail(language string, u *models.User, tpl base.TplName, code, subject, info string) { data := map[string]interface{}{ "DisplayName": u.DisplayName(), - "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language), + "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, "en-US"), "ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), "Code": code, } @@ -97,7 +97,7 @@ func SendResetPasswordMail(locale Locale, u *models.User) { func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAddress) { data := map[string]interface{}{ "DisplayName": u.DisplayName(), - "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()), + "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, "en-US"), "Code": u.GenerateEmailActivateCode(email.Email), "Email": email.Email, } diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 80d0d2275..0dac7824c 100755 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -28,6 +28,7 @@ {{.i18n.Tr "custom.head.dataset"}} {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} + {{.i18n.Tr "explore.images"}} {{else if .IsLandingPageHome}} @@ -42,6 +43,7 @@ {{.i18n.Tr "datasets"}} {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} + {{.i18n.Tr "explore.images"}} {{else if .IsLandingPageExplore}} diff --git a/templates/base/head_navbar_home.tmpl b/templates/base/head_navbar_home.tmpl index 8f89a368b..2379c1782 100644 --- a/templates/base/head_navbar_home.tmpl +++ b/templates/base/head_navbar_home.tmpl @@ -28,6 +28,7 @@ {{.i18n.Tr "custom.head.dataset"}} {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} + {{.i18n.Tr "explore.images"}} {{else if .IsLandingPageHome}} @@ -42,6 +43,7 @@ {{.i18n.Tr "datasets"}} {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} + {{.i18n.Tr "explore.images"}} {{else if .IsLandingPageExplore}} diff --git a/templates/explore/images.tmpl b/templates/explore/images.tmpl new file mode 100644 index 000000000..226a61168 --- /dev/null +++ b/templates/explore/images.tmpl @@ -0,0 +1,7 @@ +{{template "base/head" .}} +