| @@ -137,6 +137,7 @@ func init() { | |||
| new(OfficialTag), | |||
| new(OfficialTagRepos), | |||
| new(WechatBindLog), | |||
| new(OrgStatistic), | |||
| ) | |||
| tablesStatistic = append(tablesStatistic, | |||
| @@ -8,6 +8,7 @@ package models | |||
| import ( | |||
| "fmt" | |||
| "os" | |||
| "strconv" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/log" | |||
| @@ -19,6 +20,17 @@ import ( | |||
| "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. | |||
| func (org *User) IsOwnedBy(uid int64) (bool, error) { | |||
| return IsOrganizationOwner(org.ID, uid) | |||
| @@ -135,6 +147,93 @@ func (org *User) RemoveOrgRepo(repoID int64) error { | |||
| 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. | |||
| func CreateOrganization(org, owner *User) (err error) { | |||
| if !owner.CanCreateOrganization() { | |||
| @@ -73,6 +73,16 @@ func (repo *RepoStatistic) DisplayName() string { | |||
| 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 { | |||
| sess := xStatistic.NewSession() | |||
| 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() { | |||
| RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{ | |||
| Enabled: true, | |||
| @@ -215,4 +226,5 @@ func initBasicTasks() { | |||
| registerHandleSummaryStatistic() | |||
| registerSyncCloudbrainStatus() | |||
| registerHandleOrgStatistic() | |||
| } | |||
| @@ -418,17 +418,38 @@ func ExploreOrganizations(ctx *context.Context) { | |||
| ctx.Data["PageIsExploreOrganizations"] = true | |||
| 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 | |||
| @@ -44,6 +44,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues) | |||
| m.Post("/tool/update_all_repo_commit_cnt", UpdateAllRepoCommitCnt) | |||
| m.Post("/tool/repo_stat/:date", RepoStatisticManually) | |||
| m.Get("/tool/org_stat", OrgStatisticManually) | |||
| m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit) | |||
| }, CheckInternalToken) | |||
| @@ -45,6 +45,10 @@ func RepoStatisticManually(ctx *macaron.Context) { | |||
| repo.TimingCountDataByDate(date) | |||
| } | |||
| func OrgStatisticManually() { | |||
| models.UpdateOrgStatistics() | |||
| } | |||
| func UpdateRepoVisit(ctx *macaron.Context) { | |||
| date := ctx.Params("date") | |||
| log.Info("date(%s)", date) | |||