code.gitea.io/gitea@v1.21.7/models/activities/user_heatmap.go (about)

     1  // Copyright 2018 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package activities
     5  
     6  import (
     7  	"context"
     8  
     9  	"code.gitea.io/gitea/models/db"
    10  	"code.gitea.io/gitea/models/organization"
    11  	user_model "code.gitea.io/gitea/models/user"
    12  	"code.gitea.io/gitea/modules/setting"
    13  	"code.gitea.io/gitea/modules/timeutil"
    14  )
    15  
    16  // UserHeatmapData represents the data needed to create a heatmap
    17  type UserHeatmapData struct {
    18  	Timestamp     timeutil.TimeStamp `json:"timestamp"`
    19  	Contributions int64              `json:"contributions"`
    20  }
    21  
    22  // GetUserHeatmapDataByUser returns an array of UserHeatmapData
    23  func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) {
    24  	return getUserHeatmapData(ctx, user, nil, doer)
    25  }
    26  
    27  // GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
    28  func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
    29  	return getUserHeatmapData(ctx, user, team, doer)
    30  }
    31  
    32  func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
    33  	hdata := make([]*UserHeatmapData, 0)
    34  
    35  	if !ActivityReadable(user, doer) {
    36  		return hdata, nil
    37  	}
    38  
    39  	// Group by 15 minute intervals which will allow the client to accurately shift the timestamp to their timezone.
    40  	// The interval is based on the fact that there are timezones such as UTC +5:30 and UTC +12:45.
    41  	groupBy := "created_unix / 900 * 900"
    42  	groupByName := "timestamp" // We need this extra case because mssql doesn't allow grouping by alias
    43  	switch {
    44  	case setting.Database.Type.IsMySQL():
    45  		groupBy = "created_unix DIV 900 * 900"
    46  	case setting.Database.Type.IsMSSQL():
    47  		groupByName = groupBy
    48  	}
    49  
    50  	cond, err := activityQueryCondition(ctx, GetFeedsOptions{
    51  		RequestedUser:  user,
    52  		RequestedTeam:  team,
    53  		Actor:          doer,
    54  		IncludePrivate: true, // don't filter by private, as we already filter by repo access
    55  		IncludeDeleted: true,
    56  		// * Heatmaps for individual users only include actions that the user themself did.
    57  		// * For organizations actions by all users that were made in owned
    58  		//   repositories are counted.
    59  		OnlyPerformedBy: !user.IsOrganization(),
    60  	})
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	return hdata, db.GetEngine(ctx).
    66  		Select(groupBy+" AS timestamp, count(user_id) as contributions").
    67  		Table("action").
    68  		Where(cond).
    69  		And("created_unix > ?", timeutil.TimeStampNow()-31536000).
    70  		GroupBy(groupByName).
    71  		OrderBy("timestamp").
    72  		Find(&hdata)
    73  }
    74  
    75  // GetTotalContributionsInHeatmap returns the total number of contributions in a heatmap
    76  func GetTotalContributionsInHeatmap(hdata []*UserHeatmapData) int64 {
    77  	var total int64
    78  	for _, v := range hdata {
    79  		total += v.Contributions
    80  	}
    81  	return total
    82  }