Files

85 lines
3.1 KiB
Go

// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package activities
import (
"context"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
)
// UserHeatmapData represents the data needed to create a heatmap
type UserHeatmapData struct {
Timestamp timeutil.TimeStamp `json:"timestamp"`
Contributions int64 `json:"contributions"`
}
// GetUserHeatmapDataByUser returns an array of UserHeatmapData, it checks whether doer can access user's activity
func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) {
return getUserHeatmapData(ctx, user, nil, doer)
}
// GetUserHeatmapDataByOrgTeam returns an array of UserHeatmapData, it checks whether doer can access org's activity
func GetUserHeatmapDataByOrgTeam(ctx context.Context, org *organization.Organization, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
return getUserHeatmapData(ctx, org.AsUser(), team, doer)
}
func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
hdata := make([]*UserHeatmapData, 0)
if !ActivityReadable(user, doer) {
return hdata, nil
}
// Group by 15 minute intervals which will allow the client to accurately shift the timestamp to their timezone.
// The interval is based on the fact that there are timezones such as UTC +5:30 and UTC +12:45.
groupBy := "author_unix / 900 * 900"
groupByName := "timestamp" // We need this extra case because mssql doesn't allow grouping by alias
switch {
case setting.Database.Type.IsMySQL():
groupBy = "author_unix DIV 900 * 900"
case setting.Database.Type.IsMSSQL():
groupByName = groupBy
}
includePrivate, err := user_model.GetIncludePrivateContributions(ctx, user.ID)
if err != nil {
return nil, err
}
sess := db.GetEngine(ctx).
Select(groupBy+" AS timestamp, count(heatmap_contribution.user_id) as contributions").
Table("heatmap_contribution").
Join("INNER", "repository", "repository.id = heatmap_contribution.repo_id").
Join("INNER", "`user` AS repo_owner", "repo_owner.id = repository.owner_id").
Where("author_unix > ?", timeutil.TimeStampNow()-(366+7)*86400). // (366+7) days to include the first week for the heatmap
And("author_unix <= ?", timeutil.TimeStampNow())
if !includePrivate {
sess = sess.And("repository.is_private = ?", false).
And("repo_owner.visibility = ?", structs.VisibleTypePublic)
}
if user.IsOrganization() {
sess = sess.And("repository.owner_id = ?", user.ID)
if team != nil && !team.IncludesAllRepositories {
sess = sess.Join("INNER", "team_repo", "team_repo.repo_id = repository.id").
And("team_repo.org_id = ?", team.OrgID).
And("team_repo.team_id = ?", team.ID)
}
} else {
sess = sess.And("heatmap_contribution.user_id = ?", user.ID)
}
return hdata, sess.
GroupBy(groupByName).
OrderBy("timestamp").
Find(&hdata)
}