diff --git a/models/cloudbrain.go b/models/cloudbrain.go
index 851ab2456..777c2edaa 100755
--- a/models/cloudbrain.go
+++ b/models/cloudbrain.go
@@ -1933,6 +1933,7 @@ func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) {
session.Commit()
go IncreaseDatasetUseCount(cloudbrain.Uuid)
+ go OperateRepoAITaskNum(cloudbrain.RepoID, 1)
return nil
}
@@ -2088,9 +2089,29 @@ func DeleteJob(job *Cloudbrain) error {
func deleteJob(e Engine, job *Cloudbrain) error {
_, err := e.ID(job.ID).Delete(job)
+ if err == nil {
+ go updateAITaskNumWhenDeleteJob(job)
+ }
return err
}
+func updateAITaskNumWhenDeleteJob(job *Cloudbrain) {
+ repoId := job.RepoID
+ if repoId == 0 {
+ t := &Cloudbrain{}
+ _, tempErr := x.ID(job.ID).Unscoped().Get(t)
+ if tempErr != nil {
+ log.Error("updateAITaskNumWhenDeleteJob error.%v", tempErr)
+ return
+ }
+ repoId = t.RepoID
+ }
+
+ if repoId > 0 {
+ go OperateRepoAITaskNum(repoId, -1)
+ }
+}
+
func GetCloudbrainByName(jobName string) (*Cloudbrain, error) {
cb := &Cloudbrain{JobName: jobName}
return getRepoCloudBrain(cb)
@@ -2293,7 +2314,6 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) {
}
go IncreaseDatasetUseCount(new.Uuid)
-
return nil
}
func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
diff --git a/models/list_options.go b/models/list_options.go
index 0946917fe..d6d1dcf0d 100644
--- a/models/list_options.go
+++ b/models/list_options.go
@@ -10,6 +10,26 @@ import (
"xorm.io/xorm"
)
+type AvailablePageSize int
+
+const (
+ PageSize15 AvailablePageSize = 15
+ PageSize30 AvailablePageSize = 30
+ PageSize50 AvailablePageSize = 50
+)
+
+func (s AvailablePageSize) IsLegal() bool {
+ switch s {
+ case PageSize30, PageSize50, PageSize15:
+ return true
+ }
+ return false
+}
+
+func (s AvailablePageSize) Int() int {
+ return int(s)
+}
+
// ListOptions options to paginate results
type ListOptions struct {
PageSize int
diff --git a/models/repo.go b/models/repo.go
index 832e3fc37..e390ef70d 100755
--- a/models/repo.go
+++ b/models/repo.go
@@ -231,10 +231,43 @@ type Repository struct {
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
- Hot int64 `xorm:"-"`
- Active int64 `xorm:"-"`
- Alias string `xorm:"INDEX"`
- LowerAlias string `xorm:"INDEX"`
+ Hot int64 `xorm:"-"`
+ Active int64 `xorm:"-"`
+ Alias string `xorm:"INDEX"`
+ LowerAlias string `xorm:"INDEX"`
+ AiTaskCnt int64 `xorm:"NOT NULL DEFAULT 0"`
+ ModelCnt int64 `xorm:"NOT NULL DEFAULT 0"`
+ DatasetCnt int64 `xorm:"NOT NULL DEFAULT 0"`
+ LastMonthVisits int64 `xorm:"NOT NULL DEFAULT 0"`
+ LastFourMonthCommits int64 `xorm:"NOT NULL DEFAULT 0"`
+}
+
+// Repository4Card format for front display
+type Repository4Card struct {
+ ID int64
+ OwnerID int64
+ OwnerName string
+ LowerName string
+ Name string
+ Alias string
+ NumWatches int
+ NumStars int
+ NumForks int
+ Description string
+ Topics []string
+ AiTaskCnt int64
+ ModelCnt int64
+ DatasetCnt int64
+ CreatedUnix timeutil.TimeStamp
+ UpdatedUnix timeutil.TimeStamp
+ PrimaryLanguage *LanguageStat
+ RelAvatarLink string
+ Contributors []*ContributorInfo
+ IsPrivate bool
+ IsFork bool
+ IsMirror bool
+ IsOwnerPrivate bool
+ IsArchived bool
}
type RepositoryShow struct {
@@ -243,6 +276,47 @@ type RepositoryShow struct {
Alias string
}
+func (repo *Repository) ToCardFormat() *Repository4Card {
+ link := repo.RelAvatarLink()
+ var isOwnerPrivate bool
+ if repo.Owner != nil && repo.Owner.Visibility.IsPrivate() {
+ isOwnerPrivate = true
+ }
+ result := &Repository4Card{
+ ID: repo.ID,
+ OwnerID: repo.OwnerID,
+ OwnerName: repo.OwnerName,
+ LowerName: repo.LowerName,
+ Name: repo.Name,
+ NumWatches: repo.NumWatches,
+ NumStars: repo.NumStars,
+ NumForks: repo.NumForks,
+ Description: repo.Description,
+ Topics: repo.Topics,
+ AiTaskCnt: repo.AiTaskCnt,
+ ModelCnt: repo.ModelCnt,
+ DatasetCnt: repo.DatasetCnt,
+ CreatedUnix: repo.CreatedUnix,
+ UpdatedUnix: repo.UpdatedUnix,
+ PrimaryLanguage: repo.PrimaryLanguage,
+ RelAvatarLink: link,
+ Alias: repo.Alias,
+ IsPrivate: repo.IsPrivate,
+ IsFork: repo.IsFork,
+ IsMirror: repo.IsMirror,
+ IsOwnerPrivate: isOwnerPrivate,
+ IsArchived: repo.IsArchived,
+ }
+ return result
+}
+
+type ContributorInfo struct {
+ RelAvatarLink string
+ UserName string
+ Email string
+ CommitCnt int
+}
+
// SanitizedOriginalURL returns a sanitized OriginalURL
func (repo *Repository) SanitizedOriginalURL() string {
if repo.OriginalURL == "" {
@@ -2379,6 +2453,75 @@ func CheckRepoStats(ctx context.Context) error {
}
}
// ***** END: Repository.NumForks *****
+
+ // ***** START: Repository.DatasetCnt *****
+ desc = "repository count 'dataset_cnt'"
+ results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.dataset_cnt!=(select count(1) from attachment inner join dataset on attachment.dataset_id = dataset.id where dataset.repo_id = repository.id)")
+ if err != nil {
+ log.Error("Select %s: %v", desc, err)
+ } else {
+ for _, result := range results {
+ id := com.StrTo(result["id"]).MustInt64()
+ select {
+ case <-ctx.Done():
+ log.Warn("CheckRepoStats: Cancelled")
+ return ErrCancelledf("during %s for repo ID %d", desc, id)
+ default:
+ }
+ log.Trace("Updating %s: %d", desc, id)
+ err = ResetRepoDatasetNum(id)
+ if err != nil {
+ log.Error("Update %s[%d]: %v", desc, id, err)
+ }
+ }
+ }
+ // ***** END: Repository.DatasetCnt *****
+
+ // ***** START: Repository.ModelCnt *****
+ desc = "repository count 'model_cnt'"
+ results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.model_cnt!=(select count(1) from ai_model_manage where repository.id = ai_model_manage.repo_id and ai_model_manage.size > 0 )")
+ if err != nil {
+ log.Error("Select %s: %v", desc, err)
+ } else {
+ for _, result := range results {
+ id := com.StrTo(result["id"]).MustInt64()
+ select {
+ case <-ctx.Done():
+ log.Warn("CheckRepoStats: Cancelled")
+ return ErrCancelledf("during %s for repo ID %d", desc, id)
+ default:
+ }
+ log.Trace("Updating %s: %d", desc, id)
+ err = ResetRepoModelNum(id)
+ if err != nil {
+ log.Error("Update %s[%d]: %v", desc, id, err)
+ }
+ }
+ }
+ // ***** END: Repository.ModelCnt *****
+
+ // ***** START: Repository.AiTaskCnt *****
+ desc = "repository count 'ai_task_cnt'"
+ results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.ai_task_cnt!=(select count(1) from cloudbrain where repository.id = cloudbrain.repo_id and (cloudbrain.deleted_at is null or cloudbrain.deleted_at = '0001-01-01 00:00:00') )")
+ if err != nil {
+ log.Error("Select %s: %v", desc, err)
+ } else {
+ for _, result := range results {
+ id := com.StrTo(result["id"]).MustInt64()
+ select {
+ case <-ctx.Done():
+ log.Warn("CheckRepoStats: Cancelled")
+ return ErrCancelledf("during %s for repo ID %d", desc, id)
+ default:
+ }
+ log.Trace("Updating %s: %d", desc, id)
+ err = ResetRepoAITaskNum(id)
+ if err != nil {
+ log.Error("Update %s[%d]: %v", desc, id, err)
+ }
+ }
+ }
+ // ***** END: Repository.AiTaskCnt *****
return nil
}
@@ -2775,3 +2918,85 @@ func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFi
}
return &RepoFile{CommitId: commitId, Content: d}, nil
}
+
+func ResetRepoAITaskNum(repoId int64) error {
+ n, err := x.Where("repo_id = ? ", repoId).Count(&Cloudbrain{})
+ if err != nil {
+ return err
+ }
+ r := Repository{
+ AiTaskCnt: n,
+ }
+ _, err = x.Cols("ai_task_cnt").Where("id = ?", repoId).Update(&r)
+ return err
+}
+
+func ResetRepoDatasetNum(repoId int64) error {
+ n, err := x.Table("attachment").Join("inner", "dataset", "attachment.dataset_id = dataset.id").Where("dataset.repo_id = ?", repoId).Count()
+ if err != nil {
+ return err
+ }
+ r := Repository{
+ DatasetCnt: n,
+ }
+ _, err = x.Cols("dataset_cnt").Where("id = ?", repoId).Update(&r)
+ return err
+}
+
+func ResetRepoModelNum(repoId int64) error {
+ _, err := x.Exec("update repository set model_cnt = (select count(1) from ai_model_manage where ai_model_manage.repo_id = ? and size > 0) where id = ?", repoId, repoId)
+ return err
+}
+
+func operateRepoCol(repoId int64, colName string, amount int64, engines ...*xorm.Engine) error {
+ var err error
+
+ if amount == 0 {
+ return nil
+ }
+ var ee *xorm.Engine
+ if len(engines) == 0 {
+ ee = x
+ } else {
+ ee = engines[0]
+ }
+ if amount > 0 {
+ _, err = ee.Exec(fmt.Sprintf("update repository set %s = %s + ? where id = ?", colName, colName), amount, repoId)
+ } else {
+ _, err = ee.Exec(fmt.Sprintf("update repository set %s = %s - ? where id = ?", colName, colName), -1*amount, repoId)
+ }
+
+ return err
+}
+
+func OperateRepoDatasetNum(repoId int64, amount int64, engines ...*xorm.Engine) error {
+ return operateRepoCol(repoId, "dataset_cnt", amount, engines...)
+}
+
+func OperateRepoModelNum(repoId int64, amount int64, engines ...*xorm.Engine) error {
+ return operateRepoCol(repoId, "model_cnt", amount, engines...)
+}
+
+func OperateRepoAITaskNum(repoId int64, amount int64, engines ...*xorm.Engine) error {
+ return operateRepoCol(repoId, "ai_task_cnt", amount, engines...)
+}
+
+func UpdateRepositoryLastFourMonthCommits(repoID int64, amount int64) error {
+ _, err := x.Exec("update repository set last_four_month_commits = ? where id = ?", amount, repoID)
+ return err
+}
+func UpdateRepositoryLastMonthVisits(repoID int64, amount int64) error {
+ _, err := x.Exec("update repository set last_month_visits = ? where id = ?", amount, repoID)
+ return err
+}
+
+func SyncStatDataToRepo(repo *Repository) {
+ //Save the visit number of repository in the last month
+ if lv, err := SumLastMonthNumVisits(repo.ID); err == nil {
+ UpdateRepositoryLastMonthVisits(repo.ID, lv)
+ }
+ //Save the commits number of repository in the last four month
+ if lc, err := SumLastFourMonthNumCommits(repo.ID); err == nil {
+ UpdateRepositoryLastFourMonthCommits(repo.ID, lc)
+ }
+}
diff --git a/models/repo_list.go b/models/repo_list.go
index 92654c11c..3c655fbd9 100755
--- a/models/repo_list.go
+++ b/models/repo_list.go
@@ -201,29 +201,41 @@ func (s SearchOrderBy) String() string {
return string(s)
}
+type FindReposResponse struct {
+ Repos []*Repository4Card
+ Page int
+ PageSize int
+ Total int64
+}
+
// Strings for sorting result
const (
- SearchOrderByAlphabetically SearchOrderBy = "name ASC"
- SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC"
- SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC"
- SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC"
- SearchOrderByOldest SearchOrderBy = "created_unix ASC"
- SearchOrderByNewest SearchOrderBy = "created_unix DESC"
- SearchOrderBySize SearchOrderBy = "size ASC"
- SearchOrderBySizeReverse SearchOrderBy = "size DESC"
- SearchOrderByID SearchOrderBy = "id ASC"
- SearchOrderByIDReverse SearchOrderBy = "id DESC"
- SearchOrderByStars SearchOrderBy = "num_stars ASC"
- SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC"
- SearchOrderByForks SearchOrderBy = "num_forks ASC"
- SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
- SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC"
- SearchOrderByUseCount SearchOrderBy = "use_count ASC"
- SearchOrderByUseCountReverse SearchOrderBy = "use_count DESC"
- SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC"
- SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC"
- SearchOrderByWatches SearchOrderBy = "num_watches DESC"
- SearchOrderByDefault SearchOrderBy = "recommend desc,num_stars DESC,updated_unix DESC"
+ SearchOrderByAlphabetically SearchOrderBy = "name ASC"
+ SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC"
+ SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC"
+ SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC"
+ SearchOrderByOldest SearchOrderBy = "created_unix ASC"
+ SearchOrderByNewest SearchOrderBy = "created_unix DESC"
+ SearchOrderBySize SearchOrderBy = "size ASC"
+ SearchOrderBySizeReverse SearchOrderBy = "size DESC"
+ SearchOrderByID SearchOrderBy = "id ASC"
+ SearchOrderByIDReverse SearchOrderBy = "id DESC"
+ SearchOrderByStars SearchOrderBy = "num_stars ASC"
+ SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC"
+ SearchOrderByForks SearchOrderBy = "num_forks ASC"
+ SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
+ SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC"
+ SearchOrderByUseCount SearchOrderBy = "use_count ASC"
+ SearchOrderByUseCountReverse SearchOrderBy = "use_count DESC"
+ SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC"
+ SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC"
+ SearchOrderByWatches SearchOrderBy = "num_watches DESC"
+ SearchOrderByDefault SearchOrderBy = "recommend desc,num_stars DESC,updated_unix DESC"
+ SearchOrderByAiTaskCntReverse SearchOrderBy = "ai_task_cnt desc"
+ SearchOrderByModelCntReverse SearchOrderBy = "model_cnt desc"
+ SearchOrderByDatasetCntReverse SearchOrderBy = "dataset_cnt desc"
+ SearchOrderByLastMonthVisitsReverse SearchOrderBy = "last_month_visits desc"
+ SearchOrderByLastFourMonthCommitsReverse SearchOrderBy = "last_four_month_commits desc"
)
// SearchRepositoryCondition creates a query condition according search repository options
diff --git a/models/repo_statistic.go b/models/repo_statistic.go
index 4f8f13ed7..ecdd77e57 100755
--- a/models/repo_statistic.go
+++ b/models/repo_statistic.go
@@ -200,3 +200,23 @@ func UpdateRepoStatVisits(repoStat *RepoStatistic) error {
_, err := xStatistic.Exec(sql, repoStat.NumVisits, repoStat.RepoID, repoStat.Date)
return err
}
+
+func SumRepoStatColumn(begin, end time.Time, repoId int64, columnName string) (int64, error) {
+ res, err := xStatistic.Where("created_unix <= ? and created_unix >= ? and repo_id = ? ", end.Unix(), begin.Unix(), repoId).Sum(&RepoStatistic{}, columnName)
+ if err != nil {
+ return 0, err
+ }
+ return int64(res), nil
+}
+
+func SumLastMonthNumVisits(repoId int64) (int64, error) {
+ end := time.Now()
+ begin := end.AddDate(0, 0, -30)
+ return SumRepoStatColumn(begin, end, repoId, "num_visits")
+}
+
+func SumLastFourMonthNumCommits(repoId int64) (int64, error) {
+ end := time.Now()
+ begin := end.AddDate(0, 0, -120)
+ return SumRepoStatColumn(begin, end, repoId, "num_commits_added")
+}
diff --git a/models/repo_tag.go b/models/repo_tag.go
index 730eb3f2a..4585a95b6 100644
--- a/models/repo_tag.go
+++ b/models/repo_tag.go
@@ -4,6 +4,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"fmt"
+ "xorm.io/builder"
)
type OfficialTag struct {
@@ -166,3 +167,33 @@ func GetAllOfficialTags() ([]OfficialTag, error) {
}
return o, nil
}
+
+type FindSelectedReposOpts struct {
+ ListOptions
+ OrgId int64
+ OnlyPublic bool
+}
+
+func GetSelectedRepos(opts FindSelectedReposOpts) ([]*Repository, error) {
+ if opts.Page < 1 {
+ opts.Page = 1
+ }
+ var cond = builder.NewCond()
+ cond = cond.And(builder.Eq{"official_tag.code": "selected"})
+ if opts.OrgId > 0 {
+ cond = cond.And(builder.Eq{"official_tag_repos.org_id": opts.OrgId})
+ }
+ if opts.OnlyPublic {
+ cond = cond.And(builder.Eq{"repository.is_private": false})
+ }
+ t := make([]*Repository, 0)
+ err := x.Join("inner", "official_tag_repos", "repository.id = official_tag_repos.repo_id").
+ Join("inner", "official_tag", "official_tag.id = official_tag_repos.tag_id").
+ Where(cond).OrderBy("repository.updated_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&t)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return t, nil
+}
diff --git a/models/topic.go b/models/topic.go
index 0b19bc1f0..ea5698f4c 100644
--- a/models/topic.go
+++ b/models/topic.go
@@ -9,6 +9,7 @@ import (
"regexp"
"strings"
"unicode/utf8"
+ "xorm.io/xorm"
"code.gitea.io/gitea/modules/timeutil"
@@ -337,3 +338,16 @@ func GetOrgTopics(orgId int64) ([]Topic, error) {
return result, nil
}
+
+func UpdateRepoTopics(repoID int64, topicNames []string, sess ...*xorm.Engine) error {
+ e := x
+ if len(sess) > 0 {
+ e = sess[0]
+ }
+ if _, err := e.ID(repoID).Cols("topics").Update(&Repository{
+ Topics: topicNames,
+ }); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/models/user.go b/models/user.go
index c421455bc..dad252d92 100755
--- a/models/user.go
+++ b/models/user.go
@@ -198,6 +198,40 @@ type SearchOrganizationsOptions struct {
All bool
}
+type User4Front struct {
+ ID int64
+ LowerName string `xorm:"UNIQUE NOT NULL"`
+ Name string `xorm:"UNIQUE NOT NULL"`
+ FullName string
+ Email string `xorm:"NOT NULL"`
+ Language string `xorm:"VARCHAR(5)"`
+ Description string
+ RelAvatarLink string
+ NumMembers int
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+}
+
+func (u *User) ToFrontFormat() *User4Front {
+ uf := &User4Front{
+ ID: u.ID,
+ LowerName: u.LowerName,
+ Name: u.Name,
+ FullName: u.FullName,
+ Email: u.Email,
+ Language: u.Language,
+ Description: u.Description,
+ CreatedUnix: u.CreatedUnix,
+ UpdatedUnix: u.UpdatedUnix,
+ NumMembers: u.NumMembers,
+ }
+ if !u.KeepEmailPrivate {
+ uf.Email = u.Email
+ }
+ uf.RelAvatarLink = u.RelAvatarLink()
+ return uf
+}
+
// GenerateRandomAvatar generates a random avatar for user.
func (u *User) IsBindWechat() bool {
return u.WechatOpenId != ""
diff --git a/models/user_business_analysis.go b/models/user_business_analysis.go
index 6c247709e..ccefbf4f6 100644
--- a/models/user_business_analysis.go
+++ b/models/user_business_analysis.go
@@ -2443,3 +2443,9 @@ func GetContentFromPromote(url string) (string, error) {
allLineStr := string(bytes)
return allLineStr, nil
}
+
+func QueryLast30DaysHighestIndexUsers(size int) ([]int64, error) {
+ userIds := make([]int64, 0)
+ err := xStatistic.Table("user_business_analysis_last30_day").Cols("id").OrderBy("user_index desc").Limit(size).Find(&userIds)
+ return userIds, err
+}
diff --git a/modules/redis/redis_key/repo_redis_key.go b/modules/redis/redis_key/repo_redis_key.go
new file mode 100644
index 000000000..b2b7ccd0a
--- /dev/null
+++ b/modules/redis/redis_key/repo_redis_key.go
@@ -0,0 +1,9 @@
+package redis_key
+
+import "fmt"
+
+const REPO_PREFIX = "repo"
+
+func RepoTopNContributors(repoId int64, N int) string {
+ return KeyJoin(REPO_PREFIX, fmt.Sprint(repoId), fmt.Sprint(N), "top_n_contributor")
+}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index bf7eb2352..68c2c641b 100755
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -677,6 +677,10 @@ var (
CloudbrainStoppedTitle string
CloudbrainStoppedRemark string
+ //repo square config
+ IncubationSourceOrgName string
+ PaperRepoTopicName string
+
//nginx proxy
PROXYURL string
RadarMap = struct {
@@ -1585,6 +1589,10 @@ func NewContext() {
CloudbrainStoppedTitle = sec.Key("CLOUDBRAIN_STOPPED_TITLE").MustString("您好,您申请的算力资源已结束使用,任务已完成运行,状态为%s,请您关注运行结果")
CloudbrainStoppedRemark = sec.Key("CLOUDBRAIN_STOPPED_REMARK").MustString("感谢您的耐心等待。")
+ sec = Cfg.Section("repo-square")
+ IncubationSourceOrgName = sec.Key("INCUBATION_ORG_NAME").MustString("OpenI")
+ PaperRepoTopicName = sec.Key("PAPER_REPO_TOPIC_NAME").MustString("openi-paper")
+
sec = Cfg.Section("point")
CloudBrainPaySwitch = sec.Key("CLOUDBRAIN_PAY_SWITCH").MustBool(false)
CloudBrainPayDelay = sec.Key("CLOUDBRAIN_PAY_DELAY").MustDuration(30 * time.Minute)
diff --git a/package.json b/package.json
index 7748f3de3..fa2c5327b 100644
--- a/package.json
+++ b/package.json
@@ -17,11 +17,12 @@
"core-js": "3.6.5",
"css-loader": "3.5.3",
"cssnano": "4.1.10",
+ "dayjs": "1.10.7",
"domino": "2.1.5",
"dropzone": "5.7.2",
"echarts": "3.8.5",
"element-ui": "2.15.5",
- "esdk-obs-browserjs": "3.20.7",
+ "esdk-obs-browserjs": "3.22.3",
"esdk-obs-nodejs": "3.20.11",
"fast-glob": "3.2.2",
"file-loader": "6.0.0",
diff --git a/public/home/home.js b/public/home/home.js
index 3f31c857f..8fb7b08b1 100755
--- a/public/home/home.js
+++ b/public/home/home.js
@@ -631,20 +631,12 @@ function displayRepo(json){
for (var i = 0, iLen = repos.length; i < iLen; i++) {
if (i >= 4) break;
var repo = repos[i];
- // ${repo["NumStars"]}${repo["NumForks"]}
html += `
-
- ${repo["Avatar"] ? `

` : `
![]()
`}
+
+ ${repo["Avatar"] ? `

` : `
![]()
`}
${repo["Description"]}
- `;
- // if (repo["Topics"] != null) {
- // for(var j = 0; j < repo["Topics"].length; j++){
- // var topic = repo["Topics"][j];
- // var url = "/explore/repos?q=" + (topic) + "&topic="
- // html += `
${topic}`;
- // }
- // }
+
`;
html += `
`;
diff --git a/routers/admin/resources.go b/routers/admin/resources.go
index feea7b69b..8db958ef5 100644
--- a/routers/admin/resources.go
+++ b/routers/admin/resources.go
@@ -307,3 +307,37 @@ func RefreshHistorySpec(ctx *context.Context) {
r["total"] = total
ctx.JSON(http.StatusOK, response.SuccessWithData(r))
}
+
+func RefreshReposHistoryCnt(ctx *context.Context) {
+ scope := ctx.Query("scope")
+ list := ctx.Query("list")
+
+ var scopeAll = false
+ if scope == "all" {
+ scopeAll = true
+ }
+ var ids = make([]int64, 0)
+ if list != "" {
+ strs := strings.Split(list, "|")
+ for _, s := range strs {
+ i, err := strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
+ return
+ }
+ ids = append(ids, i)
+ }
+
+ }
+
+ total, success, err := resource.RefreshHistorySpec(scopeAll, ids)
+ if err != nil {
+ log.Error("RefreshHistorySpec error. %v", err)
+ ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
+ return
+ }
+ r := make(map[string]interface{}, 0)
+ r["success"] = success
+ r["total"] = total
+ ctx.JSON(http.StatusOK, response.SuccessWithData(r))
+}
diff --git a/routers/api/v1/repo/topic.go b/routers/api/v1/repo/topic.go
index f4ff7a329..d2522c9ce 100644
--- a/routers/api/v1/repo/topic.go
+++ b/routers/api/v1/repo/topic.go
@@ -177,13 +177,25 @@ func AddTopic(ctx *context.APIContext) {
return
}
- _, err = models.AddTopic(ctx.Repo.Repository.ID, topicName)
+ topic, err := models.AddTopic(ctx.Repo.Repository.ID, topicName)
if err != nil {
log.Error("AddTopic failed: %v", err)
ctx.InternalServerError(err)
return
}
-
+ found := false
+ topicNames := make([]string, len(topics))
+ for i, t := range topics {
+ topicNames[i] = t.Name
+ if strings.EqualFold(topic.Name, t.Name) {
+ found = true
+ break
+ }
+ }
+ if !found && topic.Name != "" {
+ topicNames = append(topicNames, topic.Name)
+ }
+ models.UpdateRepoTopics(ctx.Repo.Repository.ID, topicNames)
ctx.Status(http.StatusNoContent)
}
diff --git a/routers/home.go b/routers/home.go
index 092b30fe3..40a41bd68 100755
--- a/routers/home.go
+++ b/routers/home.go
@@ -7,6 +7,7 @@ package routers
import (
"bytes"
+ "code.gitea.io/gitea/routers/response"
"encoding/json"
"net/http"
"strconv"
@@ -43,6 +44,8 @@ const (
tplHomeTerm base.TplName = "terms"
tplHomePrivacy base.TplName = "privacy"
tplResoruceDesc base.TplName = "resource_desc"
+ tplRepoSquare base.TplName = "explore/repos/square"
+ tplRepoSearch base.TplName = "explore/repos/search"
)
// Home render home page
@@ -296,6 +299,109 @@ func ExploreRepos(ctx *context.Context) {
})
}
+func GetRepoSquarePage(ctx *context.Context) {
+ ctx.Data["SquareBanners"] = repository.GetBanners()
+ ctx.Data["SquareTopics"] = repository.GetTopics()
+ ctx.Data["SquareRecommendRepos"] = repository.GetRecommendRepos()
+
+ repos, _ := repository.GetPreferredRepos()
+ ctx.Data["SquarePreferredRepos"] = repos
+ ctx.HTML(200, tplRepoSquare)
+}
+func GetRepoSearchPage(ctx *context.Context) {
+ ctx.Data["SquareTopics"] = repository.GetTopics()
+ ctx.HTML(200, tplRepoSearch)
+}
+
+func RepoSquare(ctx *context.Context) {
+ var result []*models.Repository4Card
+ var err error
+ switch ctx.Query("type") {
+ case "preferred":
+ result, err = repository.GetPreferredRepos()
+ case "incubation":
+ result, err = repository.GetIncubationRepos()
+ case "hot-paper":
+ result, err = repository.GetHotPaperRepos()
+ default:
+ result, err = repository.GetPreferredRepos()
+ }
+ if err != nil {
+ ctx.JSON(http.StatusOK, response.ResponseError(err))
+ return
+ }
+ resultMap := make(map[string]interface{}, 0)
+ resultMap["Repos"] = result
+ ctx.JSON(http.StatusOK, response.SuccessWithData(resultMap))
+}
+
+func ActiveUser(ctx *context.Context) {
+ var err error
+ var currentUserId int64
+ if ctx.User != nil {
+ currentUserId = ctx.User.ID
+ }
+ result, err := repository.GetActiveUser4Square(currentUserId)
+ if err != nil {
+ log.Error("ActiveUser err. %v", err)
+ ctx.JSON(http.StatusOK, response.Success())
+ return
+ }
+ resultMap := make(map[string]interface{}, 0)
+ resultMap["Users"] = result
+ ctx.JSON(http.StatusOK, response.SuccessWithData(resultMap))
+}
+func ActiveOrg(ctx *context.Context) {
+ result, err := repository.GetActiveOrgs()
+ if err != nil {
+ log.Error("ActiveOrg err. %v", err)
+ ctx.JSON(http.StatusOK, response.Success())
+ return
+ }
+ resultMap := make(map[string]interface{}, 0)
+ resultMap["Orgs"] = result
+ ctx.JSON(http.StatusOK, response.SuccessWithData(resultMap))
+}
+
+func RepoFind(ctx *context.Context) {
+ keyword := strings.Trim(ctx.Query("q"), " ")
+ topic := strings.Trim(ctx.Query("topic"), " ")
+ sort := strings.Trim(ctx.Query("sort"), " ")
+ page := ctx.QueryInt("page")
+ pageSize := ctx.QueryInt("pageSize")
+ if pageSize == 0 {
+ pageSize = 15
+ }
+ if pageSize > 100 {
+ ctx.JSON(http.StatusOK, response.ServerError("pageSize illegal"))
+ return
+ }
+ if page <= 0 {
+ page = 1
+ }
+
+ var ownerID int64
+ if ctx.User != nil && !ctx.User.IsAdmin {
+ ownerID = ctx.User.ID
+ }
+
+ result, err := repository.FindRepos(repository.FindReposOptions{
+ ListOptions: models.ListOptions{Page: page, PageSize: pageSize},
+ Actor: ctx.User,
+ Sort: sort,
+ Keyword: keyword,
+ Topic: topic,
+ Private: ctx.User != nil,
+ OwnerID: ownerID,
+ })
+ if err != nil {
+ log.Error("RepoFind error. %v", err)
+ ctx.JSON(http.StatusOK, response.ResponseError(err))
+ return
+ }
+ ctx.JSON(http.StatusOK, response.SuccessWithData(result))
+}
+
func ExploreDatasets(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("explore")
ctx.Data["PageIsExplore"] = true
diff --git a/routers/private/internal.go b/routers/private/internal.go
index 14b0f05de..0b8ae600a 100755
--- a/routers/private/internal.go
+++ b/routers/private/internal.go
@@ -6,6 +6,7 @@
package private
import (
+ "code.gitea.io/gitea/services/repository"
"strings"
"code.gitea.io/gitea/routers/admin"
@@ -55,7 +56,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/task/history_handle/duration", repo.HandleTaskWithNoDuration)
m.Post("/task/history_handle/aicenter", repo.HandleTaskWithAiCenter)
m.Post("/resources/specification/handle_historical_task", admin.RefreshHistorySpec)
+ m.Post("/repos/cnt_stat/handle_historical_task", admin.RefreshHistorySpec)
m.Post("/duration_statisctic/history_handle", repo.CloudbrainUpdateHistoryData)
+ m.Post("/square/repo/stat/refresh", repository.RefreshRepoStatData)
}, CheckInternalToken)
}
diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go
index ecb9edd2d..d36ddab52 100644
--- a/routers/repo/ai_model_manage.go
+++ b/routers/repo/ai_model_manage.go
@@ -2,6 +2,7 @@ package repo
import (
"archive/zip"
+ "code.gitea.io/gitea/services/repository"
"encoding/json"
"errors"
"fmt"
@@ -170,10 +171,17 @@ func updateStatus(id string, modelSize int64, status int, modelPath string, stat
if len(statusDesc) > 400 {
statusDesc = statusDesc[0:400]
}
+ m, _ := models.QueryModelById(id)
err := models.ModifyModelStatus(id, modelSize, status, modelPath, statusDesc)
if err != nil {
log.Info("update status error." + err.Error())
}
+ if m != nil {
+ if modelSize > 0 && m.Size == 0 {
+ go repository.ResetRepoModelNum(m.RepoId)
+ }
+ }
+
}
func SaveNewNameModel(ctx *context.Context) {
@@ -308,13 +316,14 @@ func getSize(files []storage.FileInfo) int64 {
func UpdateModelSize(modeluuid string) {
model, err := models.QueryModelById(modeluuid)
if err == nil {
+ var size int64
if model.Type == models.TypeCloudBrainOne {
if strings.HasPrefix(model.Path, setting.Attachment.Minio.Bucket+"/"+Model_prefix) {
files, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, model.Path[len(setting.Attachment.Minio.Bucket)+1:])
if err != nil {
log.Info("Failed to query model size from minio. id=" + modeluuid)
}
- size := getSize(files)
+ size = getSize(files)
models.ModifyModelSize(modeluuid, size)
}
} else if model.Type == models.TypeCloudBrainTwo {
@@ -323,10 +332,13 @@ func UpdateModelSize(modeluuid string) {
if err != nil {
log.Info("Failed to query model size from obs. id=" + modeluuid)
}
- size := getSize(files)
+ size = getSize(files)
models.ModifyModelSize(modeluuid, size)
}
}
+ if model.Size == 0 && size > 0 {
+ go repository.ResetRepoModelNum(model.RepoId)
+ }
} else {
log.Info("not found model,uuid=" + modeluuid)
}
@@ -441,13 +453,14 @@ func DeleteModelFile(ctx *context.Context) {
fileName := ctx.Query("fileName")
model, err := models.QueryModelById(id)
if err == nil {
+ var totalSize int64
if model.ModelType == MODEL_LOCAL_TYPE {
if model.Type == models.TypeCloudBrainOne {
bucketName := setting.Attachment.Minio.Bucket
objectName := model.Path[len(bucketName)+1:] + fileName
log.Info("delete bucket=" + bucketName + " path=" + objectName)
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) {
- totalSize := storage.MinioGetFilesSize(bucketName, []string{objectName})
+ totalSize = storage.MinioGetFilesSize(bucketName, []string{objectName})
err := storage.Attachments.DeleteDir(objectName)
if err != nil {
log.Info("Failed to delete model. id=" + id)
@@ -467,7 +480,7 @@ func DeleteModelFile(ctx *context.Context) {
objectName := model.Path[len(setting.Bucket)+1:] + fileName
log.Info("delete bucket=" + setting.Bucket + " path=" + objectName)
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) {
- totalSize := storage.ObsGetFilesSize(bucketName, []string{objectName})
+ totalSize = storage.ObsGetFilesSize(bucketName, []string{objectName})
err := storage.ObsRemoveObject(bucketName, objectName)
if err != nil {
log.Info("Failed to delete model. id=" + id)
@@ -484,6 +497,9 @@ func DeleteModelFile(ctx *context.Context) {
}
}
}
+ if (model.Size - totalSize) <= 0 {
+ go repository.ResetRepoModelNum(model.RepoId)
+ }
}
ctx.JSON(200, map[string]string{
"code": "0",
@@ -552,6 +568,9 @@ func deleteModelByID(ctx *context.Context, id string) error {
}
}
}
+ if model.Size > 0 {
+ go repository.ResetRepoModelNum(model.RepoId)
+ }
}
}
return err
diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go
index 240e78acc..e1de71345 100755
--- a/routers/repo/attachment.go
+++ b/routers/repo/attachment.go
@@ -29,6 +29,7 @@ import (
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/upload"
"code.gitea.io/gitea/modules/worker"
+ repo_service "code.gitea.io/gitea/services/repository"
gouuid "github.com/satori/go.uuid"
)
@@ -180,6 +181,7 @@ func DeleteAttachment(ctx *context.Context) {
ctx.Error(500, fmt.Sprintf("DeleteAttachment: %v", err))
return
}
+ go repo_service.DecreaseRepoDatasetNum(attach.DatasetID)
attachjson, _ := json.Marshal(attach)
labelmsg.SendDeleteAttachToLabelSys(string(attachjson))
@@ -894,6 +896,7 @@ func CompleteMultipart(ctx *context.Context) {
return
}
attachment.UpdateDatasetUpdateUnix()
+ go repo_service.IncreaseRepoDatasetNum(dataset.ID)
repository, _ := models.GetRepositoryByID(dataset.RepoID)
notification.NotifyOtherTask(ctx.User, repository, fmt.Sprint(repository.IsPrivate, attachment.IsPrivate), attachment.Name, models.ActionUploadAttachment)
if attachment.DatasetID != 0 {
diff --git a/routers/repo/cloudbrain_statistic.go b/routers/repo/cloudbrain_statistic.go
index 6ff377491..de95babe9 100644
--- a/routers/repo/cloudbrain_statistic.go
+++ b/routers/repo/cloudbrain_statistic.go
@@ -14,7 +14,13 @@ import (
)
func CloudbrainDurationStatisticHour() {
- if setting.IsCloudbrainTimingEnabled {
+ defer func() {
+ err := recover()
+ if err == nil {
+ return
+ }
+ }()
+ if setting.IsCloudbrainTimingEnabled {
var statisticTime time.Time
var count int64
recordDurationUpdateTime, err := models.GetDurationRecordUpdateTime()
diff --git a/routers/repo/repo_statistic.go b/routers/repo/repo_statistic.go
index 468e6fa85..c1a7954a7 100755
--- a/routers/repo/repo_statistic.go
+++ b/routers/repo/repo_statistic.go
@@ -166,6 +166,8 @@ func RepoStatisticDaily(date string) {
repoStat.NumIssuesGrowth = repoStat.NumIssues - repoStatisticFourMonthsAgo.NumIssues
}
+ models.SyncStatDataToRepo(repo)
+
if _, err = models.InsertRepoStat(&repoStat); err != nil {
log.Error("InsertRepoStat failed(%s): %v", projectName, err)
log.Error("failed statistic: %s", projectName)
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 546854ef1..063a20999 100755
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -371,7 +371,18 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/images/custom", repo.GetCustomImages)
m.Get("/images/star", repo.GetStarImages)
- m.Get("/repos", routers.ExploreRepos)
+ m.Group("/repos", func() {
+ //m.Get("", routers.ExploreRepos)
+ m.Get("", routers.GetRepoSearchPage)
+ m.Group("/square", func() {
+ m.Get("", routers.GetRepoSquarePage)
+ m.Get("/tab", routers.RepoSquare)
+ m.Get("/active-user", routers.ActiveUser)
+ m.Get("/active-org", routers.ActiveOrg)
+ })
+
+ m.Get("/search", routers.RepoFind)
+ })
m.Get("/datasets", routers.ExploreDatasets)
m.Get("/users", routers.ExploreUsers)
m.Get("/organizations", routers.ExploreOrganizations)
diff --git a/services/repository/contributor.go b/services/repository/contributor.go
new file mode 100644
index 000000000..9a86b91dc
--- /dev/null
+++ b/services/repository/contributor.go
@@ -0,0 +1,88 @@
+package repository
+
+import (
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/redis/redis_client"
+ "code.gitea.io/gitea/modules/redis/redis_key"
+ "encoding/json"
+ "github.com/patrickmn/go-cache"
+ "time"
+)
+
+var repoContributorCache = cache.New(5*time.Minute, 1*time.Minute)
+
+type ContributorCacheVal struct {
+ Contributors []*models.ContributorInfo
+ Total int
+}
+
+func GetRepoTopNContributors(repo *models.Repository, N int) ([]*models.ContributorInfo, int) {
+ val, _ := redis_client.Get(redis_key.RepoTopNContributors(repo.ID, N))
+ if val != "" {
+ log.Debug("Get RepoTopNContributors from redis,repo.ID = %d value = %v", repo.ID, val)
+ temp := &ContributorCacheVal{}
+ json.Unmarshal([]byte(val), temp)
+ return temp.Contributors, temp.Total
+ }
+
+ contributorInfos, total := getRepoTopNContributorsFromDisk(repo, N)
+ log.Debug("Get RepoTopNContributors from disk,repo.ID = %d ", repo.ID)
+ jsonVal, err := json.Marshal(&ContributorCacheVal{Contributors: contributorInfos, Total: total})
+ if err == nil {
+ redis_client.Setex(redis_key.RepoTopNContributors(repo.ID, N), string(jsonVal), 2*time.Minute)
+ }
+ return contributorInfos, total
+}
+
+func getRepoTopNContributorsFromDisk(repo *models.Repository, N int) ([]*models.ContributorInfo, int) {
+ contributorInfos := make([]*models.ContributorInfo, 0)
+
+ branchName := GetDefaultBranchName(repo)
+ if branchName == "" {
+ return contributorInfos, 0
+ }
+
+ contributors, err := git.GetContributors(repo.RepoPath(), branchName)
+ if err == nil && contributors != nil {
+ contributorInfoHash := make(map[string]*models.ContributorInfo)
+ for _, c := range contributors {
+ if len(contributorInfos) >= N {
+ break
+ }
+ if c.Email == "" {
+ 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 = &models.ContributorInfo{
+ user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt,
+ }
+ 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 = &models.ContributorInfo{
+ "", "", c.Email, c.CommitCnt,
+ }
+ contributorInfos = append(contributorInfos, newContributor)
+ contributorInfoHash[c.Email] = newContributor
+ }
+ }
+ }
+ }
+ return contributorInfos, len(contributors)
+}
diff --git a/services/repository/repository.go b/services/repository/repository.go
index db25010ea..a5c7c2fc4 100644
--- a/services/repository/repository.go
+++ b/services/repository/repository.go
@@ -5,18 +5,19 @@
package repository
import (
- "fmt"
- "io/ioutil"
- "net/http"
- "os"
- "strings"
-
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
pull_service "code.gitea.io/gitea/services/pull"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "strings"
+ "xorm.io/xorm"
)
const SHELL_FLAG_ON = 1
@@ -328,3 +329,47 @@ func IsUploadFileInvalidErr(err error) bool {
_, ok := err.(UploadFileInvalidErr)
return ok
}
+
+func IncreaseRepoDatasetNum(datasetID int64, engines ...*xorm.Engine) error {
+ dataset, err := models.GetDatasetByID(datasetID)
+ if err != nil {
+ return err
+ }
+ return models.OperateRepoDatasetNum(dataset.RepoID, 1, engines...)
+}
+
+func IncreaseRepoModelNum(repoId int64, engines ...*xorm.Engine) error {
+ return models.OperateRepoModelNum(repoId, 1, engines...)
+}
+
+func ResetRepoModelNum(repoId int64) error {
+ return models.ResetRepoModelNum(repoId)
+}
+
+func DecreaseRepoDatasetNum(datasetID int64, engines ...*xorm.Engine) error {
+ dataset, err := models.GetDatasetByID(datasetID)
+ if err != nil {
+ return err
+ }
+ return models.OperateRepoDatasetNum(dataset.RepoID, -1, engines...)
+}
+
+func DecreaseRepoModelNum(repoId int64, engines ...*xorm.Engine) error {
+ return models.OperateRepoModelNum(repoId, -1, engines...)
+}
+
+func GetDefaultBranchName(repo *models.Repository) string {
+ gitRepo, err := git.OpenRepository(repo.RepoPath())
+ if err != nil {
+ return ""
+ }
+ defer gitRepo.Close()
+ if len(repo.DefaultBranch) > 0 && gitRepo.IsBranchExist(repo.DefaultBranch) {
+ return repo.DefaultBranch
+ }
+ brs, _, err := gitRepo.GetBranches(0, 0)
+ if len(brs) > 0 {
+ return brs[0]
+ }
+ return ""
+}
diff --git a/services/repository/square.go b/services/repository/square.go
new file mode 100644
index 000000000..d68e5b189
--- /dev/null
+++ b/services/repository/square.go
@@ -0,0 +1,315 @@
+package repository
+
+import (
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "encoding/json"
+ "github.com/patrickmn/go-cache"
+ "time"
+)
+
+var repoSquareCache = cache.New(2*time.Minute, 1*time.Minute)
+
+const (
+ RREFERED_CACHE = "PreferredRepos"
+ REPO_BANNER_CACHE = "RepoBanner"
+ TOPICS_CACHE = "RepoTopics"
+ RECOMMEND_CACHE = "RecommendRepos"
+)
+
+func GetBanners() []map[string]string {
+ v, success := repoSquareCache.Get(REPO_BANNER_CACHE)
+ if success {
+ log.Debug("GetBanners from cache,value = %v", v)
+ if v == nil {
+ return nil
+ }
+ r := v.([]map[string]string)
+ return r
+ }
+ repoMap := getMapContent("repos/square_banner")
+ repoSquareCache.Set(REPO_BANNER_CACHE, repoMap, 1*time.Minute)
+ return repoMap
+}
+
+func GetTopics() []string {
+ v, success := repoSquareCache.Get(TOPICS_CACHE)
+ if success {
+ log.Debug("GetTopics from cache,value = %v", v)
+ if v == nil {
+ return nil
+ }
+ r := v.([]string)
+ return r
+ }
+ topics := getArrayContent("repos/recommend_topics")
+ repoSquareCache.Set(TOPICS_CACHE, topics, 1*time.Minute)
+ return topics
+}
+
+func getMapContent(fileName string) []map[string]string {
+ url := setting.RecommentRepoAddr + fileName
+ result, err := RecommendContentFromPromote(url)
+ remap := make([]map[string]string, 0)
+ if err == nil {
+ json.Unmarshal([]byte(result), &remap)
+ }
+ return remap
+}
+
+func getArrayContent(fileName string) []string {
+ url := setting.RecommentRepoAddr + fileName
+ result, err := RecommendContentFromPromote(url)
+ r := make([]string, 0)
+ if err == nil {
+ json.Unmarshal([]byte(result), &r)
+ }
+ return r
+}
+
+func GetRecommendRepos() []map[string]interface{} {
+ v, success := repoSquareCache.Get(RECOMMEND_CACHE)
+ if success {
+ log.Debug("GetRecommendRepos from cache,value = %v", v)
+ if v == nil {
+ return nil
+ }
+ r := v.([]map[string]interface{})
+ return r
+ }
+ repoMap := getMapContent("home/projects")
+ r, _ := GetRecommendRepoFromPromote(repoMap)
+ repoSquareCache.Set(RECOMMEND_CACHE, r, 1*time.Minute)
+ return r
+}
+
+func GetPreferredRepos() ([]*models.Repository4Card, error) {
+ v, success := repoSquareCache.Get(RREFERED_CACHE)
+ if success {
+ log.Debug("GetPreferredRepos from cache,value = %v", v)
+ if v == nil {
+ return nil, nil
+ }
+ r := v.([]*models.Repository4Card)
+ return r, nil
+ }
+
+ repos, err := models.GetSelectedRepos(models.FindSelectedReposOpts{
+ ListOptions: models.ListOptions{
+ PageSize: 10,
+ Page: 1,
+ },
+ OnlyPublic: true,
+ })
+ if err != nil {
+ return nil, err
+ }
+ result := make([]*models.Repository4Card, len(repos))
+ for i, r := range repos {
+ result[i] = r.ToCardFormat()
+ }
+
+ repoSquareCache.Set(RREFERED_CACHE, result, 1*time.Minute)
+ return result, nil
+}
+
+func GetIncubationRepos() ([]*models.Repository4Card, error) {
+ org, err := models.GetOrgByName(setting.IncubationSourceOrgName)
+ if models.IsErrOrgNotExist(err) {
+ return make([]*models.Repository4Card, 0), nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ repos, err := models.GetSelectedRepos(models.FindSelectedReposOpts{
+ ListOptions: models.ListOptions{
+ PageSize: 10,
+ Page: 1,
+ },
+ OrgId: org.ID,
+ OnlyPublic: true,
+ })
+ if err != nil {
+ return nil, err
+ }
+ result := make([]*models.Repository4Card, len(repos))
+ for i, r := range repos {
+ result[i] = r.ToCardFormat()
+ }
+ return result, nil
+}
+
+func GetHotPaperRepos() ([]*models.Repository4Card, error) {
+ rlist, _, err := models.SearchRepository(&models.SearchRepoOptions{
+ ListOptions: models.ListOptions{
+ Page: 1,
+ PageSize: 10,
+ },
+ OrderBy: models.SearchOrderByLastMonthVisitsReverse + "," + models.SearchOrderByRecentUpdated,
+ TopicOnly: true,
+ TopicName: setting.PaperRepoTopicName,
+ AllPublic: true,
+ })
+ if err != nil {
+ return nil, err
+ }
+ result := make([]*models.Repository4Card, len(rlist))
+ for i, r := range rlist {
+ result[i] = r.ToCardFormat()
+ }
+ return result, nil
+}
+
+type FindReposOptions struct {
+ models.ListOptions
+ Actor *models.User
+ Sort string
+ Keyword string
+ Topic string
+ Private bool
+ OwnerID int64
+}
+
+func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) {
+
+ var (
+ repos []*models.Repository
+ count int64
+ err error
+ orderBy models.SearchOrderBy
+ )
+
+ switch opts.Sort {
+ //1.近期热门:按最近1个月浏览量倒序排序,最近1个月浏览量>最近更新>项目名称升序
+ case "mostpopular":
+ orderBy = models.SearchOrderByLastMonthVisitsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //2.近期活跃:按提交增长量(最近4个月commit数)倒序排序,提交增长量>最近更新>项目名称升序。
+ case "mostactive":
+ orderBy = models.SearchOrderByLastFourMonthCommitsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //3.最近更新:按最近更新>项目名称升序排序。
+ case "recentupdate":
+ orderBy = models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //4.最近创建:按项目创建时间排序,最近的排前面。最近创建>项目名称升序。
+ case "newest":
+ orderBy = models.SearchOrderByNewest + "," + models.SearchOrderByAlphabetically
+ //5.点赞最多:按点赞数倒序排序。点赞数>最近更新>项目名称升序。
+ case "moststars":
+ orderBy = models.SearchOrderByStarsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //6.派生最多:按派生数倒序排序。派生数>最近更新>项目名称升序。
+ case "mostforks":
+ orderBy = models.SearchOrderByForksReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //7.数据集最多:按项目包含的数据集文件数量倒序排序,数据集文件数>最近更新>项目名称升序。
+ case "mostdatasets":
+ orderBy = models.SearchOrderByDatasetCntReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //8.AI任务最多:按项目包含的AI任务数量倒序排序,AI任务数>最近更新>项目名称升序。
+ case "mostaitasks":
+ orderBy = models.SearchOrderByAiTaskCntReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ //9.模型最多:按项目包含的模型数量倒序排序,模型大小为0则不统计。模型数>最近更新>项目名称升序。
+ case "mostmodels":
+ orderBy = models.SearchOrderByModelCntReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+
+ default:
+ orderBy = models.SearchOrderByLastMonthVisitsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically
+ }
+
+ repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
+ ListOptions: opts.ListOptions,
+ Actor: opts.Actor,
+ OrderBy: orderBy,
+ Private: opts.Private,
+ Keyword: opts.Keyword,
+ OwnerID: opts.OwnerID,
+ AllPublic: true,
+ AllLimited: true,
+ TopicName: opts.Topic,
+ IncludeDescription: setting.UI.SearchRepoDescription,
+ })
+ if err != nil {
+ log.Error("FindRepos error when SearchRepository.%v", err)
+ return nil, err
+ }
+ result := make([]*models.Repository4Card, len(repos))
+ for i, r := range repos {
+ t := r.ToCardFormat()
+ contributors, _ := GetRepoTopNContributors(r, 6)
+ t.Contributors = contributors
+ result[i] = t
+ }
+
+ return &models.FindReposResponse{
+ Repos: result,
+ Total: count,
+ Page: opts.Page,
+ PageSize: opts.PageSize,
+ }, nil
+}
+
+type ActiveUser struct {
+ User *models.User4Front
+ Followed bool
+ ShowButton bool
+}
+
+func GetActiveUser4Square(currentUserId int64) ([]*ActiveUser, error) {
+ result := make([]*ActiveUser, 0)
+ userIds, err := models.QueryLast30DaysHighestIndexUsers(5)
+ if err != nil {
+ log.Error("ActiveUser err. %v", err)
+ return result, err
+ }
+ if len(userIds) == 0 {
+ return result, nil
+ }
+
+ users, err := models.GetUsersByIDs(userIds)
+ if err != nil {
+ return result, nil
+ }
+ usersMap := make(map[int64]*models.User)
+ for _, v := range users {
+ usersMap[v.ID] = v
+ }
+
+ for i := 0; i < len(userIds); i++ {
+ userId := userIds[i]
+ user := usersMap[userId]
+ if user == nil {
+ continue
+ }
+ isFollowed := false
+ if currentUserId != 0 {
+ isFollowed = models.IsFollowing(currentUserId, userId)
+ }
+ a := &ActiveUser{
+ Followed: isFollowed,
+ User: user.ToFrontFormat(),
+ ShowButton: currentUserId != userId,
+ }
+ result = append(result, a)
+ }
+ return result, nil
+}
+
+func GetActiveOrgs() ([]*models.User4Front, error) {
+ orgScores, err := models.FindTopNOpenIOrgs(5)
+ if err != nil {
+ return nil, err
+ }
+ orgs := make([]*models.User4Front, len(orgScores))
+ for i, v := range orgScores {
+ orgs[i] = v.ToFrontFormat()
+ }
+ return orgs, nil
+}
+
+func RefreshRepoStatData() {
+ repos, err := models.GetAllRepositories()
+ if err != nil {
+ log.Error("RefreshRepoStatData GetAllRepositories failed: %v", err.Error())
+ return
+ }
+ for _, repo := range repos {
+ models.SyncStatDataToRepo(repo)
+ }
+}
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl
index 5fb9c09d3..de55e6452 100755
--- a/templates/base/head_navbar.tmpl
+++ b/templates/base/head_navbar.tmpl
@@ -35,7 +35,7 @@
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -48,7 +48,7 @@
{{.i18n.Tr "explore"}}
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -89,7 +89,7 @@
{{.i18n.Tr "explore"}}
{{else if .IsLandingPageExplore}}
- {{.i18n.Tr "home"}}
+ {{.i18n.Tr "home"}}
{{else if .IsLandingPageOrganizations}}
{{.i18n.Tr "home"}}
{{end}}
diff --git a/templates/base/head_navbar_fluid.tmpl b/templates/base/head_navbar_fluid.tmpl
index 63291d6fb..8a4682e9d 100644
--- a/templates/base/head_navbar_fluid.tmpl
+++ b/templates/base/head_navbar_fluid.tmpl
@@ -32,7 +32,7 @@
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -45,7 +45,7 @@
{{.i18n.Tr "explore"}}
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -84,7 +84,7 @@
{{.i18n.Tr "explore"}}
{{else if .IsLandingPageExplore}}
- {{.i18n.Tr "home"}}
+ {{.i18n.Tr "home"}}
{{else if .IsLandingPageOrganizations}}
{{.i18n.Tr "home"}}
{{end}}
diff --git a/templates/base/head_navbar_home.tmpl b/templates/base/head_navbar_home.tmpl
index 334ef5a33..f6741b7c8 100644
--- a/templates/base/head_navbar_home.tmpl
+++ b/templates/base/head_navbar_home.tmpl
@@ -24,7 +24,7 @@
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -37,7 +37,7 @@
{{.i18n.Tr "explore"}}
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -77,7 +77,7 @@
{{.i18n.Tr "explore"}}
{{else if .IsLandingPageExplore}}
- {{.i18n.Tr "home"}}
+ {{.i18n.Tr "home"}}
{{else if .IsLandingPageOrganizations}}
{{.i18n.Tr "home"}}
{{end}}
diff --git a/templates/base/head_navbar_pro.tmpl b/templates/base/head_navbar_pro.tmpl
index 55a090128..9e1c1ebf7 100644
--- a/templates/base/head_navbar_pro.tmpl
+++ b/templates/base/head_navbar_pro.tmpl
@@ -34,7 +34,7 @@
- {{.i18n.Tr "custom.head.project"}}
+ {{.i18n.Tr "custom.head.project"}}
{{.i18n.Tr "custom.head.dataset"}}
{{.i18n.Tr "repo.model_manager"}}
@@ -47,7 +47,7 @@
{{.i18n.Tr "explore"}}
{{else if .IsLandingPageExplore}}
-
{{.i18n.Tr "home"}}
+
{{.i18n.Tr "home"}}
{{else if .IsLandingPageOrganizations}}
{{.i18n.Tr "home"}}
{{end}}
diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl
index c8c81defb..3bc907458 100644
--- a/templates/explore/navbar.tmpl
+++ b/templates/explore/navbar.tmpl
@@ -1,6 +1,6 @@