diff --git a/models/cloudbrain.go b/models/cloudbrain.go index af5e9f169..a106d7433 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -353,6 +353,7 @@ type FlavorInfos struct { type FlavorInfo struct { Id int `json:"id"` Value string `json:"value"` + Desc string `json:"desc"` } type PoolInfos struct { diff --git a/models/issue.go b/models/issue.go index e1b871b0b..7457fcd45 100755 --- a/models/issue.go +++ b/models/issue.go @@ -1356,6 +1356,15 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { return accum, nil } +func GetPullCountByUserAndRepoId(repoId int64, userId int64) int64 { + issue := new(Issue) + total, err := x.Where("is_pull=true and repo_id=? and poster_id=?", repoId, userId).Count(issue) + if err != nil { + return 0 + } + return total +} + func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, error) { stats := &IssueStats{} diff --git a/models/org.go b/models/org.go old mode 100644 new mode 100755 index 58afc5cb5..e8006d55f --- a/models/org.go +++ b/models/org.go @@ -182,6 +182,7 @@ func CreateOrganization(org, owner *User) (err error) { if _, err = sess.Insert(&OrgUser{ UID: owner.ID, OrgID: org.ID, + IsPublic: setting.Service.DefaultOrgMemberVisible, }); err != nil { return fmt.Errorf("insert org-user relation: %v", err) } diff --git a/models/repo.go b/models/repo.go index c8629875e..1a5cf122c 100755 --- a/models/repo.go +++ b/models/repo.go @@ -210,9 +210,12 @@ type Repository struct { Balance string `xorm:"NOT NULL DEFAULT '0'"` BlockChainStatus RepoBlockChainStatus `xorm:"NOT NULL DEFAULT 0"` - // git clone total count + // git clone and git pull total count CloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` + // only git clone total count + GitCloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` @@ -2473,6 +2476,24 @@ func (repo *Repository) IncreaseCloneCnt() { return } +func (repo *Repository) IncreaseGitCloneCnt() { + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return + } + if _, err := sess.Exec("UPDATE `repository` SET git_clone_cnt = git_clone_cnt + 1 WHERE id = ?", repo.ID); err != nil { + return + } + + if err := sess.Commit(); err != nil { + return + } + + return +} + func UpdateRepositoryCommitNum(repo *Repository) error { if _, err := x.Exec("UPDATE `repository` SET num_commit = ? where id = ?", repo.NumCommit, repo.ID); err != nil { return err diff --git a/models/repo_activity_custom.go b/models/repo_activity_custom.go index 9cb7e4a09..7cfed2359 100644 --- a/models/repo_activity_custom.go +++ b/models/repo_activity_custom.go @@ -2,12 +2,19 @@ package models import ( "fmt" + "sort" "strings" "time" "code.gitea.io/gitea/modules/git" ) +type ContributorWithUserId struct { + git.Contributor + UserId int64 + IsAdmin bool +} + func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) { wikiPath := "" if repo.HasWiki() { @@ -63,22 +70,39 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error } if recentlyContributors != nil { + resentlyContributorDistinctDict := make(map[string]int, 0) for _, recentlyContributor := range recentlyContributors { user, err := GetUserByActivateEmail(recentlyContributor.Email) - var ok bool + if err == nil { - _, ok = contributorDistinctDict[user.Email] + value, ok := resentlyContributorDistinctDict[user.Email] + if !ok { + resentlyContributorDistinctDict[user.Email] = recentlyContributor.CommitCnt + } else { + resentlyContributorDistinctDict[user.Email] = value + recentlyContributor.CommitCnt + } + } else { - _, ok = contributorDistinctDict[recentlyContributor.Email] + value, ok := resentlyContributorDistinctDict[recentlyContributor.Email] + if !ok { + resentlyContributorDistinctDict[recentlyContributor.Email] = recentlyContributor.CommitCnt + } else { + resentlyContributorDistinctDict[recentlyContributor.Email] = value + recentlyContributor.CommitCnt + } + } - if !ok { + } + + for k, v := range resentlyContributorDistinctDict { + count, ok := contributorDistinctDict[k] + if ok && count == v { stats.ContributorsAdded++ - newContributersDict[recentlyContributor.Email] = struct{}{} } } + } stats.Contributors = int64(len(contributorDistinctDict)) @@ -101,6 +125,66 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error } +func GetTop10Contributor(repoPath string) ([]ContributorWithUserId, error) { + contributors, err := git.GetContributors(repoPath) + if err != nil { + return make([]ContributorWithUserId, 0), err + } + contributorDistinctDict := make(map[string]ContributorWithUserId, 0) + if contributors != nil { + for _, contributor := range contributors { + if strings.Compare(contributor.Email, "") == 0 { + continue + } + + user, err := GetUserByActivateEmail(contributor.Email) + if err == nil { + + value, ok := contributorDistinctDict[user.Email] + if !ok { + contributorDistinctDict[user.Email] = ContributorWithUserId{ + contributor, + user.ID, + user.IsAdmin, + } + } else { + + value.CommitCnt += contributor.CommitCnt + } + + } else { + value, ok := contributorDistinctDict[contributor.Email] + if !ok { + contributorDistinctDict[contributor.Email] = ContributorWithUserId{ + contributor, + -1, + false, + } + } else { + value.CommitCnt += contributor.CommitCnt + } + + } + + } + v := make([]ContributorWithUserId, 0, len(contributorDistinctDict)) + for _, value := range contributorDistinctDict { + v = append(v, value) + } + + sort.Slice(v, func(i, j int) bool { + return v[i].CommitCnt > v[j].CommitCnt + }) + + if len(v) <= 10 { + return v, nil + } else { + return v[0:10], nil + } + } + return make([]ContributorWithUserId, 0), nil +} + func setKeyContributerDict(contributorDistinctDict map[string]int, email string, keyContributorsDict map[string]struct{}) { if contributorDistinctDict[email] >= 3 { _, ok := keyContributorsDict[email] diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 4bb95cd05..bc71ad379 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -114,6 +114,17 @@ func (repo *Repository) isCollaborator(e Engine, userID int64) (bool, error) { return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID}) } +func (repo *Repository) GetCollaboratorMode(userID int64) int { + collaboration := &Collaboration{RepoID: repo.ID, UserID: userID} + has, err := x.Get(&collaboration) + if err != nil || !has { + return -1 + } else { + return int(collaboration.Mode) + } + +} + // IsCollaborator check if a user is a collaborator of a repository func (repo *Repository) IsCollaborator(userID int64) (bool, error) { return repo.isCollaborator(x, userID) diff --git a/models/repo_statistic.go b/models/repo_statistic.go index adef672e0..df065bb79 100755 --- a/models/repo_statistic.go +++ b/models/repo_statistic.go @@ -9,56 +9,56 @@ import ( // RepoStatistic statistic info of all repository type RepoStatistic struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"unique(s) NOT NULL"` - Name string `xorm:"INDEX"` - IsPrivate bool - Date string `xorm:"unique(s) NOT NULL"` - NumWatches int64 `xorm:"NOT NULL DEFAULT 0"` - NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumStars int64 `xorm:"NOT NULL DEFAULT 0"` - NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumForks int64 `xorm:"NOT NULL DEFAULT 0"` - NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumDownloads int64 `xorm:"NOT NULL DEFAULT 0"` - NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumComments int64 `xorm:"NOT NULL DEFAULT 0"` - NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumVisits int64 `xorm:"NOT NULL DEFAULT 0"` - NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0"` - NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumVersions int64 `xorm:"NOT NULL DEFAULT 0"` - NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0"` - RepoSize int64 `xorm:"NOT NULL DEFAULT 0"` - DatasetSize int64 `xorm:"NOT NULL DEFAULT 0"` - NumModels int64 `xorm:"NOT NULL DEFAULT 0"` - NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0"` - NumCommits int64 `xorm:"NOT NULL DEFAULT 0"` - NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumIssues int64 `xorm:"NOT NULL DEFAULT 0"` - NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumPulls int64 `xorm:"NOT NULL DEFAULT 0"` - NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0"` - IssueFixedRate float32 `xorm:"NOT NULL"` - NumContributor int64 `xorm:"NOT NULL DEFAULT 0"` - NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0"` - NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0"` - - NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` - NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` - NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0"` - NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0"` - NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` - - Impact float64 `xorm:"NOT NULL DEFAULT 0"` - Completeness float64 `xorm:"NOT NULL DEFAULT 0"` - Liveness float64 `xorm:"NOT NULL DEFAULT 0"` - ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0"` - TeamHealth float64 `xorm:"NOT NULL DEFAULT 0"` - Growth float64 `xorm:"NOT NULL DEFAULT 0"` - RadarTotal float64 `xorm:"NOT NULL DEFAULT 0"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + ID int64 `xorm:"pk autoincr" json:"-"` + RepoID int64 `xorm:"unique(s) NOT NULL" json:"repo_id"` + Name string `xorm:"INDEX" json:"name"` + IsPrivate bool `json:"isPrivate"` + Date string `xorm:"unique(s) NOT NULL" json:"date"` + NumWatches int64 `xorm:"NOT NULL DEFAULT 0" json:"watch"` + NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumStars int64 `xorm:"NOT NULL DEFAULT 0" json:"star"` + NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumForks int64 `xorm:"NOT NULL DEFAULT 0" json:"fork"` + NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumDownloads int64 `xorm:"NOT NULL DEFAULT 0" json:"download"` + NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumComments int64 `xorm:"NOT NULL DEFAULT 0" json:"comment"` + NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumVisits int64 `xorm:"NOT NULL DEFAULT 0" json:"view"` + NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issueClosed"` + NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumVersions int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + RepoSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + DatasetSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumModels int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumCommits int64 `xorm:"NOT NULL DEFAULT 0" json:"commit"` + NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issue"` + NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumPulls int64 `xorm:"NOT NULL DEFAULT 0" json:"pr"` + NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + IssueFixedRate float32 `xorm:"NOT NULL" json:"issueClosedRatio"` + NumContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"contributor"` + NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + + NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` + + Impact float64 `xorm:"NOT NULL DEFAULT 0" json:"impact"` + Completeness float64 `xorm:"NOT NULL DEFAULT 0" json:"completeness"` + Liveness float64 `xorm:"NOT NULL DEFAULT 0" json:"liveness"` + ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"projectHealth"` + TeamHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"teamHealth"` + Growth float64 `xorm:"NOT NULL DEFAULT 0" json:"growth"` + RadarTotal float64 `xorm:"NOT NULL DEFAULT 0" json:"openi"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"-"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"-"` } func DeleteRepoStatDaily(date string) error { @@ -81,9 +81,60 @@ func DeleteRepoStatDaily(date string) error { return nil } -func GetRepoStatisticByDate(date string) ([]*RepoStatistic, error) { +func CountRepoStatByRawSql(sql string) (int64, error) { + + return xStatistic.SQL(sql).Count() + +} + +func GetRepoStatisticByRawSql(sql string) []*RepoStatistic { repoStatistics := make([]*RepoStatistic, 0) - err := xStatistic.Where("date = ?", date).Find(&repoStatistics) + xStatistic.SQL(sql).Find(&repoStatistics) + return repoStatistics +} + +func GetRepoStatLastUpdatedTime(repoId ...string) (string, string, error) { + + repoStatistic := new(RepoStatistic) + var has bool + var err error + if len(repoId) == 0 { + has, err = xStatistic.Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic) + + } else { + has, err = xStatistic.Where("repo_id=?", repoId[0]).Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic) + } + + if err != nil { + return "", "", err + } else { + if has { + return repoStatistic.CreatedUnix.Format("2006-01-02 15:04:05"), repoStatistic.Date, nil + } else { + return "", "", fmt.Errorf("Can not get the latest record.") + } + } + +} + +func GetRepoStatisticByDateAndRepoId(date string, repoId int64) (*RepoStatistic, error) { + repoStatistic := new(RepoStatistic) + has, err := xStatistic.Where("date=? and repo_id=?", date, repoId).Get(repoStatistic) + if err != nil { + return nil, err + } else { + if has { + return repoStatistic, nil + } else { + return nil, fmt.Errorf("The num of return records is 0.") + } + } + +} + +func GetRepoStatisticByDate(date string, repoId int64) ([]*RepoStatistic, error) { + repoStatistics := make([]*RepoStatistic, 0) + err := xStatistic.Where("date = ? and repo_id=?", date, repoId).Find(&repoStatistics) return repoStatistics, err } @@ -107,6 +158,13 @@ func InsertRepoStat(repoStat *RepoStatistic) (int64, error) { return xStatistic.Insert(repoStat) } +func RestoreRepoStatFork(numForks int64, repoId int64) error { + sql := "update repo_statistic set num_forks=? where repo_id=?" + + _, err := xStatistic.Exec(sql, numForks, repoId) + return err +} + func UpdateRepoStat(repoStat *RepoStatistic) error { sql := "update repo_statistic set impact=?,completeness=?,liveness=?,project_health=?,team_health=?,growth=?,radar_total=? where repo_id=? and date=?" diff --git a/modules/auth/modelarts.go b/modules/auth/modelarts.go index f2e5aeed5..e9e101523 100755 --- a/modules/auth/modelarts.go +++ b/modules/auth/modelarts.go @@ -19,6 +19,7 @@ type CreateModelArtsNotebookForm struct { JobName string `form:"job_name" binding:"Required"` Attachment string `form:"attachment"` Description string `form:"description"` + Flavor string `form:"flavor"` } func (f *CreateModelArtsNotebookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { diff --git a/modules/cron/tasks_basic.go b/modules/cron/tasks_basic.go index ed9829cef..eac081a8f 100755 --- a/modules/cron/tasks_basic.go +++ b/modules/cron/tasks_basic.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/migrations" repository_service "code.gitea.io/gitea/modules/repository" + api_repo "code.gitea.io/gitea/routers/api/v1/repo" "code.gitea.io/gitea/routers/repo" mirror_service "code.gitea.io/gitea/services/mirror" ) @@ -195,6 +196,17 @@ func registerHandleUserStatistic() { }) } +func registerHandleClearRepoStatisticFile() { + RegisterTaskFatal("handle_repo_clear_statistic_file", &BaseConfig{ + Enabled: true, + RunAtStart: false, + Schedule: "@daily", + }, func(ctx context.Context, _ *models.User, _ Config) error { + api_repo.ClearUnusedStatisticsFile() + return nil + }) +} + func initBasicTasks() { registerUpdateMirrorTask() registerRepoHealthCheck() diff --git a/modules/modelarts/modelarts.go b/modules/modelarts/modelarts.go index e1dbe9f5a..3153fbc52 100755 --- a/modules/modelarts/modelarts.go +++ b/modules/modelarts/modelarts.go @@ -99,7 +99,7 @@ type ResourcePool struct { } `json:"resource_pool"` } -func GenerateTask(ctx *context.Context, jobName, uuid, description string) error { +func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor string) error { var dataActualPath string if uuid != "" { dataActualPath = setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" @@ -128,7 +128,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description string) error JobName: jobName, Description: description, ProfileID: setting.ProfileID, - Flavor: setting.Flavor, + Flavor: flavor, Pool: models.Pool{ ID: poolInfos.PoolInfo[0].PoolId, Name: poolInfos.PoolInfo[0].PoolName, diff --git a/modules/setting/setting.go b/modules/setting/setting.go index eb0e41c90..9f31612b6 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -163,6 +163,7 @@ var ( // UI settings UI = struct { ExplorePagingNum int + ContributorPagingNum int IssuePagingNum int RepoSearchPagingNum int MembersPagingNum int @@ -203,19 +204,20 @@ var ( Keywords string } `ini:"ui.meta"` }{ - ExplorePagingNum: 20, - IssuePagingNum: 10, - RepoSearchPagingNum: 10, - MembersPagingNum: 20, - FeedMaxCommitNum: 5, - GraphMaxCommitNum: 100, - CodeCommentLines: 4, - ReactionMaxUserNum: 10, - ThemeColorMetaTag: `#6cc644`, - MaxDisplayFileSize: 8388608, - DefaultTheme: `gitea`, - Themes: []string{`gitea`, `arc-green`}, - Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, + ExplorePagingNum: 20, + ContributorPagingNum: 50, + IssuePagingNum: 10, + RepoSearchPagingNum: 10, + MembersPagingNum: 20, + FeedMaxCommitNum: 5, + GraphMaxCommitNum: 100, + CodeCommentLines: 4, + ReactionMaxUserNum: 10, + ThemeColorMetaTag: `#6cc644`, + MaxDisplayFileSize: 8388608, + DefaultTheme: `gitea`, + Themes: []string{`gitea`, `arc-green`}, + Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, Notification: struct { MinTimeout time.Duration TimeoutStep time.Duration @@ -544,6 +546,8 @@ var ( GrowthContributors float64 GrowthCommit float64 GrowthComments float64 + RecordBeginTime string + Path string }{} ) @@ -1324,6 +1328,8 @@ func SetRadarMapConfig() { RadarMap.GrowthContributors = sec.Key("growth_contributors").MustFloat64(0.2) RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2) RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2) + RadarMap.RecordBeginTime = sec.Key("record_beigin_time").MustString("2021-11-05") + RadarMap.Path = sec.Key("PATH").MustString("data/projectborad") } diff --git a/modules/storage/obs.go b/modules/storage/obs.go index bd73281d0..239580adb 100755 --- a/modules/storage/obs.go +++ b/modules/storage/obs.go @@ -10,11 +10,11 @@ import ( "strconv" "strings" - "github.com/unknwon/com" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/obs" "code.gitea.io/gitea/modules/setting" + + "github.com/unknwon/com" ) type FileInfo struct { @@ -178,30 +178,45 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) { input := &obs.ListObjectsInput{} input.Bucket = setting.Bucket input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") + strPrefix := strings.Split(input.Prefix, "/") output, err := ObsCli.ListObjects(input) fileInfos := make([]FileInfo, 0) if err == nil { for _, val := range output.Contents { str1 := strings.Split(val.Key, "/") var isDir bool - var fileName,nextParentDir string + var fileName, nextParentDir string if strings.HasSuffix(val.Key, "/") { + //dirs in next level dir + if len(str1)-len(strPrefix) > 2 { + continue + } fileName = str1[len(str1)-2] isDir = true - nextParentDir = fileName - if fileName == parentDir || (fileName + "/") == setting.OutPutPath { + if parentDir == "" { + nextParentDir = fileName + } else { + nextParentDir = parentDir + "/" + fileName + } + + if fileName == strPrefix[len(strPrefix)-1] || (fileName+"/") == setting.OutPutPath { continue } } else { + //files in next level dir + if len(str1)-len(strPrefix) > 1 { + continue + } fileName = str1[len(str1)-1] isDir = false + nextParentDir = parentDir } fileInfo := FileInfo{ - ModTime: val.LastModified.Format("2006-01-02 15:04:05"), + ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), FileName: fileName, - Size: val.Size, - IsDir:isDir, + Size: val.Size, + IsDir: isDir, ParenDir: nextParentDir, } fileInfos = append(fileInfos, fileInfo) @@ -242,7 +257,7 @@ func GetObsCreateSignedUrl(jobName, parentDir, fileName string) (string, error) input := &obs.CreateSignedUrlInput{} input.Bucket = setting.Bucket input.Key = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir, fileName), "/") - + input.Expires = 60 * 60 input.Method = obs.HttpMethodGet diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 7fa8c7a4f..bc71693b8 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -218,6 +218,7 @@ show_only_private = Showing only private show_only_public = Showing only public issues.in_your_repos = In your repositories +contributors = Contributors [explore] repos = Repositories @@ -755,6 +756,7 @@ unit_disabled = The site administrator has disabled this repository section. language_other = Other datasets = Datasets datasets.desc = Enable Dataset +cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc. debug=Debug stop=Stop @@ -785,7 +787,12 @@ cloudbrain_operate = Operate cloudbrain_status_createtime = Status/Createtime cloudbrain_status_runtime = Running Time - +record_begintime_get_err=Can not get the record begin time. +parameter_is_wrong=The input parameter is wrong. +total_count_get_error=Can not get the total page. +last_update_time_error=Can not get the last updated time. +get_repo_stat_error=Can not get the statistics of the repository. +get_repo_info_error=Can not get the information of the repository. modelarts.notebook=Debug Task modelarts.train_job=Train Task modelarts.train_job.new_debug= New Debug Task @@ -2152,6 +2159,19 @@ repos.stars = Stars repos.forks = Forks repos.issues = Issues repos.size = Size +repos.id=ID +repos.projectName=Project Name +repos.isPrivate=Private +repos.openi=OpenI +repos.visit=Visit +repos.download=Code Download +repos.pr=PR +repos.commit=Commit +repos.closedIssues=Closed Issue +repos.contributor=Contributor +repos.yes=Yes +repos.no=No + datasets.dataset_manage_panel= Dataset Manage datasets.owner=Owner diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index d78d3beec..6702a0434 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -220,6 +220,8 @@ show_only_public=只显示公开的 issues.in_your_repos=属于该用户项目的 +contributors=贡献者 + [explore] repos=项目 users=用户 @@ -227,6 +229,7 @@ organizations=组织 images = 云脑镜像 search=搜索 code=代码 +data_analysis=数字看板 repo_no_results=未找到匹配的项目。 dataset_no_results = 未找到匹配的数据集。 user_no_results=未找到匹配的用户。 @@ -757,6 +760,7 @@ unit_disabled=站点管理员已禁用此项目单元。 language_other=其它 datasets=数据集 datasets.desc=数据集功能 +cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 debug=调试 stop=停止 @@ -787,6 +791,12 @@ cloudbrain_status_createtime=状态/创建时间 cloudbrain_status_runtime = 运行时长 cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 +record_begintime_get_err=无法获取统计开始时间。 +parameter_is_wrong=输入参数错误,请检查输入参数。 +total_count_get_error=查询总页数失败。 +last_update_time_error=查询最新更新时间失败。 +get_repo_stat_error=查询当前仓库的统计信息失败。 +get_repo_info_error=查询当前仓库信息失败。 modelarts.notebook=调试任务 modelarts.train_job=训练任务 modelarts.train_job.new_debug=新建调试任务 diff --git a/public/img/git-logo.svg b/public/img/git-logo.svg new file mode 100644 index 000000000..70e6ab484 --- /dev/null +++ b/public/img/git-logo.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/public/img/name.png b/public/img/name.png new file mode 100755 index 000000000..11a5c8751 Binary files /dev/null and b/public/img/name.png differ diff --git a/public/img/overview.png b/public/img/overview.png new file mode 100755 index 000000000..b704ead84 Binary files /dev/null and b/public/img/overview.png differ diff --git a/public/img/pro.png b/public/img/pro.png new file mode 100755 index 000000000..7d44e180e Binary files /dev/null and b/public/img/pro.png differ diff --git a/public/img/pro.svg b/public/img/pro.svg new file mode 100755 index 000000000..c7bcfff8b --- /dev/null +++ b/public/img/pro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 9dd773c4d..b2e701998 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -523,6 +523,22 @@ func RegisterRoutes(m *macaron.Macaron) { Get(notify.GetThread). Patch(notify.ReadThread) }, reqToken()) + adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) + //Project board + m.Group("/projectboard", func() { + + m.Get("/restoreFork", adminReq, repo.RestoreForkNumber) + + m.Group("/project", func() { + m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics) + m.Get("/download", adminReq, repo.ServeAllProjectsPeriodStatisticsFile) + m.Group("/:id", func() { + m.Get("", adminReq, repo.GetProjectLatestStatistics) + m.Get("/period", adminReq, repo.GetProjectPeriodStatistics) + + }) + }) + }) // Users m.Group("/users", func() { diff --git a/routers/api/v1/repo/repo_dashbord.go b/routers/api/v1/repo/repo_dashbord.go new file mode 100644 index 000000000..975c3aa00 --- /dev/null +++ b/routers/api/v1/repo/repo_dashbord.go @@ -0,0 +1,509 @@ +package repo + +import ( + "encoding/csv" + "fmt" + "io/ioutil" + "net/http" + "os" + "path" + "strconv" + "time" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" +) + +const DEFAULT_PAGE_SIZE = 10 +const DATE_FORMAT = "2006-01-02" + +type ProjectsPeriodData struct { + RecordBeginTime string `json:"recordBeginTime"` + LastUpdatedTime string `json:"lastUpdatedTime"` + PageSize int `json:"pageSize"` + TotalPage int `json:"totalPage"` + TotalCount int64 `json:"totalCount"` + PageRecords []*models.RepoStatistic `json:"pageRecords"` +} + +type UserInfo struct { + User string `json:"user"` + Mode int `json:"mode"` + PR int64 `json:"pr"` + Commit int `json:"commit"` +} + +type ProjectLatestData struct { + RecordBeginTime string `json:"recordBeginTime"` + LastUpdatedTime string `json:"lastUpdatedTime"` + CreatTime string `json:"creatTime"` + OpenI float64 `json:"openi"` + Comment int64 `json:"comment"` + View int64 `json:"view"` + Download int64 `json:"download"` + IssueClosedRatio float32 `json:"issueClosedRatio"` + Impact float64 `json:"impact"` + Completeness float64 `json:"completeness"` + Liveness float64 `json:"liveness"` + ProjectHealth float64 `json:"projectHealth"` + TeamHealth float64 `json:"teamHealth"` + Growth float64 `json:"growth"` + Description string `json:"description"` + Top10 []UserInfo `json:"top10"` +} + +func RestoreForkNumber(ctx *context.Context) { + repos, err := models.GetAllRepositories() + if err != nil { + log.Error("GetAllRepositories failed: %v", err.Error()) + return + } + for _, repo := range repos { + models.RestoreRepoStatFork(int64(repo.NumForks), repo.ID) + } + + ctx.JSON(http.StatusOK, struct{}{}) +} + +func GetAllProjectsPeriodStatistics(ctx *context.Context) { + + recordBeginTime, err := getRecordBeginTime() + if err != nil { + log.Error("Can not get record begin time", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) + return + } + beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) + if err != nil { + log.Error("Parameter is wrong", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong")) + return + } + q := ctx.QueryTrim("q") + page := ctx.QueryInt("page") + if page <= 0 { + page = 1 + } + pageSize := ctx.QueryInt("pagesize") + if pageSize <= 0 { + pageSize = DEFAULT_PAGE_SIZE + } + orderBy := getOrderBy(ctx) + + latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime() + if err != nil { + log.Error("Can not query the last updated time.", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error")) + return + } + + countSql := generateCountSql(beginTime, endTime, latestDate, q) + total, err := models.CountRepoStatByRawSql(countSql) + if err != nil { + log.Error("Can not query total count.", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error")) + return + } + + projectsPeriodData := ProjectsPeriodData{ + RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), + PageSize: pageSize, + TotalPage: getTotalPage(total, pageSize), + TotalCount: total, + LastUpdatedTime: latestUpdatedTime, + PageRecords: models.GetRepoStatisticByRawSql(generatePageSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)), + } + + ctx.JSON(http.StatusOK, projectsPeriodData) + +} + +func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) { + + recordBeginTime, err := getRecordBeginTime() + if err != nil { + log.Error("Can not get record begin time", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) + return + } + beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) + if err != nil { + log.Error("Parameter is wrong", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong")) + return + } + q := ctx.QueryTrim("q") + page := ctx.QueryInt("page") + if page <= 0 { + page = 1 + } + pageSize := 1000 + orderBy := getOrderBy(ctx) + + _, latestDate, err := models.GetRepoStatLastUpdatedTime() + if err != nil { + log.Error("Can not query the last updated time.", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error")) + return + } + + countSql := generateCountSql(beginTime, endTime, latestDate, q) + total, err := models.CountRepoStatByRawSql(countSql) + if err != nil { + log.Error("Can not query total count.", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error")) + return + } + + fileName := getFileName(ctx, beginTime, endTime) + + if err := os.MkdirAll(setting.RadarMap.Path, os.ModePerm); err != nil { + ctx.Error(http.StatusBadRequest, fmt.Errorf("Failed to create dir %s: %v", setting.AvatarUploadPath, err).Error()) + } + + totalPage := getTotalPage(total, pageSize) + + f, e := os.Create(fileName) + defer f.Close() + if e != nil { + log.Warn("Failed to create file", e) + } + writer := csv.NewWriter(f) + writer.Write(allProjectsPeroidHeader(ctx)) + for i := 0; i <= totalPage; i++ { + + pageRecords := models.GetRepoStatisticByRawSql(generatePageSql(beginTime, endTime, latestDate, q, orderBy, i+1, pageSize)) + for _, record := range pageRecords { + e = writer.Write(allProjectsPeroidValues(record, ctx)) + if e != nil { + log.Warn("Failed to write record", e) + } + } + writer.Flush() + + } + + ctx.ServeFile(fileName) + +} + +func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time) string { + baseName := setting.RadarMap.Path + "/" + if ctx.QueryTrim("type") != "" { + baseName = baseName + ctx.QueryTrim("type") + "_" + } + if ctx.QueryTrim("q") != "" { + baseName = baseName + ctx.QueryTrim("q") + "_" + } + baseName = baseName + beginTime.AddDate(0, 0, -1).Format(DATE_FORMAT) + "_to_" + endTime.AddDate(0, 0, -1).Format(DATE_FORMAT) + "_" + strconv.FormatInt(time.Now().Unix(), 10) + ".csv" + return baseName +} + +func ClearUnusedStatisticsFile() { + fileInfos, err := ioutil.ReadDir(setting.RadarMap.Path) + if err != nil { + log.Warn("can not read dir: "+setting.RadarMap.Path, err) + return + } + + for _, fileInfo := range fileInfos { + if !fileInfo.IsDir() && fileInfo.ModTime().Before(time.Now().AddDate(0, 0, -1)) { + os.Remove(path.Join(setting.RadarMap.Path, fileInfo.Name())) + } + } + +} + +func allProjectsPeroidHeader(ctx *context.Context) []string { + + return []string{ctx.Tr("repos.id"), ctx.Tr("repos.projectName"), ctx.Tr("repos.isPrivate"), ctx.Tr("repos.openi"), ctx.Tr("repos.visit"), ctx.Tr("repos.download"), ctx.Tr("repos.pr"), ctx.Tr("repos.commit"), + ctx.Tr("repos.watches"), ctx.Tr("repos.stars"), ctx.Tr("repos.forks"), ctx.Tr("repos.issues"), ctx.Tr("repos.closedIssues"), ctx.Tr("repos.contributor")} + +} + +func allProjectsPeroidValues(rs *models.RepoStatistic, ctx *context.Context) []string { + return []string{strconv.FormatInt(rs.RepoID, 10), rs.Name, getIsPrivateDisplay(rs.IsPrivate, ctx), strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64), + strconv.FormatInt(rs.NumVisits, 10), strconv.FormatInt(rs.NumDownloads, 10), strconv.FormatInt(rs.NumPulls, 10), strconv.FormatInt(rs.NumCommits, 10), + strconv.FormatInt(rs.NumWatches, 10), strconv.FormatInt(rs.NumStars, 10), strconv.FormatInt(rs.NumForks, 10), strconv.FormatInt(rs.NumIssues, 10), + strconv.FormatInt(rs.NumClosedIssues, 10), strconv.FormatInt(rs.NumContributor, 10), + } +} + +func getIsPrivateDisplay(private bool, ctx *context.Context) string { + if private { + return ctx.Tr("repos.yes") + } else { + return ctx.Tr("repos.no") + } +} + +func GetProjectLatestStatistics(ctx *context.Context) { + repoId := ctx.Params(":id") + recordBeginTime, err := getRecordBeginTime() + if err != nil { + log.Error("Can not get record begin time", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) + return + } + latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime(repoId) + repoIdInt, _ := strconv.ParseInt(repoId, 10, 64) + repoStat, err := models.GetRepoStatisticByDateAndRepoId(latestDate, repoIdInt) + if err != nil { + log.Error("Can not get the repo statistics "+repoId, err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_stat_error")) + return + } + + repository, err := models.GetRepositoryByID(repoIdInt) + if err != nil { + log.Error("Can not get the repo info "+repoId, err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_info_error")) + return + } + projectLatestData := ProjectLatestData{ + RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), + CreatTime: time.Unix(int64(repository.CreatedUnix), 0).Format(DATE_FORMAT), + LastUpdatedTime: latestUpdatedTime, + OpenI: repoStat.RadarTotal, + Comment: repoStat.NumComments, + View: repoStat.NumVisits, + Download: repoStat.NumDownloads, + IssueClosedRatio: repoStat.IssueFixedRate, + Impact: repoStat.Impact, + Completeness: repoStat.Completeness, + Liveness: repoStat.Liveness, + ProjectHealth: repoStat.ProjectHealth, + TeamHealth: repoStat.TeamHealth, + Growth: repoStat.Growth, + Description: repository.Description, + } + + contributors, err := models.GetTop10Contributor(repository.RepoPath()) + if err != nil { + log.Error("can not get contributors", err) + } + users := make([]UserInfo, 0) + + for _, contributor := range contributors { + mode := repository.GetCollaboratorMode(contributor.UserId) + if mode == -1 { + if contributor.IsAdmin { + mode = int(models.AccessModeAdmin) + } + if contributor.UserId == repository.OwnerID { + mode = int(models.AccessModeOwner) + } + } + + pr := models.GetPullCountByUserAndRepoId(repoIdInt, contributor.UserId) + userInfo := UserInfo{ + User: contributor.Committer, + Commit: contributor.CommitCnt, + Mode: mode, + PR: pr, + } + users = append(users, userInfo) + + } + + projectLatestData.Top10 = users + + ctx.JSON(http.StatusOK, projectLatestData) + +} + +func GetProjectPeriodStatistics(ctx *context.Context) { + repoId := ctx.Params(":id") + recordBeginTime, err := getRecordBeginTime() + if err != nil { + log.Error("Can not get record begin time", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) + return + } + + repoIdInt, _ := strconv.ParseInt(repoId, 10, 64) + + if err != nil { + log.Error("Can not get record begin time", err) + ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) + return + } + beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) + isOpenI := ctx.QueryBool("openi") + var repositorys []*models.RepoStatistic + if isOpenI { + repositorys = models.GetRepoStatisticByRawSql(generateRadarSql(beginTime, endTime, repoIdInt)) + } else { + repositorys = models.GetRepoStatisticByRawSql(generateTargetSql(beginTime, endTime, repoIdInt)) + } + ctx.JSON(http.StatusOK, repositorys) +} + +func generateRadarSql(beginTime time.Time, endTime time.Time, repoId int64) string { + sql := "SELECT date, impact, completeness, liveness, project_health, team_health, growth, radar_total FROM repo_statistic" + + " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + + return sql +} + +func generateTargetSql(beginTime time.Time, endTime time.Time, repoId int64) string { + sql := "SELECT date, num_visits,num_downloads,num_commits FROM repo_statistic" + + " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + + return sql +} + +func generateCountSql(beginTime time.Time, endTime time.Time, yesterday string, q string) string { + countSql := "SELECT count(*) FROM " + + "(SELECT repo_id FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," + + "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" + + " where A.repo_id=B.repo_id" + if q != "" { + countSql = countSql + " and B.name like '%" + q + "%'" + } + return countSql +} + +func generatePageSql(beginTime time.Time, endTime time.Time, yesterday string, q string, orderBy string, page int, pageSize int) string { + countSql := "SELECT A.repo_id,name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " + + "(SELECT repo_id,sum(num_watches_added) as num_watches,sum(num_visits) as num_visits, sum(num_downloads_added) as num_downloads,sum(num_pulls_added) as num_pulls,sum(num_commits_added) as num_commits,sum(num_stars_added) as num_stars,sum(num_forks_added) num_forks,sum(num_issues_added) as num_issues,sum(num_closed_issues_added) as num_closed_issues,sum(num_contributor_added) as num_contributor " + + " FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," + + "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" + + " where A.repo_id=B.repo_id" + if q != "" { + countSql = countSql + " and B.name like '%" + q + "%'" + } + countSql = countSql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) + return countSql +} + +func getOrderBy(ctx *context.Context) string { + orderBy := "" + switch ctx.Query("sort") { + case "openi": + orderBy = "B.radar_total" + case "view": + orderBy = "A.num_visits" + case "download": + orderBy = "A.num_downloads" + case "pr": + orderBy = "A.num_pulls" + case "commit": + orderBy = "A.num_commits" + case "watch": + orderBy = "A.num_watches" + case "star": + orderBy = "A.num_stars" + case "fork": + orderBy = "A.num_forks" + case "issue": + orderBy = "A.num_issues" + case "issue_closed": + orderBy = "A.num_closed_issues" + case "contributor": + orderBy = "A.num_contributor" + default: + orderBy = "B.radar_total" + } + return orderBy +} + +func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) { + queryType := ctx.QueryTrim("type") + now := time.Now() + recordBeginTimeTemp := recordBeginTime.AddDate(0, 0, 1) + + beginTimeStr := ctx.QueryTrim("beginTime") + endTimeStr := ctx.QueryTrim("endTime") + var beginTime time.Time + var endTime time.Time + var err error + if queryType != "" { + + if queryType == "all" { + beginTime = recordBeginTimeTemp + endTime = now + } else if queryType == "yesterday" { + endTime = now + beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location()) + + } else if queryType == "current_week" { + beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+1) + beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) + endTime = now + } else if queryType == "current_month" { + endTime = now + beginTime = time.Date(endTime.Year(), endTime.Month(), 2, 0, 0, 0, 0, now.Location()) + } else if queryType == "monthly" { + endTime = now + beginTime = now.AddDate(0, -1, 1) + beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) + + } else if queryType == "current_year" { + endTime = now + beginTime = time.Date(endTime.Year(), 1, 2, 0, 0, 0, 0, now.Location()) + + } else if queryType == "last_month" { + + lastMonthTime := now.AddDate(0, -1, 0) + beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 2, 0, 0, 0, 0, now.Location()) + endTime = time.Date(now.Year(), now.Month(), 2, 0, 0, 0, 0, now.Location()) + + } else { + return now, now, fmt.Errorf("The value of type parameter is wrong.") + + } + + } else { + if beginTimeStr == "" || endTimeStr == "" { + //如果查询类型和开始时间结束时间都未设置,按queryType=all处理 + beginTime = recordBeginTimeTemp + endTime = now + + } else { + + beginTime, err = time.Parse("2006-01-02", beginTimeStr) + if err != nil { + return now, now, err + } + + endTime, err = time.Parse("2006-01-02", endTimeStr) + if err != nil { + return now, now, err + } + + beginTime = beginTime.AddDate(0, 0, 1) + endTime = endTime.AddDate(0, 0, 1) + } + + } + + if beginTime.Before(recordBeginTimeTemp) { + beginTime = recordBeginTimeTemp + } + + return beginTime, endTime, nil + +} + +func getRecordBeginTime() (time.Time, error) { + + return time.Parse(DATE_FORMAT, setting.RadarMap.RecordBeginTime) +} + +func getTotalPage(total int64, pageSize int) int { + + another := 0 + if int(total)%pageSize != 0 { + another = 1 + } + return int(total)/pageSize + another + +} diff --git a/routers/home.go b/routers/home.go index 71ba5b6c5..d2c93c771 100755 --- a/routers/home.go +++ b/routers/home.go @@ -33,8 +33,9 @@ const ( // tplExploreOrganizations explore organizations page template tplExploreOrganizations base.TplName = "explore/organizations" // tplExploreCode explore code page template - tplExploreCode base.TplName = "explore/code" - tplExploreImages base.TplName = "explore/images" + tplExploreCode base.TplName = "explore/code" + tplExploreImages base.TplName = "explore/images" + tplExploreExploreDataAnalysis base.TplName = "explore/data_analysis" ) // Home render home page @@ -146,7 +147,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { ctx.Data["SortType"] = "hot" orderBy = models.SearchOrderByHot } - + orderBy = orderBy + ",id" //todo:support other topics keyword := strings.Trim(ctx.Query("q"), " ") topic := strings.Trim(ctx.Query("topic"), " ") @@ -501,6 +502,10 @@ func ExploreImages(ctx *context.Context) { ctx.HTML(200, tplExploreImages) } +func ExploreDataAnalysis(ctx *context.Context) { + ctx.HTML(200, tplExploreExploreDataAnalysis) +} + // NotFound render 404 page func NotFound(ctx *context.Context) { ctx.Data["Title"] = "Page Not Found" diff --git a/routers/org/members.go b/routers/org/members.go old mode 100644 new mode 100755 diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 03fba6cd1..529d576bc 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -204,7 +204,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { resourceSpecId := form.ResourceSpecId if !jobNamePattern.MatchString(jobName) { - ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplModelArtsNew, &form) + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplCloudBrainNew, &form) return } diff --git a/routers/repo/http.go b/routers/repo/http.go index ed6276466..ad2abf567 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -317,6 +317,12 @@ func HTTP(ctx *context.Context) { go repo.IncreaseCloneCnt() } + if ctx.Req.Method == "POST" { + if strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { + go repo.IncreaseGitCloneCnt() + } + } + w := ctx.Resp r := ctx.Req.Request cfg := &serviceConfig{ diff --git a/routers/repo/modelarts.go b/routers/repo/modelarts.go index f33d345cd..aec6a024f 100755 --- a/routers/repo/modelarts.go +++ b/routers/repo/modelarts.go @@ -27,15 +27,10 @@ import ( ) const ( - // tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index" tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index" tplModelArtsNotebookNew base.TplName = "repo/modelarts/notebook/new" tplModelArtsNotebookShow base.TplName = "repo/modelarts/notebook/show" - tplModelArtsIndex base.TplName = "repo/modelarts/index" - tplModelArtsNew base.TplName = "repo/modelarts/new" - tplModelArtsShow base.TplName = "repo/modelarts/show" - tplModelArtsTrainJobIndex base.TplName = "repo/modelarts/trainjob/index" tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" @@ -50,229 +45,6 @@ func MustEnableModelArts(ctx *context.Context) { } } -func ModelArtsIndex(ctx *context.Context) { - MustEnableModelArts(ctx) - repo := ctx.Repo.Repository - page := ctx.QueryInt("page") - if page <= 0 { - page = 1 - } - - ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ - ListOptions: models.ListOptions{ - Page: page, - PageSize: setting.UI.IssuePagingNum, - }, - RepoID: repo.ID, - Type: models.TypeCloudBrainTwo, - }) - if err != nil { - ctx.ServerError("Cloudbrain", err) - return - } - - for i, task := range ciTasks { - if task.Status == string(models.JobRunning) { - ciTasks[i].CanDebug = true - } else { - ciTasks[i].CanDebug = false - } - - ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) - } - - pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) - pager.SetDefaultParams(ctx) - ctx.Data["Page"] = pager - - ctx.Data["PageIsCloudBrain"] = true - ctx.Data["Tasks"] = ciTasks - ctx.HTML(200, tplModelArtsIndex) -} - -func ModelArtsNew(ctx *context.Context) { - ctx.Data["PageIsCloudBrain"] = true - - t := time.Now() - 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) - if err != nil { - ctx.ServerError("GetAllUserAttachments failed:", err) - return - } - - ctx.Data["attachments"] = attachs - ctx.Data["dataset_path"] = modelarts.DataSetMountPath - ctx.Data["env"] = modelarts.NotebookEnv - ctx.Data["notebook_type"] = modelarts.NotebookType - if modelarts.FlavorInfos == nil { - json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos) - } - ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo - ctx.HTML(200, tplModelArtsNew) -} - -func ModelArtsCreate(ctx *context.Context, form auth.CreateModelArtsForm) { - ctx.Data["PageIsCloudBrain"] = true - jobName := form.JobName - uuid := form.Attachment - description := form.Description - //repo := ctx.Repo.Repository - if !jobNamePattern.MatchString(jobName) { - ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplModelArtsNew, &form) - return - } - err := modelarts.GenerateTask(ctx, jobName, uuid, description) - if err != nil { - ctx.RenderWithErr(err.Error(), tplModelArtsNew, &form) - return - } - - ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts") -} - -func ModelArtsShow(ctx *context.Context) { - ctx.Data["PageIsCloudBrain"] = true - - var jobID = ctx.Params(":jobid") - task, err := models.GetCloudbrainByJobID(jobID) - if err != nil { - ctx.Data["error"] = err.Error() - ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) - return - } - - result, err := modelarts.GetJob(jobID) - if err != nil { - ctx.Data["error"] = err.Error() - ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) - return - } - - if result != nil { - task.Status = result.Status - err = models.UpdateJob(task) - if err != nil { - ctx.Data["error"] = err.Error() - ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) - return - } - - createTime, _ := com.StrTo(result.CreationTimestamp).Int64() - result.CreateTime = time.Unix(int64(createTime/1000), 0).Format("2006-01-02 15:04:05") - endTime, _ := com.StrTo(result.LatestUpdateTimestamp).Int64() - result.LatestUpdateTime = time.Unix(int64(endTime/1000), 0).Format("2006-01-02 15:04:05") - result.QueuingInfo.BeginTime = time.Unix(int64(result.QueuingInfo.BeginTimestamp/1000), 0).Format("2006-01-02 15:04:05") - result.QueuingInfo.EndTime = time.Unix(int64(result.QueuingInfo.EndTimestamp/1000), 0).Format("2006-01-02 15:04:05") - } - - ctx.Data["task"] = task - ctx.Data["jobID"] = jobID - ctx.Data["result"] = result - ctx.HTML(200, tplModelArtsShow) -} - -func ModelArtsDebug(ctx *context.Context) { - var jobID = ctx.Params(":jobid") - _, err := models.GetCloudbrainByJobID(jobID) - if err != nil { - ctx.ServerError("GetCloudbrainByJobID failed", err) - return - } - - result, err := modelarts.GetJob(jobID) - if err != nil { - ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) - return - } - - res, err := modelarts.GetJobToken(jobID) - if err != nil { - ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) - return - } - - urls := strings.Split(result.Spec.Annotations.Url, "/") - urlPrefix := result.Spec.Annotations.TargetDomain - for i, url := range urls { - if i > 2 { - urlPrefix += "/" + url - } - } - - //urlPrefix := result.Spec.Annotations.TargetDomain + "/modelarts/internal/hub/notebook/user/" + task.JobID - log.Info(urlPrefix) - debugUrl := urlPrefix + "?token=" + res.Token - ctx.Redirect(debugUrl) -} - -func ModelArtsStop(ctx *context.Context) { - var jobID = ctx.Params(":jobid") - log.Info(jobID) - task, err := models.GetCloudbrainByJobID(jobID) - if err != nil { - ctx.ServerError("GetCloudbrainByJobID failed", err) - return - } - - if task.Status != string(models.JobRunning) { - log.Error("the job(%s) is not running", task.JobName) - ctx.ServerError("the job is not running", errors.New("the job is not running")) - return - } - - param := models.NotebookAction{ - Action: models.ActionStop, - } - res, err := modelarts.StopJob(jobID, param) - if err != nil { - log.Error("StopJob(%s) failed:%v", task.JobName, err.Error()) - ctx.ServerError("StopJob failed", err) - return - } - - task.Status = res.CurrentStatus - err = models.UpdateJob(task) - if err != nil { - ctx.ServerError("UpdateJob failed", err) - return - } - - ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts") -} - -func ModelArtsDel(ctx *context.Context) { - var jobID = ctx.Params(":jobid") - task, err := models.GetCloudbrainByJobID(jobID) - if err != nil { - ctx.ServerError("GetCloudbrainByJobID failed", err) - return - } - - if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) { - log.Error("the job(%s) has not been stopped", task.JobName) - ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped")) - return - } - - _, err = modelarts.DelJob(jobID) - if err != nil { - log.Error("DelJob(%s) failed:%v", task.JobName, err.Error()) - ctx.ServerError("DelJob failed", err) - return - } - - err = models.DeleteJob(task) - if err != nil { - ctx.ServerError("DeleteJob failed", err) - return - } - - ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts") -} - func NotebookIndex(ctx *context.Context) { MustEnableModelArts(ctx) repo := ctx.Repo.Repository @@ -342,8 +114,9 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) jobName := form.JobName uuid := form.Attachment description := form.Description + flavor := form.Flavor - err := modelarts.GenerateTask(ctx, jobName, uuid, description) + err := modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) if err != nil { ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) return diff --git a/routers/repo/repo_statistic.go b/routers/repo/repo_statistic.go index 2de22a1ee..c1edb0fed 100755 --- a/routers/repo/repo_statistic.go +++ b/routers/repo/repo_statistic.go @@ -93,6 +93,7 @@ func RepoStatisticDaily(date string) { IsPrivate: repo.IsPrivate, NumWatches: int64(repo.NumWatches), NumStars: int64(repo.NumStars), + NumForks: int64(repo.NumForks), NumDownloads: repo.CloneCnt, NumComments: numComments, NumVisits: int64(numVisits), @@ -115,7 +116,7 @@ func RepoStatisticDaily(date string) { } dayBeforeDate := t.AddDate(0, 0, -1).Format("2006-01-02") - repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate) + repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate, repo.ID) if err != nil { log.Error("get data of day before the date failed ", err) diff --git a/routers/repo/user_data_analysis.go b/routers/repo/user_data_analysis.go index 7dc7af321..68cccd478 100755 --- a/routers/repo/user_data_analysis.go +++ b/routers/repo/user_data_analysis.go @@ -1,13 +1,27 @@ package repo import ( + "fmt" + "net/http" "time" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" ) +func QueryUserStaticData(ctx *context.Context) { + startDate := ctx.Query("startDate") + endDate := ctx.Query("endDate") + log.Info("startDate=" + startDate + " endDate=" + endDate) + startTime, _ := time.Parse("2006-01-02", startDate) + endTime, _ := time.Parse("2006-01-02", endDate) + log.Info("startTime=" + fmt.Sprint(startTime.Unix()) + " endDate=" + fmt.Sprint(endTime.Unix())) + ctx.JSON(http.StatusOK, models.QueryUserStaticData(startTime.Unix(), endTime.Unix())) + +} + func TimingCountDataByDate(date string) { t, _ := time.Parse("2006-01-02", date) diff --git a/routers/repo/view.go b/routers/repo/view.go old mode 100644 new mode 100755 index 9477b27dd..cd59ec920 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -12,6 +12,7 @@ import ( "fmt" gotemplate "html/template" "io/ioutil" + "net/http" "net/url" "path" "strings" @@ -31,11 +32,12 @@ import ( ) const ( - tplRepoEMPTY base.TplName = "repo/empty" - tplRepoHome base.TplName = "repo/home" - tplWatchers base.TplName = "repo/watchers" - tplForks base.TplName = "repo/forks" - tplMigrating base.TplName = "repo/migrating" + tplRepoEMPTY base.TplName = "repo/empty" + tplRepoHome base.TplName = "repo/home" + tplWatchers base.TplName = "repo/watchers" + tplForks base.TplName = "repo/forks" + tplMigrating base.TplName = "repo/migrating" + tplContributors base.TplName = "repo/contributors" ) type namedBlob struct { @@ -243,6 +245,11 @@ func renderDirectory(ctx *context.Context, treeLink string) { ctx.Data["ReadmeInList"] = true ctx.Data["ReadmeExist"] = true ctx.Data["FileIsSymlink"] = readmeFile.isSymlink + ctx.Data["ReadmeName"] = readmeFile.name + + if ctx.Repo.CanEnableEditor() { + ctx.Data["CanEditFile"] = true + } dataRc, err := readmeFile.blob.DataAsync() if err != nil { @@ -570,19 +577,29 @@ func safeURL(address string) string { } type ContributorInfo struct { - UserInfo *models.User // nil for contributor who is not a registered user - Email string - CommitCnt int + UserInfo *models.User // nil for contributor who is not a registered user + RelAvatarLink string `json:"rel_avatar_link"` + UserName string `json:"user_name"` + Email string `json:"email"` + CommitCnt int `json:"commit_cnt"` +} + +type GetContributorsInfo struct { + ErrorCode int `json:"error_code"` + ErrorMsg string `json:"error_msg"` + Count int `json:"count"` + ContributorInfo []*ContributorInfo `json:"contributor_info"` } -func getContributorInfo(contributorInfos []*ContributorInfo, email string) *ContributorInfo{ +func getContributorInfo(contributorInfos []*ContributorInfo, email string) *ContributorInfo { for _, c := range contributorInfos { - if strings.Compare(c.Email,email) == 0 { + if strings.Compare(c.Email, email) == 0 { return c } } return nil } + // Home render repository home page func Home(ctx *context.Context) { if len(ctx.Repo.Units) > 0 { @@ -591,35 +608,41 @@ func Home(ctx *context.Context) { if err == nil && contributors != nil { startTime := time.Now() var contributorInfos []*ContributorInfo - contributorInfoHash:= make(map[string]*ContributorInfo) + contributorInfoHash := make(map[string]*ContributorInfo) + count := 0 for _, c := range contributors { - if strings.Compare(c.Email,"") == 0 { + if count >= 25 { + continue + } + if strings.Compare(c.Email, "") == 0 { continue } // get user info from committer email user, err := models.GetUserByActivateEmail(c.Email) if err == nil { // committer is system user, get info through user's primary email - if existedContributorInfo,ok:=contributorInfoHash[user.Email];ok { + if existedContributorInfo, ok := contributorInfoHash[user.Email]; ok { // existed: same primary email, different committer name existedContributorInfo.CommitCnt += c.CommitCnt - }else{ + } else { // new committer info var newContributor = &ContributorInfo{ - user, user.Email,c.CommitCnt, + user, user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt, } - contributorInfos = append(contributorInfos, newContributor ) + count++ + contributorInfos = append(contributorInfos, newContributor) contributorInfoHash[user.Email] = newContributor } } else { // committer is not system user - if existedContributorInfo,ok:=contributorInfoHash[c.Email];ok { + if existedContributorInfo, ok := contributorInfoHash[c.Email]; ok { // existed: same primary email, different committer name existedContributorInfo.CommitCnt += c.CommitCnt - }else{ + } else { var newContributor = &ContributorInfo{ - user, c.Email,c.CommitCnt, + user, "", "",c.Email, c.CommitCnt, } + count++ contributorInfos = append(contributorInfos, newContributor) contributorInfoHash[c.Email] = newContributor } @@ -627,7 +650,7 @@ func Home(ctx *context.Context) { } ctx.Data["ContributorInfo"] = contributorInfos var duration = time.Since(startTime) - log.Info("getContributorInfo cost: %v seconds",duration.Seconds()) + log.Info("getContributorInfo cost: %v seconds", duration.Seconds()) } if ctx.Repo.Repository.IsBeingCreated() { task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) @@ -694,13 +717,13 @@ func renderLicense(ctx *context.Context) { log.Error("failed to get license content: %v, err:%v", f, err) continue } - if bytes.Compare(buf,license) == 0 { - log.Info("got matched license:%v",f) + if bytes.Compare(buf, license) == 0 { + log.Info("got matched license:%v", f) ctx.Data["LICENSE"] = f return } } - log.Info("not found matched license,repo:%v",ctx.Repo.Repository.Name) + log.Info("not found matched license,repo:%v", ctx.Repo.Repository.Name) } func renderLanguageStats(ctx *context.Context) { @@ -801,31 +824,31 @@ func renderCode(ctx *context.Context) { baseGitRepo, err := git.OpenRepository(ctx.Repo.Repository.BaseRepo.RepoPath()) defer baseGitRepo.Close() if err != nil { - log.Error("error open baseRepo:%s",ctx.Repo.Repository.BaseRepo.RepoPath()) + log.Error("error open baseRepo:%s", ctx.Repo.Repository.BaseRepo.RepoPath()) ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error - }else{ - if _,error:= baseGitRepo.GetBranch(ctx.Repo.BranchName);error==nil{ + } else { + if _, error := baseGitRepo.GetBranch(ctx.Repo.BranchName); error == nil { //base repo has the same branch, then compare between current repo branch and base repo's branch - compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.BranchName - ctx.SetParams("*",compareUrl) + compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.BranchName + ctx.SetParams("*", compareUrl) ctx.Data["UpstreamSameBranchName"] = true - }else{ + } else { //else, compare between current repo branch and base repo's default branch - compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.Repository.BaseRepo.DefaultBranch - ctx.SetParams("*",compareUrl) + compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.Repository.BaseRepo.DefaultBranch + ctx.SetParams("*", compareUrl) ctx.Data["UpstreamSameBranchName"] = false } _, _, headGitRepo, compareInfo, _, _ := ParseCompareInfo(ctx) defer headGitRepo.Close() - if compareInfo!= nil { - if compareInfo.Commits!=nil { - log.Info("compareInfoCommits数量:%d",compareInfo.Commits.Len()) + if compareInfo != nil { + if compareInfo.Commits != nil { + log.Info("compareInfoCommits数量:%d", compareInfo.Commits.Len()) ctx.Data["FetchUpstreamCnt"] = compareInfo.Commits.Len() - }else{ + } else { log.Info("compareInfo nothing different") ctx.Data["FetchUpstreamCnt"] = 0 } - }else{ + } else { ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error } } @@ -893,3 +916,64 @@ func Forks(ctx *context.Context) { ctx.HTML(200, tplForks) } + +func Contributors(ctx *context.Context) { + ctx.HTML(http.StatusOK, tplContributors) +} + +func ContributorsAPI(ctx *context.Context) { + count := 0 + errorCode := 0 + errorMsg := "" + contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath()) + var contributorInfos []*ContributorInfo + if err == nil && contributors != nil { + contributorInfoHash := make(map[string]*ContributorInfo) + for _, c := range contributors { + if strings.Compare(c.Email, "") == 0 { + continue + } + // get user info from committer email + user, err := models.GetUserByActivateEmail(c.Email) + if err == nil { + // committer is system user, get info through user's primary email + if existedContributorInfo, ok := contributorInfoHash[user.Email]; ok { + // existed: same primary email, different committer name + existedContributorInfo.CommitCnt += c.CommitCnt + } else { + // new committer info + var newContributor = &ContributorInfo{ + user, user.RelAvatarLink(),user.Name, user.Email,c.CommitCnt, + } + count++ + contributorInfos = append(contributorInfos, newContributor) + contributorInfoHash[user.Email] = newContributor + } + } else { + // committer is not system user + if existedContributorInfo, ok := contributorInfoHash[c.Email]; ok { + // existed: same primary email, different committer name + existedContributorInfo.CommitCnt += c.CommitCnt + } else { + var newContributor = &ContributorInfo{ + user, "", "",c.Email,c.CommitCnt, + } + count++ + contributorInfos = append(contributorInfos, newContributor) + contributorInfoHash[c.Email] = newContributor + } + } + } + } else { + log.Error("GetContributors failed: %v", err) + errorCode = -1 + errorMsg = err.Error() + } + + ctx.JSON(http.StatusOK, GetContributorsInfo{ + ErrorCode: errorCode, + ErrorMsg: errorMsg, + Count: count, + ContributorInfo: contributorInfos, + }) +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 7e7d0642a..a3de68373 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -311,7 +311,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Head("/", func() string { return "" }) - m.Get("/", routers.Dashboard) + m.Get("/", routers.Home) m.Get("/dashboard", routers.Dashboard) m.Group("/explore", func() { m.Get("", func(ctx *context.Context) { @@ -325,6 +325,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/organizations", routers.ExploreOrganizations) m.Get("/code", routers.ExploreCode) m.Get("/images", routers.ExploreImages) + m.Get("/data_analysis", routers.ExploreDataAnalysis) }, ignSignIn) m.Combo("/install", routers.InstallInit).Get(routers.Install). Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) @@ -615,6 +616,11 @@ func RegisterRoutes(m *macaron.Macaron) { //reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) // ***** START: Organization ***** + m.Group("/org", func() { + m.Group("/:org", func() { + m.Get("/members", org.Members) + }, context.OrgAssignment()) + }) m.Group("/org", func() { m.Group("", func() { m.Get("/create", org.Create) @@ -625,7 +631,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/dashboard", user.Dashboard) m.Get("/^:type(issues|pulls)$", user.Issues) m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) - m.Get("/members", org.Members) + //m.Get("/members", org.Members) m.Post("/members/action/:action", org.MembersAction) m.Get("/teams", org.Teams) @@ -786,9 +792,11 @@ 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", repo.QueryUserStaticData) // Grouping for those endpoints not requiring authentication m.Group("/:username/:reponame", func() { + m.Get("/contributors", repo.Contributors) + m.Get("/contributors/list", repo.ContributorsAPI) m.Group("/milestone", func() { m.Get("/:id", repo.MilestoneIssuesAndPulls) }, reqRepoIssuesOrPullsReader, context.RepoRef()) diff --git a/routers/user/auth.go b/routers/user/auth.go index 44c5ad97d..16af84b66 100755 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -544,7 +544,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR if err := models.UpdateUserCols(u, "language"); err != nil { log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language)) - return setting.AppSubURL + "/" + return setting.AppSubURL + "/dashboard" } } else { // Language setting of the user use the one previously set @@ -562,7 +562,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR u.SetLastLogin() if err := models.UpdateUserCols(u, "last_login_unix"); err != nil { ctx.ServerError("UpdateUserCols", err) - return setting.AppSubURL + "/" + return setting.AppSubURL + "/dashboard" } if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) { @@ -574,9 +574,9 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR } if obeyRedirect { - ctx.Redirect(setting.AppSubURL + "/") + ctx.Redirect(setting.AppSubURL + "/dashboard") } - return setting.AppSubURL + "/" + return setting.AppSubURL + "/dashboard" } // SignInOAuth handles the OAuth2 login buttons diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 24389d122..110200894 100755 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -180,8 +180,8 @@ var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); - hm.src = "https://hm.baidu.com/hm.js?7c4ef0a24be6109ab22e63c832ab21cf"; - var s = document.getElementsByTagName("script")[0]; + hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; + var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); diff --git a/templates/base/head_home.tmpl b/templates/base/head_home.tmpl index 69bf23f51..d1b2934ea 100644 --- a/templates/base/head_home.tmpl +++ b/templates/base/head_home.tmpl @@ -181,8 +181,8 @@ var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); - hm.src = "https://hm.baidu.com/hm.js?7c4ef0a24be6109ab22e63c832ab21cf"; - var s = document.getElementsByTagName("script")[0]; + hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; + var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index c22cb9fa7..67d8fc1b7 100755 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -7,6 +7,14 @@ +
+
+ + + +
+ + {{if .IsSigned}} {{.i18n.Tr "index"}} @@ -29,6 +37,7 @@ {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} {{.i18n.Tr "explore.images"}} + {{.i18n.Tr "explore.data_analysis"}} {{else if .IsLandingPageHome}} diff --git a/templates/base/head_navbar_home.tmpl b/templates/base/head_navbar_home.tmpl index e6729da62..e334efba8 100644 --- a/templates/base/head_navbar_home.tmpl +++ b/templates/base/head_navbar_home.tmpl @@ -29,6 +29,7 @@ {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} {{.i18n.Tr "explore.images"}} + {{.i18n.Tr "explore.data_analysis"}} {{else if .IsLandingPageHome}} diff --git a/templates/explore/data_analysis.tmpl b/templates/explore/data_analysis.tmpl new file mode 100755 index 000000000..8277dc902 --- /dev/null +++ b/templates/explore/data_analysis.tmpl @@ -0,0 +1,14 @@ +{{template "base/head" .}} +
+ + +
+ +{{template "base/footer" .}} + + diff --git a/templates/home.tmpl b/templates/home.tmpl index 97a2a7fc9..4ed285954 100755 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -7,7 +7,11 @@

免费私有代码仓库,免费计算资源,大容量数据存储,
多类型硬件环境(GPU、NPU),AI开发流水线(开发-调试-训练-迭代)

- 立即使用 + {{if .IsSigned}} + 立即使用 + {{else}} + 立即使用 + {{end}}
diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl old mode 100644 new mode 100755 index a81e8ac17..7e9970d2b --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -38,11 +38,12 @@

{{.i18n.Tr "org.people"}} - {{if .IsOrganizationMember}} - - {{end}} + + + +

{{$isMember := .IsOrganizationMember}} diff --git a/templates/org/navber.tmpl b/templates/org/navber.tmpl index 9ff92845e..7bb2ff69c 100755 --- a/templates/org/navber.tmpl +++ b/templates/org/navber.tmpl @@ -3,10 +3,10 @@ {{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} + + {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} + {{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} - - {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} - {{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} @@ -23,10 +23,10 @@ {{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} {{end}} + + {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} + {{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} - - {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} - {{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index 41f6be643..58da09e90 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -2,8 +2,18 @@
{{template "repo/header" .}}
-

{{.DateFrom}} - {{.DateUntil}} -
+
+
+ +
+
+ {{.DateFrom}} - {{.DateUntil}} +
+
-

+
{{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}} diff --git a/templates/repo/contributors.tmpl b/templates/repo/contributors.tmpl new file mode 100755 index 000000000..de00e7961 --- /dev/null +++ b/templates/repo/contributors.tmpl @@ -0,0 +1,9 @@ +{{template "base/head" .}} +
+ {{template "repo/header" .}} +
+ + +
+
+{{template "base/footer" .}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index c290de552..6dc4d8ee5 100755 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -92,16 +92,27 @@ {{if not .Repository.IsBeingCreated}} - - -
- -
- -
-{{template "base/footer" .}} - - \ No newline at end of file diff --git a/templates/repo/modelarts/new.tmpl b/templates/repo/modelarts/new.tmpl deleted file mode 100755 index 79a31286f..000000000 --- a/templates/repo/modelarts/new.tmpl +++ /dev/null @@ -1,240 +0,0 @@ -{{template "base/head" .}} - - -
-
-
-
-
-
-
-
-
-
- {{template "repo/header" .}} -
-
- {{template "base/alert" .}} -
-

-
-
- {{.CsrfTokenHtml}} -

- {{.i18n.Tr "repo.cloudbrain.new"}} -

-
- -
- - -
- -
- - - - {{range .attachments}} - - {{end}} - - -
- -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - - {{.i18n.Tr "repo.cloudbrain.cancel"}} -
-
-
-
-
-
-{{template "base/footer" .}} - - \ No newline at end of file diff --git a/templates/repo/modelarts/notebook/new.tmpl b/templates/repo/modelarts/notebook/new.tmpl index 8cfa680f7..284d6d6c7 100755 --- a/templates/repo/modelarts/notebook/new.tmpl +++ b/templates/repo/modelarts/notebook/new.tmpl @@ -138,7 +138,7 @@ diff --git a/templates/repo/modelarts/show.tmpl b/templates/repo/modelarts/show.tmpl deleted file mode 100755 index 3f914b56d..000000000 --- a/templates/repo/modelarts/show.tmpl +++ /dev/null @@ -1,122 +0,0 @@ -{{template "base/head" .}} -
-{{template "repo/header" .}} -
-
- {{template "base/alert" .}} - -

- 返回 -

-
-
- {{with .task}} -

任务名称: {{.JobName}}

- {{end}} -
-
-

任务结果:

- {{with .result}} - - - - - - - - - - - - - - - -
状态 {{.Status}}
开始时间 {{.CreateTime}}
最后更新时间 {{.LatestUpdateTime}}
- {{end}} -
-
- {{with .result}} - - - - - - - - - - - - - - -
配置信息
开发环境类型 {{.Profile.DeType}}
硬件类型 {{.Profile.FlavorType}}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
机器规格详情
机器规格 {{.Flavor}}
规格名称 {{.FlavorDetails.Name}}
规格销售状态 {{.FlavorDetails.Status}}
排队个数 {{.FlavorDetails.QueuingNum}}
排到队的剩余时间(秒) {{.FlavorDetails.QueueLeftTime}}
自动停止时间(秒) {{.FlavorDetails.Duration}}
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
排队信息
实例状态 {{.QueuingInfo.Status}}
实例排队的开始时间 {{.QueuingInfo.BeginTime}}
排到队的剩余时间(秒) {{.QueuingInfo.RemainTime}}
实例排队的预计停止时间 {{.QueuingInfo.EndTime}}
实例在队列中的排位 {{.QueuingInfo.Rank}}
- {{end}} -
-
- -
-
-
-{{template "base/footer" .}} diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index d0b160a1c..59f076f02 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -4,7 +4,11 @@ + + {{if .ReadmeInList}} +
+
+ {{if .Repository.CanEnableEditor}} + {{if .CanEditFile}} + {{svg "octicon-pencil" 16}} + {{else}} + {{svg "octicon-pencil" 16}} + {{end}} + {{end}} +
+
+ {{end}} + {{if not .ReadmeInList}}
diff --git a/templates/repo/wiki/start.tmpl b/templates/repo/wiki/start.tmpl index d8de0fcb7..78b1ddafc 100644 --- a/templates/repo/wiki/start.tmpl +++ b/templates/repo/wiki/start.tmpl @@ -2,6 +2,13 @@
{{template "repo/header" .}}
+

+ +

{{svg "octicon-book" 32}}

{{.i18n.Tr "repo.wiki.welcome"}}

diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index e9d02d508..ea132e3ac 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -3,6 +3,14 @@ {{template "repo/header" .}} {{ $title := .title}}
+

+ +

+
@@ -28,7 +36,7 @@
-
+
{{if not $.DisableHTTP}}