@@ -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) | ||||