| @@ -31,6 +31,7 @@ const ( | |||
| JobTypeBrainScore JobType = "BRAINSCORE" | |||
| JobTypeTrain JobType = "TRAIN" | |||
| //notebook | |||
| ModelArtsCreateQueue ModelArtsJobStatus = "CREATE_QUEUING" //免费资源创建排队中 | |||
| ModelArtsCreating ModelArtsJobStatus = "CREATING" //创建中 | |||
| ModelArtsCreateFailed ModelArtsJobStatus = "CREATE_FAILED" //创建失败 | |||
| @@ -46,6 +47,30 @@ const ( | |||
| ModelArtsDeleted ModelArtsJobStatus = "DELETED" //已删除 | |||
| ModelArtsResizing ModelArtsJobStatus = "RESIZING" //规格变更中 | |||
| ModelArtsResizFailed ModelArtsJobStatus = "RESIZE_FAILED" //规格变更失败 | |||
| //trainjob | |||
| ModelArtsTrainJobUnknown ModelArtsJobStatus = "UNKNOWN" //作业状态未知 | |||
| ModelArtsTrainJobInit ModelArtsJobStatus = "INIT" //作业初始化状态 | |||
| ModelArtsTrainJobImageCreating ModelArtsJobStatus = "IMAGE_CREATING" //作业镜像正在创建 | |||
| ModelArtsTrainJobImageFailed ModelArtsJobStatus = "IMAGE_FAILED" //作业镜像创建失败 | |||
| ModelArtsTrainJobSubmitTrying ModelArtsJobStatus = "SUBMIT_TRYING" //作业正在提交 | |||
| ModelArtsTrainJobSubmitFailed ModelArtsJobStatus = "SUBMIT_FAILED" //作业提交失败 | |||
| ModelArtsTrainJobDeleteFailed ModelArtsJobStatus = "DELETE_FAILED" //作业删除失败 | |||
| ModelArtsTrainJobWaiting ModelArtsJobStatus = "WAITING" //作业正在排队中 | |||
| ModelArtsTrainJobRunning ModelArtsJobStatus = "RUNNING" //作业正在运行中 | |||
| ModelArtsTrainJobKilling ModelArtsJobStatus = "KILLING" //作业正在取消 | |||
| ModelArtsTrainJobCompleted ModelArtsJobStatus = "COMPLETED" //作业已经完成 | |||
| ModelArtsTrainJobFailed ModelArtsJobStatus = "FAILED" //作业运行失败 | |||
| ModelArtsTrainJobKilled ModelArtsJobStatus = "KILLED" //作业取消成功 | |||
| ModelArtsTrainJobCanceled ModelArtsJobStatus = "CANCELED" //作业取消 | |||
| ModelArtsTrainJobLost ModelArtsJobStatus = "LOST" //作业丢失 | |||
| ModelArtsTrainJobScaling ModelArtsJobStatus = "SCALING" //作业正在扩容 | |||
| ModelArtsTrainJobSubmitModelFailed ModelArtsJobStatus = "SUBMIT_MODEL_FAILED" //提交模型失败 | |||
| ModelArtsTrainJobDeployServiceFailed ModelArtsJobStatus = "DEPLOY_SERVICE_FAILED" //部署服务失败 | |||
| ModelArtsTrainJobCheckInit ModelArtsJobStatus = "CHECK_INIT" //审核作业初始化 | |||
| ModelArtsTrainJobCheckRunning ModelArtsJobStatus = "CHECK_RUNNING" //审核作业正在运行中 | |||
| ModelArtsTrainJobCheckRunningCompleted ModelArtsJobStatus = "CHECK_RUNNING_COMPLETED" //审核作业已经完成 | |||
| ModelArtsTrainJobCheckFailed ModelArtsJobStatus = "CHECK_FAILED" //审核作业失败 | |||
| ) | |||
| type Cloudbrain struct { | |||
| @@ -66,6 +91,7 @@ type Cloudbrain struct { | |||
| DeletedAt time.Time `xorm:"deleted"` | |||
| CanDebug bool `xorm:"-"` | |||
| CanDel bool `xorm:"-"` | |||
| CanModify bool `xorm:"-"` | |||
| Type int | |||
| VersionID int64 //版本id | |||
| @@ -1007,13 +1033,13 @@ func GetCloudbrainByJobIDAndIsLatestVersion(jobID string, isLatestVersion string | |||
| func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | |||
| cloudBrains := make([]*Cloudbrain, 0) | |||
| err := x.Cols("job_id", "status", "type").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | |||
| err := x.Cols("job_id", "status", "type", "job_type", "version_id").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | |||
| return cloudBrains, err | |||
| } | |||
| func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) { | |||
| cloudBrains := make([]*Cloudbrain, 0) | |||
| err := x.Cols("job_id", "status", "type").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains) | |||
| err := x.Cols("job_id", "status", "type", "job_type", "version_id").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains) | |||
| return cloudBrains, err | |||
| } | |||
| @@ -1091,3 +1117,31 @@ func CanDelJob(isSigned bool, user *User, job *CloudbrainInfo) bool { | |||
| } | |||
| return false | |||
| } | |||
| func GetCloudBrainUnStoppedJob() ([]*Cloudbrain, error) { | |||
| cloudbrains := make([]*Cloudbrain, 0, 10) | |||
| return cloudbrains, x. | |||
| NotIn("status", | |||
| JobStopped, JobSucceeded, JobFailed, ModelArtsCreateFailed, ModelArtsStartFailed, ModelArtsUnavailable, ModelArtsResizFailed, ModelArtsDeleted, | |||
| ModelArtsStopped, ModelArtsTrainJobCanceled, ModelArtsTrainJobCheckFailed, ModelArtsTrainJobCompleted, ModelArtsTrainJobDeleteFailed, ModelArtsTrainJobDeployServiceFailed, | |||
| ModelArtsTrainJobFailed, ModelArtsTrainJobImageFailed, ModelArtsTrainJobKilled, ModelArtsTrainJobLost, ModelArtsTrainJobSubmitFailed, ModelArtsTrainJobSubmitModelFailed). | |||
| Limit(100). | |||
| Find(&cloudbrains) | |||
| } | |||
| func GetCloudbrainCountByUserID(userID int64) (int, error) { | |||
| count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainOne).Count(new(Cloudbrain)) | |||
| return int(count), err | |||
| } | |||
| func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { | |||
| count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting). | |||
| And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) | |||
| return int(count), err | |||
| } | |||
| func GetCloudbrainTrainJobCountByUserID(userID int64) (int, error) { | |||
| count, err := x.In("status", ModelArtsTrainJobInit, ModelArtsTrainJobImageCreating, ModelArtsTrainJobSubmitTrying, ModelArtsTrainJobWaiting, ModelArtsTrainJobRunning, ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobCheckRunningCompleted). | |||
| And("job_type = ? and user_id = ? and type = ?", JobTypeTrain, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) | |||
| return int(count), err | |||
| } | |||
| @@ -667,15 +667,11 @@ func (repo *Repository) getReviewersPublic(e Engine, doerID, posterID int64) (_ | |||
| users := make([]*User, 0) | |||
| const SQLCmd = "SELECT * FROM `user` WHERE id IN ( " + | |||
| "SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?) " + | |||
| "UNION " + | |||
| "SELECT user_id FROM `watch` WHERE repo_id = ? AND user_id NOT IN ( ?, ?) AND mode IN (?, ?) " + | |||
| ") ORDER BY name" | |||
| "SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?) ) ORDER BY name " | |||
| if err = e. | |||
| SQL(SQLCmd, | |||
| repo.ID, AccessModeRead, doerID, posterID, | |||
| repo.ID, doerID, posterID, RepoWatchModeNormal, RepoWatchModeAuto). | |||
| repo.ID, AccessModeWrite, doerID, posterID). | |||
| Find(&users); err != nil { | |||
| return nil, err | |||
| } | |||
| @@ -145,6 +145,7 @@ type User struct { | |||
| AllowImportLocal bool // Allow migrate repository by local path | |||
| AllowCreateOrganization bool `xorm:"DEFAULT true"` | |||
| ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"` | |||
| IsOperator bool `xorm:"NOT NULL DEFAULT false"` //运营人员 | |||
| // Avatar | |||
| Avatar string `xorm:"VARCHAR(2048) NOT NULL"` | |||
| @@ -928,8 +929,17 @@ var ( | |||
| "template", | |||
| "user", | |||
| "vendor", | |||
| } | |||
| reservedUserPatterns = []string{"*.keys", "*.gpg"} | |||
| "dashbord", | |||
| "operation", | |||
| "blockchain", | |||
| "avatar", | |||
| "swagger.v1.json", | |||
| "secure", | |||
| "serviceworker.js", | |||
| "self", | |||
| "repo-avatars", | |||
| } | |||
| reservedUserPatterns = []string{"*.keys", "*.gpg", "*.png"} | |||
| ) | |||
| // isUsableName checks if name is reserved or pattern of name is not allowed | |||
| @@ -1551,11 +1561,11 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||
| if err := ctx.e.Join("INNER", "email_address", "email_address.uid = \"user\".id"). | |||
| Where("email_address.email= ?", email). | |||
| Find(&users); err != nil { | |||
| return nil,err | |||
| return nil, err | |||
| } | |||
| if len(users) >= 1 { | |||
| return &users[0],nil | |||
| }else { | |||
| return &users[0], nil | |||
| } else { | |||
| // Finally, if email address is the protected email address:用户邮件地址设置为隐藏电子邮件地址 | |||
| if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { | |||
| username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) | |||
| @@ -1571,6 +1581,7 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||
| return nil, errors.New("cannot find user by email") | |||
| } | |||
| } | |||
| // GetUserByEmail returns the user object by given e-mail if exists. | |||
| func GetUserByEmail(email string) (*User, error) { | |||
| return GetUserByEmailContext(DefaultDBContext(), email) | |||
| @@ -9,6 +9,9 @@ import ( | |||
| "reflect" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/base" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth/sso" | |||
| "code.gitea.io/gitea/modules/validation" | |||
| @@ -31,6 +34,8 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) | |||
| return nil, false | |||
| } | |||
| checkAutoLogin(ctx, sess) | |||
| // Try to sign in with each of the enabled plugins | |||
| for _, ssoMethod := range sso.Methods() { | |||
| if !ssoMethod.IsEnabled() { | |||
| @@ -46,6 +51,23 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) | |||
| return nil, false | |||
| } | |||
| func checkAutoLogin(ctx *macaron.Context, sess session.Store) { | |||
| uid := sess.Get("uid") | |||
| if uid == nil { | |||
| uname := ctx.GetCookie(setting.CookieUserName) | |||
| u, err := models.GetUserByName(uname) | |||
| if err == nil { | |||
| if val, ok := ctx.GetSuperSecureCookie( | |||
| base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); ok && val == u.Name { | |||
| sess.Set("uid", u.ID) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Form form binding interface | |||
| type Form interface { | |||
| binding.Validator | |||
| @@ -1,9 +1,10 @@ | |||
| package cloudbrain | |||
| import ( | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "errors" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| @@ -16,7 +17,7 @@ const ( | |||
| ModelMountPath = "/model" | |||
| BenchMarkMountPath = "/benchmark" | |||
| Snn4imagenetMountPath = "/snn4imagenet" | |||
| BrainScoreMountPath = "/brainscore" | |||
| BrainScoreMountPath = "/brainscore" | |||
| TaskInfoName = "/taskInfo" | |||
| SubTaskName = "task1" | |||
| @@ -28,6 +29,72 @@ var ( | |||
| ResourceSpecs *models.ResourceSpecs | |||
| ) | |||
| func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
| if err != nil { | |||
| return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() | |||
| } else { | |||
| return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID | |||
| } | |||
| } | |||
| func CanDeleteDebugJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
| if job.Status != string(models.JobStopped) && job.Status != string(models.JobFailed) && job.Status != string(models.ModelArtsStartFailed) && job.Status != string(models.ModelArtsCreateFailed) { | |||
| return false | |||
| } | |||
| return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||
| } | |||
| func CanDeleteTrainJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
| return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||
| } | |||
| func CanCreateOrDebugJob(ctx *context.Context) bool { | |||
| return ctx.Repo.CanWrite(models.UnitTypeCloudBrain) | |||
| } | |||
| func CanModifyJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
| return isAdminOrJobCreater(ctx, job, nil) | |||
| } | |||
| func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
| if err != nil { | |||
| return ctx.IsUserSiteAdmin() | |||
| } else { | |||
| return ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID | |||
| } | |||
| } | |||
| func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||
| var jobID = ctx.Params(":jobid") | |||
| job, err := models.GetCloudbrainByJobID(jobID) | |||
| if !isAdminOrOwnerOrJobCreater(ctx, job, err) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| } | |||
| func AdminOrJobCreaterRight(ctx *context.Context) { | |||
| var jobID = ctx.Params(":jobid") | |||
| job, err := models.GetCloudbrainByJobID(jobID) | |||
| if !isAdminOrJobCreater(ctx, job, err) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| } | |||
| func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue string, resourceSpecId int) error { | |||
| dataActualPath := setting.Attachment.Minio.RealPath + | |||
| setting.Attachment.Minio.Bucket + "/" + | |||
| @@ -145,8 +145,7 @@ func Toggle(options *ToggleOptions) macaron.Handler { | |||
| } | |||
| if options.OperationRequired { | |||
| //todo: add isOperator judgement | |||
| if !ctx.User.IsAdmin { | |||
| if !ctx.User.IsOperator { | |||
| ctx.Error(403) | |||
| return | |||
| } | |||
| @@ -310,6 +310,7 @@ func Contexter() macaron.Handler { | |||
| ctx.Data["SignedUserID"] = ctx.User.ID | |||
| ctx.Data["SignedUserName"] = ctx.User.Name | |||
| ctx.Data["IsAdmin"] = ctx.User.IsAdmin | |||
| ctx.Data["IsOperator"] = ctx.User.IsOperator | |||
| c.Data["SignedUserName"] = ctx.User.Name | |||
| } else { | |||
| ctx.Data["SignedUserID"] = int64(0) | |||
| @@ -524,7 +524,7 @@ func RepoAssignment() macaron.Handler { | |||
| } | |||
| ctx.Data["Tags"] = tags | |||
| brs, err := ctx.Repo.GitRepo.GetBranches() | |||
| brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches", err) | |||
| return | |||
| @@ -712,7 +712,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler { | |||
| refName = ctx.Repo.Repository.DefaultBranch | |||
| ctx.Repo.BranchName = refName | |||
| if !ctx.Repo.GitRepo.IsBranchExist(refName) { | |||
| brs, err := ctx.Repo.GitRepo.GetBranches() | |||
| brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches", err) | |||
| return | |||
| @@ -185,6 +185,17 @@ func registerHandleSummaryStatistic() { | |||
| }) | |||
| } | |||
| func registerSyncCloudbrainStatus() { | |||
| RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{ | |||
| Enabled: true, | |||
| RunAtStart: false, | |||
| Schedule: "@every 10m", | |||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | |||
| repo.SyncCloudbrainStatus() | |||
| return nil | |||
| }) | |||
| } | |||
| func initBasicTasks() { | |||
| registerUpdateMirrorTask() | |||
| registerRepoHealthCheck() | |||
| @@ -202,4 +213,6 @@ func initBasicTasks() { | |||
| registerHandleRepoAndUserStatistic() | |||
| registerHandleSummaryStatistic() | |||
| registerSyncCloudbrainStatus() | |||
| } | |||
| @@ -6,7 +6,9 @@ | |||
| package git | |||
| import ( | |||
| "bufio" | |||
| "fmt" | |||
| "io" | |||
| "strings" | |||
| "github.com/go-git/go-git/v5/plumbing" | |||
| @@ -74,25 +76,6 @@ func (repo *Repository) SetDefaultBranch(name string) error { | |||
| return err | |||
| } | |||
| // GetBranches returns all branches of the repository. | |||
| func (repo *Repository) GetBranches() ([]string, error) { | |||
| var branchNames []string | |||
| branches, err := repo.gogitRepo.Branches() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| _ = branches.ForEach(func(branch *plumbing.Reference) error { | |||
| branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix)) | |||
| return nil | |||
| }) | |||
| // TODO: Sort? | |||
| return branchNames, nil | |||
| } | |||
| // GetBranch returns a branch by it's name | |||
| func (repo *Repository) GetBranch(branch string) (*Branch, error) { | |||
| if !repo.IsBranchExist(branch) { | |||
| @@ -106,16 +89,16 @@ func (repo *Repository) GetBranch(branch string) (*Branch, error) { | |||
| } | |||
| // GetBranchesByPath returns a branch by it's path | |||
| func GetBranchesByPath(path string) ([]*Branch, error) { | |||
| func GetBranchesByPath(path string, skip, limit int) ([]*Branch, int, error) { | |||
| gitRepo, err := OpenRepository(path) | |||
| if err != nil { | |||
| return nil, err | |||
| return nil, 0, err | |||
| } | |||
| defer gitRepo.Close() | |||
| brs, err := gitRepo.GetBranches() | |||
| brs, countAll, err := gitRepo.GetBranches(skip, limit) | |||
| if err != nil { | |||
| return nil, err | |||
| return nil, 0, err | |||
| } | |||
| branches := make([]*Branch, len(brs)) | |||
| @@ -127,7 +110,7 @@ func GetBranchesByPath(path string) ([]*Branch, error) { | |||
| } | |||
| } | |||
| return branches, nil | |||
| return branches, countAll, nil | |||
| } | |||
| // DeleteBranchOptions Option(s) for delete branch | |||
| @@ -183,3 +166,91 @@ func (repo *Repository) RemoveRemote(name string) error { | |||
| func (branch *Branch) GetCommit() (*Commit, error) { | |||
| return branch.gitRepo.GetBranchCommit(branch.Name) | |||
| } | |||
| // GetBranches returns branches from the repository, skipping skip initial branches and | |||
| // returning at most limit branches, or all branches if limit is 0. | |||
| func (repo *Repository) GetBranches(skip, limit int) ([]string, int, error) { | |||
| return callShowRef(repo.Path, BranchPrefix, "--heads", skip, limit) | |||
| } | |||
| // callShowRef return refs, if limit = 0 it will not limit | |||
| func callShowRef(repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) { | |||
| stdoutReader, stdoutWriter := io.Pipe() | |||
| defer func() { | |||
| _ = stdoutReader.Close() | |||
| _ = stdoutWriter.Close() | |||
| }() | |||
| go func() { | |||
| stderrBuilder := &strings.Builder{} | |||
| err := NewCommand("show-ref", arg).RunInDirPipeline(repoPath, stdoutWriter, stderrBuilder) | |||
| if err != nil { | |||
| if stderrBuilder.Len() == 0 { | |||
| _ = stdoutWriter.Close() | |||
| return | |||
| } | |||
| _ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String())) | |||
| } else { | |||
| _ = stdoutWriter.Close() | |||
| } | |||
| }() | |||
| i := 0 | |||
| bufReader := bufio.NewReader(stdoutReader) | |||
| for i < skip { | |||
| _, isPrefix, err := bufReader.ReadLine() | |||
| if err == io.EOF { | |||
| return branchNames, i, nil | |||
| } | |||
| if err != nil { | |||
| return nil, 0, err | |||
| } | |||
| if !isPrefix { | |||
| i++ | |||
| } | |||
| } | |||
| for limit == 0 || i < skip+limit { | |||
| // The output of show-ref is simply a list: | |||
| // <sha> SP <ref> LF | |||
| _, err := bufReader.ReadSlice(' ') | |||
| for err == bufio.ErrBufferFull { | |||
| // This shouldn't happen but we'll tolerate it for the sake of peace | |||
| _, err = bufReader.ReadSlice(' ') | |||
| } | |||
| if err == io.EOF { | |||
| return branchNames, i, nil | |||
| } | |||
| if err != nil { | |||
| return nil, 0, err | |||
| } | |||
| branchName, err := bufReader.ReadString('\n') | |||
| if err == io.EOF { | |||
| // This shouldn't happen... but we'll tolerate it for the sake of peace | |||
| return branchNames, i, nil | |||
| } | |||
| if err != nil { | |||
| return nil, i, err | |||
| } | |||
| branchName = strings.TrimPrefix(branchName, prefix) | |||
| if len(branchName) > 0 { | |||
| branchName = branchName[:len(branchName)-1] | |||
| } | |||
| branchNames = append(branchNames, branchName) | |||
| i++ | |||
| } | |||
| // count all refs | |||
| for limit != 0 { | |||
| _, isPrefix, err := bufReader.ReadLine() | |||
| if err == io.EOF { | |||
| return branchNames, i, nil | |||
| } | |||
| if err != nil { | |||
| return nil, 0, err | |||
| } | |||
| if !isPrefix { | |||
| i++ | |||
| } | |||
| } | |||
| return branchNames, i, nil | |||
| } | |||
| @@ -10,7 +10,6 @@ import ( | |||
| "strings" | |||
| "github.com/go-git/go-git/v5/plumbing" | |||
| "github.com/mcuadros/go-version" | |||
| ) | |||
| // TagPrefix tags prefix path on the repository | |||
| @@ -225,29 +224,35 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, error) { | |||
| return tags, nil | |||
| } | |||
| // GetTags returns all tags of the repository. | |||
| func (repo *Repository) GetTags() ([]string, error) { | |||
| var tagNames []string | |||
| tags, err := repo.gogitRepo.Tags() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| //// GetTags returns all tags of the repository. | |||
| //func (repo *Repository) GetTags() ([]string, error) { | |||
| // var tagNames []string | |||
| // | |||
| // tags, err := repo.gogitRepo.Tags() | |||
| // if err != nil { | |||
| // return nil, err | |||
| // } | |||
| // | |||
| // _ = tags.ForEach(func(tag *plumbing.Reference) error { | |||
| // tagNames = append(tagNames, strings.TrimPrefix(tag.Name().String(), TagPrefix)) | |||
| // return nil | |||
| // }) | |||
| // | |||
| // version.Sort(tagNames) | |||
| // | |||
| // // Reverse order | |||
| // for i := 0; i < len(tagNames)/2; i++ { | |||
| // j := len(tagNames) - i - 1 | |||
| // tagNames[i], tagNames[j] = tagNames[j], tagNames[i] | |||
| // } | |||
| // | |||
| // return tagNames, nil | |||
| //} | |||
| _ = tags.ForEach(func(tag *plumbing.Reference) error { | |||
| tagNames = append(tagNames, strings.TrimPrefix(tag.Name().String(), TagPrefix)) | |||
| return nil | |||
| }) | |||
| version.Sort(tagNames) | |||
| // Reverse order | |||
| for i := 0; i < len(tagNames)/2; i++ { | |||
| j := len(tagNames) - i - 1 | |||
| tagNames[i], tagNames[j] = tagNames[j], tagNames[i] | |||
| } | |||
| return tagNames, nil | |||
| // GetTags returns all tags of the repository. | |||
| func (repo *Repository) GetTags() (tags []string, err error) { | |||
| tags, _, err = callShowRef(repo.Path, TagPrefix, "--tags", 0, 0) | |||
| return | |||
| } | |||
| // GetTagType gets the type of the tag, either commit (simple) or tag (annotated) | |||
| @@ -140,3 +140,11 @@ func ParseBool(value string) (result bool, valid bool) { | |||
| } | |||
| return intValue != 0, true | |||
| } | |||
| // ConcatenateError concatenats an error with stderr string | |||
| func ConcatenateError(err error, stderr string) error { | |||
| if len(stderr) == 0 { | |||
| return err | |||
| } | |||
| return fmt.Errorf("%w - %s", err, stderr) | |||
| } | |||
| @@ -13,6 +13,9 @@ import ( | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "golang.org/x/net/proxy" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/migrations/base" | |||
| "code.gitea.io/gitea/modules/structs" | |||
| @@ -98,13 +101,41 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith | |||
| ) | |||
| client = oauth2.NewClient(downloader.ctx, ts) | |||
| } else { | |||
| client = &http.Client{ | |||
| Transport: &http.Transport{ | |||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||
| req.SetBasicAuth(userName, password) | |||
| return nil, nil | |||
| if setting.Migrations.Proxy != "" { | |||
| contextDialer, err := getProxyDialContext() | |||
| if err != nil { | |||
| log.Warn("Failed to use proxy for Github.", err) | |||
| client = &http.Client{ | |||
| Transport: &http.Transport{ | |||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||
| req.SetBasicAuth(userName, password) | |||
| return nil, nil | |||
| }, | |||
| }, | |||
| } | |||
| } else { | |||
| client = &http.Client{ | |||
| Transport: &http.Transport{ | |||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||
| req.SetBasicAuth(userName, password) | |||
| return nil, nil | |||
| }, | |||
| DialContext: contextDialer.DialContext, | |||
| }, | |||
| } | |||
| } | |||
| } else { | |||
| client = &http.Client{ | |||
| Transport: &http.Transport{ | |||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||
| req.SetBasicAuth(userName, password) | |||
| return nil, nil | |||
| }, | |||
| }, | |||
| }, | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -112,6 +143,25 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith | |||
| return &downloader | |||
| } | |||
| func getProxyDialContext() (proxy.ContextDialer, error) { | |||
| authInfo := &proxy.Auth{ | |||
| setting.Migrations.Username, | |||
| setting.Migrations.Password, | |||
| } | |||
| dialSocksProxy, err := proxy.SOCKS5("tcp", setting.Migrations.Proxy, authInfo, proxy.Direct) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok { | |||
| return contextDialer, nil | |||
| } else { | |||
| return nil, fmt.Errorf("It is not a valiad dialer.") | |||
| } | |||
| } | |||
| // SetContext set context | |||
| func (g *GithubDownloaderV3) SetContext(ctx context.Context) { | |||
| g.ctx = ctx | |||
| @@ -23,9 +23,10 @@ func GetBranch(repo *models.Repository, branch string) (*git.Branch, error) { | |||
| return gitRepo.GetBranch(branch) | |||
| } | |||
| // GetBranches returns all the branches of a repository | |||
| func GetBranches(repo *models.Repository) ([]*git.Branch, error) { | |||
| return git.GetBranchesByPath(repo.RepoPath()) | |||
| // GetBranches returns branches from the repository, skipping skip initial branches and | |||
| // returning at most limit branches, or all branches if limit is 0. | |||
| func GetBranches(repo *models.Repository, skip, limit int) ([]*git.Branch, int, error) { | |||
| return git.GetBranchesByPath(repo.RepoPath(), skip, limit) | |||
| } | |||
| // checkBranchName validates branch name with existing repository branches | |||
| @@ -36,7 +37,7 @@ func checkBranchName(repo *models.Repository, name string) error { | |||
| } | |||
| defer gitRepo.Close() | |||
| branches, err := GetBranches(repo) | |||
| branches, _, err := GetBranches(repo, 0, 0) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| @@ -6,6 +6,7 @@ package repository | |||
| import ( | |||
| "fmt" | |||
| "net/url" | |||
| "os" | |||
| "path" | |||
| "strings" | |||
| @@ -54,29 +55,34 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||
| repo.NumWatches = 1 | |||
| } | |||
| migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||
| migrateTimeout := getMigrateTimeout(opts.CloneAddr) | |||
| var err error | |||
| if err = os.RemoveAll(repoPath); err != nil { | |||
| return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) | |||
| } | |||
| log.Info("clone begin:" + opts.CloneAddr) | |||
| if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ | |||
| Mirror: true, | |||
| Quiet: true, | |||
| Timeout: migrateTimeout, | |||
| }); err != nil { | |||
| log.Warn("clone err") | |||
| return repo, fmt.Errorf("Clone: %v", err) | |||
| } | |||
| log.Info("clone end:" + opts.CloneAddr) | |||
| if opts.Wiki { | |||
| log.Info("test wiki path begin") | |||
| wikiPath := models.WikiPath(u.Name, opts.RepoName) | |||
| wikiRemotePath := wikiRemoteURL(opts.CloneAddr) | |||
| log.Info("test wiki path end") | |||
| if len(wikiRemotePath) > 0 { | |||
| if err := os.RemoveAll(wikiPath); err != nil { | |||
| return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | |||
| } | |||
| log.Info("wiki clone begin") | |||
| if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ | |||
| Mirror: true, | |||
| Quiet: true, | |||
| @@ -88,6 +94,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||
| return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | |||
| } | |||
| } | |||
| log.Info("wiki clone end") | |||
| } | |||
| } | |||
| @@ -137,9 +144,20 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||
| repo, err = CleanUpMigrateInfo(repo) | |||
| } | |||
| log.Info("clone all end:" + opts.CloneAddr) | |||
| return repo, err | |||
| } | |||
| func getMigrateTimeout(urlClone string) time.Duration { | |||
| u, err := url.Parse(urlClone) | |||
| if err == nil && strings.EqualFold(u.Host, "github.com") { | |||
| return time.Duration(setting.Git.Timeout.GitHubMigrate) * time.Second | |||
| } | |||
| return time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||
| } | |||
| // cleanUpMigrateGitConfig removes mirror info which prevents "push --all". | |||
| // This also removes possible user credentials. | |||
| func cleanUpMigrateGitConfig(configPath string) error { | |||
| @@ -27,12 +27,13 @@ var ( | |||
| EnableAutoGitWireProtocol bool | |||
| PullRequestPushMessage bool | |||
| Timeout struct { | |||
| Default int | |||
| Migrate int | |||
| Mirror int | |||
| Clone int | |||
| Pull int | |||
| GC int `ini:"GC"` | |||
| Default int | |||
| Migrate int | |||
| GitHubMigrate int | |||
| Mirror int | |||
| Clone int | |||
| Pull int | |||
| GC int `ini:"GC"` | |||
| } `ini:"git.timeout"` | |||
| }{ | |||
| DisableDiffHighlight: false, | |||
| @@ -45,19 +46,21 @@ var ( | |||
| EnableAutoGitWireProtocol: true, | |||
| PullRequestPushMessage: true, | |||
| Timeout: struct { | |||
| Default int | |||
| Migrate int | |||
| Mirror int | |||
| Clone int | |||
| Pull int | |||
| GC int `ini:"GC"` | |||
| Default int | |||
| Migrate int | |||
| GitHubMigrate int | |||
| Mirror int | |||
| Clone int | |||
| Pull int | |||
| GC int `ini:"GC"` | |||
| }{ | |||
| Default: int(git.DefaultCommandExecutionTimeout / time.Second), | |||
| Migrate: 600, | |||
| Mirror: 300, | |||
| Clone: 300, | |||
| Pull: 300, | |||
| GC: 60, | |||
| Default: int(git.DefaultCommandExecutionTimeout / time.Second), | |||
| Migrate: 900, | |||
| GitHubMigrate: 1800, | |||
| Mirror: 1200, | |||
| Clone: 300, | |||
| Pull: 300, | |||
| GC: 60, | |||
| }, | |||
| } | |||
| ) | |||
| @@ -83,6 +83,7 @@ func newIndexerService() { | |||
| Indexer.UpdateQueueLength = sec.Key("UPDATE_BUFFER_LEN").MustInt(20) | |||
| Indexer.MaxIndexerFileSize = sec.Key("MAX_FILE_SIZE").MustInt64(1024 * 1024) | |||
| Indexer.StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(30 * time.Second) | |||
| log.Info("New IndexerService Inited.") | |||
| } | |||
| // IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing | |||
| @@ -9,6 +9,9 @@ var ( | |||
| Migrations = struct { | |||
| MaxAttempts int | |||
| RetryBackoff int | |||
| Proxy string | |||
| Username string | |||
| Password string | |||
| }{ | |||
| MaxAttempts: 3, | |||
| RetryBackoff: 3, | |||
| @@ -19,4 +22,7 @@ func newMigrationsService() { | |||
| sec := Cfg.Section("migrations") | |||
| Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) | |||
| Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) | |||
| Migrations.Proxy = sec.Key("Proxy").MustString("") | |||
| Migrations.Username = sec.Key("Username").MustString("") | |||
| Migrations.Password = sec.Key("Password").MustString("") | |||
| } | |||
| @@ -160,6 +160,7 @@ func NewQueueService() { | |||
| if _, ok := sectionMap["LENGTH"]; !ok { | |||
| _, _ = section.NewKey("LENGTH", fmt.Sprintf("%d", Repository.PullRequestQueueLength)) | |||
| } | |||
| log.Info("New QueueService Inited.") | |||
| } | |||
| // ParseQueueConnStr parses a queue connection string | |||
| @@ -48,4 +48,5 @@ func newWebhookService() { | |||
| } | |||
| } | |||
| Webhook.ProxyHosts = sec.Key("PROXY_HOSTS").Strings(",") | |||
| log.Info("New WebhookService Inited.") | |||
| } | |||
| @@ -51,6 +51,7 @@ func Init() error { | |||
| switch setting.Attachment.StoreType { | |||
| case LocalStorageType: | |||
| Attachments, err = NewLocalStorage(setting.Attachment.Path) | |||
| log.Info("local storage inited.") | |||
| case MinioStorageType: | |||
| minio := setting.Attachment.Minio | |||
| Attachments, err = NewMinioStorage( | |||
| @@ -62,6 +63,7 @@ func Init() error { | |||
| minio.BasePath, | |||
| minio.UseSSL, | |||
| ) | |||
| log.Info("minio storage inited.") | |||
| default: | |||
| return fmt.Errorf("Unsupported attachment store type: %s", setting.Attachment.StoreType) | |||
| } | |||
| @@ -71,6 +73,7 @@ func Init() error { | |||
| log.Error("obs.New failed:", err) | |||
| return err | |||
| } | |||
| log.Info("obs cli inited.") | |||
| if err != nil { | |||
| return err | |||
| @@ -228,6 +228,7 @@ users=用户 | |||
| organizations=组织 | |||
| images = 云脑镜像 | |||
| search=搜索 | |||
| search_pro=搜项目 | |||
| code=代码 | |||
| data_analysis=数字看板(内测) | |||
| repo_no_results=未找到匹配的项目。 | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638325192035" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2222" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M979.792374 404.577188 574.183101 83.942886c-34.918864-27.694272-89.619352-27.694272-124.538216 0L44.207626 404.577188c-13.933143 11.008903-16.169326 31.134554-5.332437 44.895683s30.618512 16.169326 44.551655 5.332437l12.55703-10.320847 0 387.547791c0 54.872501 57.968755 95.983874 108.712918 95.983874l639.892491 0c50.22812 0 83.254829-38.531161 83.254829-95.983874L927.844112 445.860575l11.69696 8.944734c5.84848 4.644381 13.073072 6.880564 20.125651 6.880564 9.460776 0 18.921552-4.128339 25.286074-12.213002C995.9617 435.711742 993.725517 415.586091 979.792374 404.577188zM479.919368 864.026877 479.919368 686.508315c0-8.77272 15.997312-13.245087 31.994625-13.245087s31.994625 4.472367 31.994625 13.245087l0 177.346548L479.919368 864.026877 479.919368 864.026877zM864.026877 832.032253c0 21.157736-5.84848 31.994625-19.26558 31.994625L608.585923 864.026877c0-0.516042-0.688056-0.860071-0.688056-1.376113L607.897867 686.508315c0-37.155048-29.930455-77.234336-95.983874-77.234336s-95.983874 40.079288-95.983874 77.234336l0 176.142449c0 0.516042 0.860071 0.860071 0.860071 1.376113L204.868806 864.026877c-20.125651 0-44.723669-17.373425-44.723669-31.994625L160.145137 393.740299 488.864102 134.171006c11.868974-9.288762 33.198723-9.288762 44.895683 0l330.095078 261.11742L863.854863 832.032253z" p-id="2223" fill="#1684FC"></path></svg> | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638171446718" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2430" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 69.717333l383.018667 221.141334v442.282666L512 954.282667 128.981333 733.141333V290.858667L512 69.717333zM192.96 375.402667v320.768L480 861.888V541.141333l-287.04-165.76z m638.058667 0L544 541.162667V861.866667l287.018667-165.717334V375.424zM512 143.637333L215.722667 314.666667 512 485.717333l296.256-171.050666L512 143.616z" fill="#1684FC" p-id="2431"></path></svg> | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638433773401" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2884" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M469.333333 768c-166.4 0-298.666667-132.266667-298.666666-298.666667s132.266667-298.666667 298.666666-298.666666 298.666667 132.266667 298.666667 298.666666-132.266667 298.666667-298.666667 298.666667z m0-85.333333c119.466667 0 213.333333-93.866667 213.333334-213.333334s-93.866667-213.333333-213.333334-213.333333-213.333333 93.866667-213.333333 213.333333 93.866667 213.333333 213.333333 213.333334z m251.733334 0l119.466666 119.466666-59.733333 59.733334-119.466667-119.466667 59.733334-59.733333z" fill="#5BB973" p-id="2885"></path></svg> | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638171175505" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2087" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M947.924 963.76c0 21.752-17.62 39.372-39.354 39.372-21.75 0-39.37-17.62-39.37-39.371l-0.354-3.655c0-1.554 0.283-3.054 0.442-4.59-24.576-172.792-172.72-299.768-353.104-301.763-1.447 0.036-2.825 0.23-4.29 0.23-1.43 0-2.807-0.194-4.237-0.23C329.34 655.731 182.607 779.9 155.56 949.69c0.9 3.337 1.536 6.78 1.536 10.4l0.37 3.707c0 22.086-17.902 39.989-39.97 39.989s-39.99-17.903-39.99-39.99l-0.035-0.352h-0.76c0.107-1.165 0.336-2.278 0.46-3.425 0-3.302 0.53-6.427 1.27-9.499C98.94 791.217 205.684 662.422 350.968 606.95c-84.586-54.2-139.74-149.963-139.74-259.372 0-169.224 131.478-306.405 300.702-306.405 169.208 0 300.703 137.18 300.703 306.405 0 109.374-55.102 205.118-139.652 259.32 144.278 55.03 250.544 182.325 272.19 340.038 1.465 4.131 2.436 8.528 2.436 13.17l0.318 3.656z m-204.43-616.094c0-127.947-103.706-231.654-231.653-231.654S280.188 219.736 280.188 347.666c0 127.929 103.724 231.636 231.653 231.636s231.654-103.707 231.654-231.636z" fill="#1684FC" p-id="2088"></path></svg> | |||
| @@ -75,6 +75,7 @@ import ( | |||
| "code.gitea.io/gitea/routers/api/v1/repo" | |||
| _ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation | |||
| "code.gitea.io/gitea/routers/api/v1/user" | |||
| repo_ext "code.gitea.io/gitea/routers/repo" | |||
| "gitea.com/macaron/binding" | |||
| "gitea.com/macaron/macaron" | |||
| @@ -523,23 +524,26 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| Get(notify.GetThread). | |||
| Patch(notify.ReadThread) | |||
| }, reqToken()) | |||
| adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | |||
| operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true}) | |||
| //Project board | |||
| m.Group("/projectboard", func() { | |||
| m.Get("/restoreFork", adminReq, repo.RestoreForkNumber) | |||
| m.Get("/downloadAll", adminReq, repo.ServeAllProjectsPeriodStatisticsFile) | |||
| m.Get("/downloadAllOpenI", adminReq, repo.ServeAllProjectsOpenIStatisticsFile) | |||
| m.Get("/restoreFork", repo.RestoreForkNumber) | |||
| m.Get("/downloadAll", repo.ServeAllProjectsPeriodStatisticsFile) | |||
| m.Get("/downloadAllOpenI", repo.ServeAllProjectsOpenIStatisticsFile) | |||
| m.Group("/project", func() { | |||
| m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics) | |||
| m.Get("", repo.GetAllProjectsPeriodStatistics) | |||
| m.Group("/:id", func() { | |||
| m.Get("", adminReq, repo.GetProjectLatestStatistics) | |||
| m.Get("/period", adminReq, repo.GetProjectPeriodStatistics) | |||
| m.Get("", repo.GetProjectLatestStatistics) | |||
| m.Get("/period", repo.GetProjectPeriodStatistics) | |||
| }) | |||
| }) | |||
| }) | |||
| }, operationReq) | |||
| m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage) | |||
| // Users | |||
| m.Group("/users", func() { | |||
| @@ -204,7 +204,7 @@ func ListBranches(ctx *context.APIContext) { | |||
| // "200": | |||
| // "$ref": "#/responses/BranchList" | |||
| branches, err := repo_module.GetBranches(ctx.Repo.Repository) | |||
| branches, _, err := repo_module.GetBranches(ctx.Repo.Repository,0,0) | |||
| if err != nil { | |||
| ctx.Error(http.StatusInternalServerError, "GetBranches", err) | |||
| return | |||
| @@ -5,6 +5,7 @@ import ( | |||
| "net/http" | |||
| "net/url" | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| "github.com/360EntSecGroup-Skylar/excelize/v2" | |||
| @@ -467,7 +468,7 @@ func generateCountSql(beginTime time.Time, endTime time.Time, latestDate string, | |||
| "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" + | |||
| " where A.repo_id=B.repo_id" | |||
| if q != "" { | |||
| countSql = countSql + " and B.name like '%" + q + "%'" | |||
| countSql = countSql + " and LOWER(B.name) like '%" + strings.ToLower(q) + "%'" | |||
| } | |||
| return countSql | |||
| } | |||
| @@ -488,7 +489,7 @@ func generateTypeAllSql(beginTime time.Time, endTime time.Time, latestDate strin | |||
| " where A.repo_id=B.repo_id" | |||
| if q != "" { | |||
| sql = sql + " and name like '%" + q + "%'" | |||
| sql = sql + " and LOWER(name) like '%" + strings.ToLower(q) + "%'" | |||
| } | |||
| sql = sql + " order by " + orderBy + " desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | |||
| return sql | |||
| @@ -511,7 +512,7 @@ func generatePageSql(beginTime time.Time, endTime time.Time, latestDate string, | |||
| "(SELECT repo_id,name,owner_name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" + | |||
| " where A.repo_id=B.repo_id" | |||
| if q != "" { | |||
| sql = sql + " and B.name like '%" + q + "%'" | |||
| sql = sql + " and LOWER(B.name) like '%" + strings.ToLower(q) + "%'" | |||
| } | |||
| sql = sql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | |||
| return sql | |||
| @@ -60,11 +60,17 @@ func NewServices() { | |||
| if err := storage.Init(); err != nil { | |||
| log.Fatal("storage init failed: %v", err) | |||
| } | |||
| log.Info("storage init succeed.") | |||
| mailer.NewContext() | |||
| log.Info("mailer.NewContext() succeed.") | |||
| _ = cache.NewContext() | |||
| log.Info("cache.NewContext() succeed.") | |||
| notification.NewContext() | |||
| log.Info("notification.NewContext() succeed.") | |||
| decompression.NewContext() | |||
| log.Info("decompression.NewContext() succeed.") | |||
| labelmsg.Init() | |||
| log.Info("labelmsg.Init() succeed.") | |||
| } | |||
| // In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology | |||
| @@ -181,7 +181,7 @@ func deleteBranch(ctx *context.Context, branchName string) error { | |||
| } | |||
| func loadBranches(ctx *context.Context) []*Branch { | |||
| rawBranches, err := repo_module.GetBranches(ctx.Repo.Repository) | |||
| rawBranches, _, err := repo_module.GetBranches(ctx.Repo.Repository, 0, 0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches", err) | |||
| return nil | |||
| @@ -74,12 +74,13 @@ func CloudBrainIndex(ctx *context.Context) { | |||
| timestamp := time.Now().Unix() | |||
| for i, task := range ciTasks { | |||
| if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | |||
| ciTasks[i].CanDebug = true | |||
| ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| } else { | |||
| ciTasks[i].CanDebug = false | |||
| } | |||
| ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||
| ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| @@ -88,6 +89,7 @@ func CloudBrainIndex(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = ciTasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.HTML(200, tplCloudBrainIndex) | |||
| } | |||
| @@ -216,7 +218,22 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
| return | |||
| } | |||
| _, err := models.GetCloudbrainByName(jobName) | |||
| count, err := models.GetCloudbrainCountByUserID(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("system error", tplCloudBrainNew, &form) | |||
| return | |||
| } else { | |||
| if count >= 1 { | |||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplCloudBrainNew, &form) | |||
| return | |||
| } | |||
| } | |||
| _, err = models.GetCloudbrainByName(jobName) | |||
| if err == nil { | |||
| log.Error("the job name did already exist", ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| @@ -437,14 +454,22 @@ func StopJobs(cloudBrains []*models.Cloudbrain) { | |||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||
| } else { | |||
| param := models.NotebookAction{ | |||
| Action: models.ActionStop, | |||
| if taskInfo.JobType == string(models.JobTypeTrain) { | |||
| err := retry(3, time.Second*30, func() error { | |||
| _, err := modelarts.StopTrainJob(taskInfo.JobID, strconv.FormatInt(taskInfo.VersionID, 10)) | |||
| return err | |||
| }) | |||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||
| } else { | |||
| param := models.NotebookAction{ | |||
| Action: models.ActionStop, | |||
| } | |||
| err := retry(3, time.Second*30, func() error { | |||
| _, err := modelarts.StopJob(taskInfo.JobID, param) | |||
| return err | |||
| }) | |||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||
| } | |||
| err := retry(3, time.Second*30, func() error { | |||
| _, err := modelarts.StopJob(taskInfo.JobID, param) | |||
| return err | |||
| }) | |||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||
| } | |||
| } | |||
| @@ -715,3 +740,78 @@ func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benc | |||
| return nil | |||
| } | |||
| func SyncCloudbrainStatus() { | |||
| cloudBrains, err := models.GetCloudBrainUnStoppedJob() | |||
| if err != nil { | |||
| log.Error("GetCloudBrainUnStoppedJob failed:", err.Error()) | |||
| return | |||
| } | |||
| for _, task := range cloudBrains { | |||
| if task.Type == models.TypeCloudBrainOne { | |||
| result, err := cloudbrain.GetJob(task.JobID) | |||
| if err != nil { | |||
| log.Error("GetJob(%s) failed:%v", task.JobName, err) | |||
| continue | |||
| } | |||
| if result != nil { | |||
| jobRes, _ := models.ConvertToJobResultPayload(result.Payload) | |||
| taskRoles := jobRes.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| task.Status = taskRes.TaskStatuses[0].State | |||
| if task.Status != string(models.JobWaiting) { | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| continue | |||
| } | |||
| } | |||
| } | |||
| } else if task.Type == models.TypeCloudBrainTwo { | |||
| if task.JobType == string(models.JobTypeDebug) { | |||
| result, err := modelarts.GetJob(task.JobID) | |||
| if err != nil { | |||
| log.Error("GetJob(%s) failed:%v", task.JobName, err) | |||
| continue | |||
| } | |||
| if result != nil { | |||
| task.Status = result.Status | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| continue | |||
| } | |||
| } | |||
| } else if task.JobType == string(models.JobTypeTrain) { | |||
| result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10)) | |||
| if err != nil { | |||
| log.Error("GetTrainJob(%s) failed:%v", task.JobName, err) | |||
| continue | |||
| } | |||
| if result != nil { | |||
| task.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| task.Duration = result.Duration | |||
| task.TrainJobDuration = result.TrainJobDuration | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| continue | |||
| } | |||
| } | |||
| } else { | |||
| log.Error("task.JobType(%s) is error:%s", task.JobName, task.JobType) | |||
| } | |||
| } else { | |||
| log.Error("task.Type(%s) is error:%d", task.JobName, task.Type) | |||
| } | |||
| } | |||
| return | |||
| } | |||
| @@ -507,7 +507,7 @@ func getBranchesForRepo(user *models.User, repo *models.Repository) (bool, []str | |||
| } | |||
| defer gitRepo.Close() | |||
| branches, err := gitRepo.GetBranches() | |||
| branches, _, err := gitRepo.GetBranches(0, 0) | |||
| if err != nil { | |||
| return false, nil, err | |||
| } | |||
| @@ -528,7 +528,7 @@ func CompareDiff(ctx *context.Context) { | |||
| } | |||
| if ctx.Data["PageIsComparePull"] == true { | |||
| headBranches, err := headGitRepo.GetBranches() | |||
| headBranches, _, err := headGitRepo.GetBranches(0,0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches", err) | |||
| return | |||
| @@ -424,7 +424,7 @@ func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository, isPull boo | |||
| return nil | |||
| } | |||
| brs, err := ctx.Repo.GitRepo.GetBranches() | |||
| brs, _, err := ctx.Repo.GitRepo.GetBranches(0,0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches", err) | |||
| return nil | |||
| @@ -1390,7 +1390,7 @@ func isLegalReviewRequest(reviewer, doer *models.User, isAdd bool, issue *models | |||
| var pemResult bool | |||
| if isAdd { | |||
| pemResult = permReviewer.CanAccessAny(models.AccessModeRead, models.UnitTypePullRequests) | |||
| pemResult = permReviewer.CanAccessAny(models.AccessModeWrite, models.UnitTypePullRequests) | |||
| if !pemResult { | |||
| return fmt.Errorf("Reviewer can't read [user_id: %d, repo_name: %s]", reviewer.ID, issue.Repo.Name) | |||
| } | |||
| @@ -11,6 +11,8 @@ import ( | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/cloudbrain" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/base" | |||
| @@ -124,10 +126,11 @@ func NotebookIndex(ctx *context.Context) { | |||
| for i, task := range ciTasks { | |||
| if task.Status == string(models.JobRunning) { | |||
| ciTasks[i].CanDebug = true | |||
| ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| } else { | |||
| ciTasks[i].CanDebug = false | |||
| } | |||
| ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| @@ -136,6 +139,7 @@ func NotebookIndex(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = ciTasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.HTML(200, tplModelArtsNotebookIndex) | |||
| } | |||
| @@ -171,7 +175,22 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) | |||
| description := form.Description | |||
| flavor := form.Flavor | |||
| err := modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) | |||
| count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form) | |||
| return | |||
| } else { | |||
| if count >= 1 { | |||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsNotebookNew, &form) | |||
| return | |||
| } | |||
| } | |||
| err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) | |||
| if err != nil { | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) | |||
| return | |||
| @@ -342,12 +361,18 @@ func TrainJobIndex(ctx *context.Context) { | |||
| return | |||
| } | |||
| for i, task := range tasks { | |||
| tasks[i].CanDel = cloudbrain.CanDeleteTrainJob(ctx, &task.Cloudbrain) | |||
| tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| pager.SetDefaultParams(ctx) | |||
| ctx.Data["Page"] = pager | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = tasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.HTML(200, tplModelArtsTrainJobIndex) | |||
| } | |||
| @@ -416,16 +441,8 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
| ctx.Data["train_url"] = outputObsPath | |||
| Branches, err := ctx.Repo.GitRepo.GetBranches() | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches error:", err) | |||
| return err | |||
| } | |||
| ctx.Data["Branches"] = Branches | |||
| ctx.Data["BranchesCount"] = len(Branches) | |||
| ctx.Data["params"] = "" | |||
| ctx.Data["BranchName"] = ctx.Repo.BranchName | |||
| ctx.Data["branchName"] = ctx.Repo.BranchName | |||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | |||
| if err != nil { | |||
| @@ -494,14 +511,6 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts | |||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
| ctx.Data["train_url"] = outputObsPath | |||
| Branches, err := ctx.Repo.GitRepo.GetBranches() | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches error:", err) | |||
| return err | |||
| } | |||
| ctx.Data["Branches"] = Branches | |||
| ctx.Data["BranchesCount"] = len(Branches) | |||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | |||
| if err != nil { | |||
| ctx.ServerError("getConfigList failed:", err) | |||
| @@ -597,13 +606,13 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
| ctx.Data["train_url"] = outputObsPath | |||
| Branches, err := ctx.Repo.GitRepo.GetBranches() | |||
| branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches error:", err) | |||
| return err | |||
| } | |||
| ctx.Data["branches"] = Branches | |||
| ctx.Data["branches"] = branches | |||
| ctx.Data["branch_name"] = task.BranchName | |||
| ctx.Data["description"] = task.Description | |||
| ctx.Data["boot_file"] = task.BootFile | |||
| @@ -686,12 +695,12 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai | |||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
| ctx.Data["train_url"] = outputObsPath | |||
| Branches, err := ctx.Repo.GitRepo.GetBranches() | |||
| branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||
| if err != nil { | |||
| ctx.ServerError("GetBranches error:", err) | |||
| return err | |||
| } | |||
| ctx.Data["branches"] = Branches | |||
| ctx.Data["branches"] = branches | |||
| ctx.Data["description"] = form.Description | |||
| ctx.Data["dataset_name"] = task.DatasetName | |||
| ctx.Data["work_server_number"] = form.WorkServerNumber | |||
| @@ -739,6 +748,21 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| VersionCount := modelarts.VersionCount | |||
| EngineName := form.EngineName | |||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||
| trainJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | |||
| return | |||
| } else { | |||
| if count >= 1 { | |||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||
| trainJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobNew, &form) | |||
| return | |||
| } | |||
| } | |||
| if err := paramCheckCreateTrainJob(form); err != nil { | |||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | |||
| trainJobErrorNewDataPrepare(ctx, form) | |||
| @@ -891,7 +915,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| return | |||
| } | |||
| err := modelarts.GenerateTrainJob(ctx, req) | |||
| err = modelarts.GenerateTrainJob(ctx, req) | |||
| if err != nil { | |||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | |||
| trainJobErrorNewDataPrepare(ctx, form) | |||
| @@ -905,6 +929,21 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
| ctx.Data["PageIsTrainJob"] = true | |||
| var jobID = ctx.Params(":jobid") | |||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||
| versionErrorDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobVersionNew, &form) | |||
| return | |||
| } else { | |||
| if count >= 1 { | |||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||
| versionErrorDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobVersionNew, &form) | |||
| return | |||
| } | |||
| } | |||
| latestTask, err := models.GetCloudbrainByJobIDAndIsLatestVersion(jobID, modelarts.IsLatestVersion) | |||
| if err != nil { | |||
| ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | |||
| @@ -208,7 +208,7 @@ func RepoStatisticDaily(date string) { | |||
| maxRepoRadar.Completeness = tempRepoStat.Completeness | |||
| } | |||
| if tempRepoStat.Liveness < minRepoRadar.Completeness { | |||
| if tempRepoStat.Liveness < minRepoRadar.Liveness { | |||
| minRepoRadar.Liveness = tempRepoStat.Liveness | |||
| } | |||
| @@ -12,6 +12,8 @@ import ( | |||
| "text/template" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/cloudbrain" | |||
| "code.gitea.io/gitea/routers/operation" | |||
| "code.gitea.io/gitea/routers/private" | |||
| @@ -792,7 +794,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) | |||
| m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) | |||
| m.Get("/tool/query_user_static_page", adminReq, repo.QueryUserStaticDataPage) | |||
| // Grouping for those endpoints not requiring authentication | |||
| m.Group("/:username/:reponame", func() { | |||
| m.Get("/contributors", repo.Contributors) | |||
| @@ -957,15 +959,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("", reqRepoCloudBrainReader, repo.CloudBrainIndex) | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow) | |||
| m.Get("/debug", reqRepoCloudBrainReader, repo.CloudBrainDebug) | |||
| m.Post("/commit_image", reqRepoCloudBrainWriter, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage) | |||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.CloudBrainStop) | |||
| m.Post("/del", reqRepoCloudBrainWriter, repo.CloudBrainDel) | |||
| m.Get("/debug", reqRepoCloudBrainWriter, repo.CloudBrainDebug) | |||
| m.Post("/commit_image", cloudbrain.AdminOrOwnerOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage) | |||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop) | |||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel) | |||
| m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate) | |||
| m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels) | |||
| m.Get("/download_model", reqRepoCloudBrainReader, repo.CloudBrainDownloadModel) | |||
| m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDownloadModel) | |||
| }) | |||
| m.Get("/create", reqRepoCloudBrainReader, repo.CloudBrainNew) | |||
| m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew) | |||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | |||
| }, context.RepoRef()) | |||
| @@ -978,9 +980,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("", reqRepoCloudBrainReader, repo.NotebookIndex) | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.NotebookShow) | |||
| m.Get("/debug", reqRepoCloudBrainReader, repo.NotebookDebug) | |||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.NotebookStop) | |||
| m.Post("/del", reqRepoCloudBrainWriter, repo.NotebookDel) | |||
| m.Get("/debug", reqRepoCloudBrainWriter, repo.NotebookDebug) | |||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookStop) | |||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel) | |||
| }) | |||
| m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew) | |||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsNotebookForm{}), repo.NotebookCreate) | |||
| @@ -990,13 +992,13 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("", reqRepoCloudBrainReader, repo.TrainJobIndex) | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) | |||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.TrainJobStop) | |||
| m.Post("/del", reqRepoCloudBrainWriter, repo.TrainJobDel) | |||
| m.Get("/model_download", reqRepoCloudBrainReader, repo.ModelDownload) | |||
| m.Get("/create_version", reqRepoCloudBrainReader, repo.TrainJobNewVersion) | |||
| m.Post("/create_version", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobStop) | |||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobDel) | |||
| m.Get("/model_download", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.ModelDownload) | |||
| m.Get("/create_version", cloudbrain.AdminOrJobCreaterRight, repo.TrainJobNewVersion) | |||
| m.Post("/create_version", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||
| }) | |||
| m.Get("/create", reqRepoCloudBrainReader, repo.TrainJobNew) | |||
| m.Get("/create", reqRepoCloudBrainWriter, repo.TrainJobNew) | |||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | |||
| m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | |||
| @@ -252,7 +252,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
| } | |||
| } | |||
| branches, err := repo_module.GetBranches(m.Repo) | |||
| branches, _, err := repo_module.GetBranches(m.Repo,0,0) | |||
| if err != nil { | |||
| log.Error("GetBranches: %v", err) | |||
| return nil, false | |||
| @@ -452,7 +452,7 @@ func CloseBranchPulls(doer *models.User, repoID int64, branch string) error { | |||
| // CloseRepoBranchesPulls close all pull requests which head branches are in the given repository | |||
| func CloseRepoBranchesPulls(doer *models.User, repo *models.Repository) error { | |||
| branches, err := git.GetBranchesByPath(repo.RepoPath()) | |||
| branches, _, err := git.GetBranchesByPath(repo.RepoPath(), 0, 0) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| @@ -17,47 +17,57 @@ | |||
| {{if .IsSigned}} | |||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| {{if not .UnitIssuesGlobalDisabled}} | |||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| {{end}} | |||
| {{if not .UnitPullsGlobalDisabled}} | |||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| {{end}} | |||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||
| {{end}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "index"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "home"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <!-- 未登录跳转登录界面 --> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageExplore}} | |||
| @@ -78,7 +88,18 @@ | |||
| */}} | |||
| {{if .IsSigned}} | |||
| <div class="right stackable menu"> | |||
| <div class="right stackable menu"> | |||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
| </button> | |||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
| </div> | |||
| </form> | |||
| <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | |||
| <span class="text"> | |||
| <span class="fitted">{{svg "octicon-bell" 16}}</span> | |||
| @@ -163,6 +184,17 @@ | |||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
| <div class="right stackable menu"> | |||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
| </button> | |||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
| </div> | |||
| </form> | |||
| {{if .ShowRegistrationButton}} | |||
| <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | |||
| {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||
| @@ -17,47 +17,54 @@ | |||
| {{if .IsSigned}} | |||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| {{if not .UnitIssuesGlobalDisabled}} | |||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| {{end}} | |||
| {{if not .UnitPullsGlobalDisabled}} | |||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| {{end}} | |||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||
| {{end}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "index"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "home"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <!-- 未登录跳转登录界面 --> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageExplore}} | |||
| @@ -79,6 +86,17 @@ | |||
| {{if .IsSigned}} | |||
| <div class="right stackable menu"> | |||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
| </button> | |||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
| </div> | |||
| </form> | |||
| <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | |||
| <span class="text"> | |||
| <span class="fitted">{{svg "octicon-bell" 16}}</span> | |||
| @@ -163,6 +181,17 @@ | |||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
| <div class="right stackable menu"> | |||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
| </button> | |||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
| </div> | |||
| </form> | |||
| {{if .ShowRegistrationButton}} | |||
| <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | |||
| {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||
| @@ -9,47 +9,56 @@ | |||
| </div> | |||
| {{if .IsSigned}} | |||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| {{if not .UnitIssuesGlobalDisabled}} | |||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| {{end}} | |||
| {{if not .UnitPullsGlobalDisabled}} | |||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| {{end}} | |||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||
| {{end}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "index"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "home"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <!-- 未登录跳转登录界面 --> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageExplore}} | |||
| @@ -183,9 +183,9 @@ | |||
| {{end}} | |||
| {{end}} | |||
| {{else}} | |||
| <option name="branch_name" value="{{.BranchName}}">{{.BranchName}}</option> | |||
| <option name="branch_name" value="{{.branchName}}">{{.branchName}}</option> | |||
| {{range $k, $v :=.Branches}} | |||
| {{ if ne $v $.BranchName }} | |||
| {{ if ne $v $.branchName }} | |||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||
| {{end}} | |||
| {{end}} | |||
| @@ -474,6 +474,7 @@ td, th { | |||
| <script> | |||
| console.log({{.version_list_task}}) | |||
| console.log({{.}}) | |||
| $('.menu .item').tab() | |||
| // $('.ui.style.accordion').accordion(); | |||
| @@ -708,11 +709,13 @@ td, th { | |||
| } | |||
| function logScroll(version_name) { | |||
| let container = document.querySelector(`#log${version_name}`) | |||
| let scrollTop = container.scrollTop | |||
| let scrollHeight = container.scrollHeight | |||
| let clientHeight = container.clientHeight | |||
| if(parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight){ | |||
| let scrollLeft = container.scrollLeft | |||
| if((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight) && (scrollLeft===0)){ | |||
| let end_line = $(`#log${version_name} input[name=end_line]`).val() | |||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { | |||
| if (data.Lines == 0){ | |||
| @@ -735,7 +738,7 @@ td, th { | |||
| console.log(err); | |||
| }); | |||
| } | |||
| if(scrollTop == 0){ | |||
| if(scrollTop == 0 && scrollLeft==0){ | |||
| let start_line = $(`#log${version_name} input[name=start_line]`).val() | |||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => { | |||
| if (data.Lines == 0){ | |||
| @@ -346,7 +346,7 @@ | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| let url_href = location.pathname.split('create_version')[0] | |||
| let url_href = location.pathname.split('/create_version')[0] | |||
| let url_post = location.pathname | |||
| let version_name = location.search.split('?version_name=')[1] | |||
| $("#parents_version").val(version_name) | |||
| @@ -3,7 +3,7 @@ | |||
| <el-tabs tab-position="left" v-model="activeName" style="height:100%" @tab-click="handleClick" > | |||
| <el-tab-pane label="概览" name="first" > | |||
| <span slot="label"> | |||
| <el-image style="width: 13px; height: 13px" src="/img/overview.png"> | |||
| <el-image style="width: 13px; height: 13px" src="/img/overview_rgb.svg"> | |||
| </el-image> | |||
| 概览 | |||
| </span> | |||
| @@ -13,14 +13,14 @@ | |||
| <el-tab-pane label="项目分析" name="second" id="second" > | |||
| <ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis> | |||
| <span slot="label"> | |||
| <el-image style="width: 13px; height: 13px" src="/img/pro_new.svg"> | |||
| <el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg"> | |||
| </el-image> | |||
| 项目分析 | |||
| </span> | |||
| </el-tab-pane> | |||
| <el-tab-pane name="third" id='third' > | |||
| <span slot='label'> | |||
| <el-image style="width: 13px; height: 13px" src="/img/name.png"> | |||
| <el-image style="width: 13px; height: 13px" src="/img/user_rgb.svg"> | |||
| </el-image> | |||
| 用户分析 | |||
| </span> | |||
| @@ -121,6 +121,14 @@ | |||
| /deep/ .el-tabs__item { | |||
| padding: 0px 20px 0px 20px; | |||
| } | |||
| /deep/ .el-tabs__item.is-active .el-image{ | |||
| filter:none | |||
| } | |||
| /deep/ .el-tabs__item:hover .el-image{ | |||
| filter:none | |||
| } | |||
| /deep/ .el-image{ | |||
| filter:grayscale(100%) | |||
| } | |||
| </style> | |||
| @@ -1085,6 +1085,12 @@ | |||
| return data[0]+''+data[1]+''+data[2] | |||
| } | |||
| }, | |||
| goBack(){ | |||
| if( $("#pro_detail").is(':visible') ){ | |||
| document.getElementById("pro_main").style.display = "block"; | |||
| document.getElementById("pro_detail").style.display = "none"; | |||
| } | |||
| }, | |||
| }, | |||
| filters:{ | |||
| @@ -1125,7 +1131,7 @@ | |||
| return " <a href=\" mailto:" + value.email + "class=\"circular ui button\">" +value.user+ "</a>" | |||
| } | |||
| }, | |||
| }, | |||
| }, | |||
| @@ -1140,6 +1146,10 @@ | |||
| this.radarOpenI = this.$echarts.init(document.getElementById('radar_openi')) | |||
| this.echartsOITd = this.$echarts.init(document.getElementById('line_openi')) | |||
| this.echartsSelectData = this.$echarts.init(document.getElementById('selectData')) | |||
| if (window.history && window.history.pushState) { | |||
| history.pushState(null, null, document.URL); | |||
| window.addEventListener('popstate', this.goBack, false); | |||
| } | |||
| // window.onresize=function(){ | |||
| // this.radarOpenI.resize(); | |||
| // this.echartsOITd.resize(); | |||
| @@ -27,10 +27,10 @@ | |||
| </span> | |||
| <span style="float:right; margin-right: 20px;" > | |||
| <a style="display:inline-block;margin-left: 20px; " id = 'download'> | |||
| <a class="el-icon-download" v-if="tableData!=''" :href= "'../tool/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" ></a> | |||
| <a class="el-icon-download" v-if="tableData!=''" :href= "'../api/v1/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" ></a> | |||
| <i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | |||
| <span > | |||
| <a v-if="tableData!=''" :href= "'../tool/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" >下载报告</a> | |||
| <a v-if="tableData!=''" :href= "'../api/v1/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" >下载报告</a> | |||
| <a v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | |||
| </span> | |||
| </a> | |||
| @@ -335,7 +335,7 @@ | |||
| } | |||
| }; | |||
| this.$axios.get('../tool/query_user_static_page',{ | |||
| this.$axios.get('../api/v1/query_user_static_page',{ | |||
| params:this.params | |||
| }).then((res)=>{ | |||
| this.tableData = res.data.data | |||