| @@ -137,6 +137,7 @@ func init() { | |||||
| new(OfficialTag), | new(OfficialTag), | ||||
| new(OfficialTagRepos), | new(OfficialTagRepos), | ||||
| new(WechatBindLog), | new(WechatBindLog), | ||||
| new(OrgStatistic), | |||||
| ) | ) | ||||
| tablesStatistic = append(tablesStatistic, | tablesStatistic = append(tablesStatistic, | ||||
| @@ -8,6 +8,7 @@ package models | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "os" | "os" | ||||
| "strconv" | |||||
| "strings" | "strings" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| @@ -19,6 +20,17 @@ import ( | |||||
| "xorm.io/xorm" | "xorm.io/xorm" | ||||
| ) | ) | ||||
| type OrgStatistic struct { | |||||
| ID int64 `xorm:"pk autoincr"` | |||||
| OrgID int64 `xorm:"UNIQUE"` | |||||
| NumScore int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||||
| } | |||||
| type OrgScore struct { | |||||
| *User | |||||
| Score string | |||||
| } | |||||
| // IsOwnedBy returns true if given user is in the owner team. | // IsOwnedBy returns true if given user is in the owner team. | ||||
| func (org *User) IsOwnedBy(uid int64) (bool, error) { | func (org *User) IsOwnedBy(uid int64) (bool, error) { | ||||
| return IsOrganizationOwner(org.ID, uid) | return IsOrganizationOwner(org.ID, uid) | ||||
| @@ -135,6 +147,93 @@ func (org *User) RemoveOrgRepo(repoID int64) error { | |||||
| return org.removeOrgRepo(x, repoID) | return org.removeOrgRepo(x, repoID) | ||||
| } | } | ||||
| func UpdateOrgStatistics() { | |||||
| ids, err := GetOrganizationsId() | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| for _, id := range ids { | |||||
| org := User{ID: id} | |||||
| orgStat := &OrgStatistic{OrgID: id} | |||||
| numScore, err := org.getOrgStatistics() | |||||
| if err == nil { | |||||
| has, _ := x.Get(orgStat) | |||||
| orgStat.NumScore = numScore | |||||
| if has { | |||||
| x.ID(orgStat.ID).Cols("num_score").Update(&orgStat) | |||||
| } else { | |||||
| x.Insert(orgStat) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| func (org *User) getOrgStatistics() (int, error) { | |||||
| count, err := getRepositoryCount(x, org) | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| err = org.GetRepositories(ListOptions{int(count), 1}) | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| var numScore = 0 | |||||
| for _, repo := range org.Repos { | |||||
| numScore += int(getOpenIByRepoId(repo.ID)) | |||||
| } | |||||
| return numScore, nil | |||||
| } | |||||
| func FindTopNStarsOrgs(n int) ([]*OrgScore, error) { | |||||
| sql := "select a.id,sum(b.num_stars) score from \"user\" a ,repository b where a.id=b.owner_id and a.type=1 group by a.id order by score desc limit " + strconv.Itoa(n) | |||||
| return findTopNOrgs(sql) | |||||
| } | |||||
| func FindTopNMembersOrgs(n int) ([]*OrgScore, error) { | |||||
| sql := "select id, count(user_id) score from" + | |||||
| " (select org_id as id, uid as user_id from org_user " + | |||||
| "union select a.id,b.user_id from \"user\" a,collaboration b,repository c " + | |||||
| "where a.type=1 and a.id=c.owner_id and b.repo_id=c.id) d " + | |||||
| "group by id order by score desc limit " + strconv.Itoa(n) | |||||
| return findTopNOrgs(sql) | |||||
| } | |||||
| func FindTopNOpenIOrgs(n int) ([]*OrgScore, error) { | |||||
| sql := "select org_id id,num_score score from org_statistic order by num_score desc limit 10" + strconv.Itoa(n) | |||||
| return findTopNOrgs(sql) | |||||
| } | |||||
| func findTopNOrgs(sql string) ([]*OrgScore, error) { | |||||
| resutls, err := x.QueryString(sql) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| var orgScore []*OrgScore | |||||
| for _, record := range resutls { | |||||
| id, _ := strconv.ParseInt(record["id"], 10, 64) | |||||
| user, err := getUserByID(x, id) | |||||
| if err != nil { | |||||
| continue | |||||
| } | |||||
| orgScore = append(orgScore, &OrgScore{user, record["score"]}) | |||||
| } | |||||
| return orgScore, nil | |||||
| } | |||||
| // CreateOrganization creates record of a new organization. | // CreateOrganization creates record of a new organization. | ||||
| func CreateOrganization(org, owner *User) (err error) { | func CreateOrganization(org, owner *User) (err error) { | ||||
| if !owner.CanCreateOrganization() { | if !owner.CanCreateOrganization() { | ||||
| @@ -73,6 +73,16 @@ func (repo *RepoStatistic) DisplayName() string { | |||||
| return repo.Alias | return repo.Alias | ||||
| } | } | ||||
| func getOpenIByRepoId(repoId int64) float64 { | |||||
| repoStatistic := new(RepoStatistic) | |||||
| has, err := xStatistic.Cols("radar_total").Where("repo_id=?", repoId).Desc("id").Limit(1).Get(repoStatistic) | |||||
| if !has || err != nil { | |||||
| return 0 | |||||
| } | |||||
| return repoStatistic.RadarTotal | |||||
| } | |||||
| func DeleteRepoStatDaily(date string) error { | func DeleteRepoStatDaily(date string) error { | ||||
| sess := xStatistic.NewSession() | sess := xStatistic.NewSession() | ||||
| defer sess.Close() | defer sess.Close() | ||||
| @@ -185,6 +185,17 @@ func registerHandleSummaryStatistic() { | |||||
| }) | }) | ||||
| } | } | ||||
| func registerHandleOrgStatistic() { | |||||
| RegisterTaskFatal("handle_org_statistic", &BaseConfig{ | |||||
| Enabled: true, | |||||
| RunAtStart: false, | |||||
| Schedule: "0 0 2 * * ?", | |||||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | |||||
| models.UpdateOrgStatistics() | |||||
| return nil | |||||
| }) | |||||
| } | |||||
| func registerSyncCloudbrainStatus() { | func registerSyncCloudbrainStatus() { | ||||
| RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{ | RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{ | ||||
| Enabled: true, | Enabled: true, | ||||
| @@ -215,4 +226,5 @@ func initBasicTasks() { | |||||
| registerHandleSummaryStatistic() | registerHandleSummaryStatistic() | ||||
| registerSyncCloudbrainStatus() | registerSyncCloudbrainStatus() | ||||
| registerHandleOrgStatistic() | |||||
| } | } | ||||
| @@ -418,17 +418,38 @@ func ExploreOrganizations(ctx *context.Context) { | |||||
| ctx.Data["PageIsExploreOrganizations"] = true | ctx.Data["PageIsExploreOrganizations"] = true | ||||
| ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled | ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled | ||||
| visibleTypes := []structs.VisibleType{structs.VisibleTypePublic} | |||||
| if ctx.User != nil { | |||||
| visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate) | |||||
| N := 10 | |||||
| starInfo, err := models.FindTopNStarsOrgs(N) | |||||
| if err != nil { | |||||
| log.Error("GetStarOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"]) | |||||
| ctx.ServerError("GetStarOrgInfos", err) | |||||
| return | |||||
| } | |||||
| memberInfo, err := models.FindTopNMembersOrgs(N) | |||||
| if err != nil { | |||||
| log.Error("GetMemberOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"]) | |||||
| ctx.ServerError("GetMemberOrgInfos", err) | |||||
| return | |||||
| } | |||||
| openIInfo, err := models.FindTopNOpenIOrgs(N) | |||||
| if err != nil { | |||||
| log.Error("GetOpenIOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"]) | |||||
| ctx.ServerError("GetOpenIOrgInfos", err) | |||||
| return | |||||
| } | } | ||||
| RenderUserSearch(ctx, &models.SearchUserOptions{ | |||||
| Actor: ctx.User, | |||||
| Type: models.UserTypeOrganization, | |||||
| ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum}, | |||||
| Visible: visibleTypes, | |||||
| }, tplExploreOrganizations) | |||||
| recommendOrgs, err := models.GetRecommendOrgInfos() | |||||
| if err != nil { | |||||
| log.Error("GetRecommendOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"]) | |||||
| ctx.ServerError("GetRecommendOrgInfos", err) | |||||
| return | |||||
| } | |||||
| ctx.Data["RecommendOrgs"] = recommendOrgs | |||||
| ctx.Data["StarOrgs"] = starInfo | |||||
| ctx.Data["MemberOrgs"] = memberInfo | |||||
| ctx.Data["ActiveOrgs"] = openIInfo | |||||
| ctx.HTML(http.StatusOK, tplExploreOrganizations) | |||||
| } | } | ||||
| // ExploreCode render explore code page | // ExploreCode render explore code page | ||||
| @@ -44,6 +44,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues) | m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues) | ||||
| m.Post("/tool/update_all_repo_commit_cnt", UpdateAllRepoCommitCnt) | m.Post("/tool/update_all_repo_commit_cnt", UpdateAllRepoCommitCnt) | ||||
| m.Post("/tool/repo_stat/:date", RepoStatisticManually) | m.Post("/tool/repo_stat/:date", RepoStatisticManually) | ||||
| m.Get("/tool/org_stat", OrgStatisticManually) | |||||
| m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit) | m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit) | ||||
| }, CheckInternalToken) | }, CheckInternalToken) | ||||
| @@ -45,6 +45,10 @@ func RepoStatisticManually(ctx *macaron.Context) { | |||||
| repo.TimingCountDataByDate(date) | repo.TimingCountDataByDate(date) | ||||
| } | } | ||||
| func OrgStatisticManually() { | |||||
| models.UpdateOrgStatistics() | |||||
| } | |||||
| func UpdateRepoVisit(ctx *macaron.Context) { | func UpdateRepoVisit(ctx *macaron.Context) { | ||||
| date := ctx.Params("date") | date := ctx.Params("date") | ||||
| log.Info("date(%s)", date) | log.Info("date(%s)", date) | ||||