forked from Gitlink/gitea_hat
新增:用户提交次数分布api(按时间)
This commit is contained in:
parent
2f56447e7a
commit
b18906605a
|
|
@ -1,27 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
)
|
||||
|
||||
type Contributor struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Contributions int64 `json:"contributions"`
|
||||
}
|
||||
|
||||
func GetContributors(repoID, userID int64) (result []Contributor, err error) {
|
||||
sql :=
|
||||
`select a.act_user_id as id ,
|
||||
u.name as login,
|
||||
u.email as email,
|
||||
count(act_user_id) as contributions
|
||||
from action a
|
||||
left join user u on a.act_user_id=u.id
|
||||
where repo_id=? and user_id=?
|
||||
group by repo_id,act_user_id `
|
||||
|
||||
err = db.GetEngine(db.DefaultContext).SQL(sql, repoID, userID).Find(&result)
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package activities
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gitea_activities_models "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
gitea_repo_model "code.gitea.io/gitea/models/repo"
|
||||
gitea_user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type Contributor struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Contributions int64 `json:"contributions"`
|
||||
}
|
||||
|
||||
func GetContributors(repoID, userID int64) (result []Contributor, err error) {
|
||||
sql :=
|
||||
`select a.act_user_id as id ,
|
||||
u.name as login,
|
||||
u.email as email,
|
||||
count(act_user_id) as contributions
|
||||
from action a
|
||||
left join user u on a.act_user_id=u.id
|
||||
where repo_id=? and user_id=?
|
||||
group by repo_id,act_user_id `
|
||||
|
||||
err = db.GetEngine(db.DefaultContext).SQL(sql, repoID, userID).Find(&result)
|
||||
return
|
||||
}
|
||||
|
||||
func activityQueryCondition(opts gitea_activities_models.GetFeedsOptions) (builder.Cond, error) {
|
||||
cond := builder.NewCond()
|
||||
|
||||
if opts.RequestedTeam != nil && opts.RequestedUser == nil {
|
||||
org, err := gitea_user_model.GetUserByID(opts.RequestedTeam.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.RequestedUser = org
|
||||
}
|
||||
|
||||
// check activity visibility for actor ( similar to activityReadable() )
|
||||
if opts.Actor == nil {
|
||||
cond = cond.And(builder.In("act_user_id",
|
||||
builder.Select("`user`.id").Where(
|
||||
builder.Eq{"keep_activity_private": false, "visibility": structs.VisibleTypePublic},
|
||||
).From("`user`"),
|
||||
))
|
||||
} else if !opts.Actor.IsAdmin {
|
||||
cond = cond.And(builder.In("act_user_id",
|
||||
builder.Select("`user`.id").Where(
|
||||
builder.Eq{"keep_activity_private": false}.
|
||||
And(builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))).
|
||||
Or(builder.Eq{"id": opts.Actor.ID}).From("`user`"),
|
||||
))
|
||||
}
|
||||
|
||||
// check readable repositories by doer/actor
|
||||
if opts.Actor == nil || !opts.Actor.IsAdmin {
|
||||
cond = cond.And(builder.In("repo_id", gitea_repo_model.AccessibleRepoIDsQuery(opts.Actor)))
|
||||
}
|
||||
|
||||
if opts.RequestedRepo != nil {
|
||||
cond = cond.And(builder.Eq{"repo_id": opts.RequestedRepo.ID})
|
||||
}
|
||||
|
||||
if opts.RequestedTeam != nil {
|
||||
env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(opts.RequestedTeam)
|
||||
teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetTeamRepositories: %w", err)
|
||||
}
|
||||
cond = cond.And(builder.In("repo_id", teamRepoIDs))
|
||||
}
|
||||
|
||||
if opts.RequestedUser != nil {
|
||||
cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})
|
||||
|
||||
if opts.OnlyPerformedBy {
|
||||
cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID})
|
||||
}
|
||||
}
|
||||
|
||||
if !opts.IncludePrivate {
|
||||
cond = cond.And(builder.Eq{"`action`.is_private": false})
|
||||
}
|
||||
if !opts.IncludeDeleted {
|
||||
cond = cond.And(builder.Eq{"is_deleted": false})
|
||||
}
|
||||
|
||||
if opts.Date != "" {
|
||||
dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
|
||||
if err != nil {
|
||||
log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
|
||||
} else {
|
||||
dateHigh := dateLow.Add(86399000000000) // 23h59m59s
|
||||
|
||||
cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()})
|
||||
cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()})
|
||||
}
|
||||
}
|
||||
|
||||
return cond, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package activities
|
||||
|
||||
import (
|
||||
gitea_activities_models "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
gitea_user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
)
|
||||
|
||||
type UserHeatmapData struct {
|
||||
Timestamp timeutil.TimeStamp `json:"timestamp"`
|
||||
Contributions int64 `json:"contributions"`
|
||||
}
|
||||
|
||||
func GetUserHeatmapDataByTimestampRange(user *gitea_user_model.User, team *organization.Team, doer *gitea_user_model.User, startAt, endAt timeutil.TimeStamp) ([]*UserHeatmapData, error) {
|
||||
hdata := make([]*UserHeatmapData, 0)
|
||||
if !gitea_activities_models.ActivityReadable(user, doer) {
|
||||
return hdata, nil
|
||||
}
|
||||
|
||||
groupBy := "created_unix / 900 * 900"
|
||||
groupByName := "timestamp"
|
||||
|
||||
switch {
|
||||
case setting.Database.UseMySQL:
|
||||
groupBy = "created_unix DIV 900 * 900"
|
||||
case setting.Database.UseMSSQL:
|
||||
groupByName = groupBy
|
||||
}
|
||||
|
||||
cond, err := activityQueryCondition(gitea_activities_models.GetFeedsOptions{
|
||||
RequestedUser: user,
|
||||
RequestedTeam: team,
|
||||
Actor: doer,
|
||||
IncludePrivate: true,
|
||||
IncludeDeleted: true,
|
||||
OnlyPerformedBy: !user.IsOrganization(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hdata, db.GetEngine(db.DefaultContext).
|
||||
Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
||||
Table("action").
|
||||
Where(cond).
|
||||
And("created_unix >= ?", startAt).
|
||||
And("created_unix <= ?", endAt).
|
||||
GroupBy(groupByName).
|
||||
OrderBy("timestamp").
|
||||
Find(&hdata)
|
||||
}
|
||||
|
|
@ -22,8 +22,10 @@ import (
|
|||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/api/v1/misc"
|
||||
"code.gitea.io/gitea/services/auth"
|
||||
context_service "code.gitea.io/gitea/services/context"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/org"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/user"
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
||||
|
|
@ -106,6 +108,14 @@ func Routers(ctx gocontext.Context) *web.Route {
|
|||
})
|
||||
}, repoAssignment())
|
||||
})
|
||||
m.Group("/users", func() {
|
||||
|
||||
m.Group("/{username}", func() {
|
||||
if setting.Service.EnableUserHeatmap {
|
||||
m.Get("/heatmap", user.GetUserHeatmapData)
|
||||
}
|
||||
}, context_service.UserAssignmentAPI())
|
||||
})
|
||||
m.Post("/orgs", reqToken(), bind(gitea_api.CreateOrgOption{}), org.Create)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
hat_models "code.gitlink.org.cn/Gitlink/gitea_hat.git/models"
|
||||
hat_activities_models "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/activities"
|
||||
)
|
||||
|
||||
func PrepareComapreDiff(
|
||||
|
|
@ -481,7 +481,7 @@ func SetDiffViewStyle(ctx *context.Context) {
|
|||
}
|
||||
|
||||
func GetContributors(ctx *context.APIContext) {
|
||||
list, err := hat_models.GetContributors(ctx.Repo.Repository.ID, ctx.Repo.Owner.ID)
|
||||
list, err := hat_activities_models.GetContributors(ctx.Repo.Repository.ID, ctx.Repo.Owner.ID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetContributors", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
hat_activities_models "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/activities"
|
||||
)
|
||||
|
||||
func GetUserHeatmapData(ctx *context.APIContext) {
|
||||
startAt := timeutil.TimeStamp(ctx.FormInt("start"))
|
||||
endAt := timeutil.TimeStamp(ctx.FormInt("end"))
|
||||
if startAt <= 0 || endAt <= 0 {
|
||||
startAt = timeutil.TimeStampNow() - 31536000
|
||||
endAt = timeutil.TimeStampNow()
|
||||
}
|
||||
|
||||
heatmap, err := hat_activities_models.GetUserHeatmapDataByTimestampRange(ctx.ContextUser, nil, ctx.Doer, startAt, endAt)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserHeatmapDataByTimestampRange", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, heatmap)
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue