2014-03-13 09:16:14 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2019-05-01 19:21:05 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2014-03-13 09:16:14 +04:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
2021-12-10 04:27:50 +03:00
"context"
2014-05-06 19:50:31 +04:00
"fmt"
2021-11-16 21:18:25 +03:00
"net/url"
2014-07-26 08:24:27 +04:00
"path"
2017-06-25 21:20:29 +03:00
"strconv"
2014-04-14 06:20:28 +04:00
"strings"
2014-03-13 09:16:14 +04:00
"time"
2014-03-22 14:20:00 +04:00
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2022-03-29 09:29:02 +03:00
"code.gitea.io/gitea/models/organization"
2022-05-11 13:09:36 +03:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-12-12 18:48:20 +03:00
"code.gitea.io/gitea/models/unit"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/base"
2020-12-14 20:08:37 +03:00
"code.gitea.io/gitea/modules/git"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2022-03-10 17:54:51 +03:00
"code.gitea.io/gitea/modules/structs"
2019-08-15 17:46:21 +03:00
"code.gitea.io/gitea/modules/timeutil"
2021-12-16 22:01:14 +03:00
"code.gitea.io/gitea/modules/util"
2017-12-03 05:20:12 +03:00
2019-06-23 18:22:43 +03:00
"xorm.io/builder"
2014-03-13 09:16:14 +04:00
)
2016-11-22 13:43:30 +03:00
// ActionType represents the type of an action.
2014-07-26 08:24:27 +04:00
type ActionType int
2016-11-22 13:43:30 +03:00
// Possible action types.
2014-03-13 09:16:14 +04:00
const (
2021-06-23 07:14:22 +03:00
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
ActionStarRepo // 3
ActionWatchRepo // 4
ActionCommitRepo // 5
ActionCreateIssue // 6
ActionCreatePullRequest // 7
ActionTransferRepo // 8
ActionPushTag // 9
ActionCommentIssue // 10
ActionMergePullRequest // 11
ActionCloseIssue // 12
ActionReopenIssue // 13
ActionClosePullRequest // 14
ActionReopenPullRequest // 15
ActionDeleteTag // 16
ActionDeleteBranch // 17
ActionMirrorSyncPush // 18
ActionMirrorSyncCreate // 19
ActionMirrorSyncDelete // 20
ActionApprovePullRequest // 21
ActionRejectPullRequest // 22
ActionCommentPull // 23
ActionPublishRelease // 24
ActionPullReviewDismissed // 25
ActionPullRequestReadyForReview // 26
2014-03-13 09:16:14 +04:00
)
2016-11-22 13:43:30 +03:00
// Action represents user operation type and other information to
// repository. It implemented interface base.Actioner so that can be
// used in template render.
2014-03-13 09:16:14 +04:00
type Action struct {
2017-05-26 04:38:18 +03:00
ID int64 ` xorm:"pk autoincr" `
UserID int64 ` xorm:"INDEX" ` // Receiver user id.
OpType ActionType
2021-12-10 04:27:50 +03:00
ActUserID int64 ` xorm:"INDEX" ` // Action user id.
ActUser * user_model . User ` xorm:"-" `
RepoID int64 ` xorm:"INDEX" `
Repo * repo_model . Repository ` xorm:"-" `
CommentID int64 ` xorm:"INDEX" `
Comment * Comment ` xorm:"-" `
IsDeleted bool ` xorm:"INDEX NOT NULL DEFAULT false" `
2017-05-26 04:38:18 +03:00
RefName string
2019-08-15 17:46:21 +03:00
IsPrivate bool ` xorm:"INDEX NOT NULL DEFAULT false" `
Content string ` xorm:"TEXT" `
CreatedUnix timeutil . TimeStamp ` xorm:"INDEX created" `
2015-08-19 19:12:43 +03:00
}
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( Action ) )
}
2016-11-22 13:43:30 +03:00
// GetOpType gets the ActionType of this action.
2017-09-20 04:22:42 +03:00
func ( a * Action ) GetOpType ( ) ActionType {
return a . OpType
2014-03-15 08:50:51 +04:00
}
2020-12-09 08:11:15 +03:00
// LoadActUser loads a.ActUser
func ( a * Action ) LoadActUser ( ) {
2017-05-26 04:38:18 +03:00
if a . ActUser != nil {
return
}
var err error
2021-11-24 12:49:20 +03:00
a . ActUser , err = user_model . GetUserByID ( a . ActUserID )
2017-05-26 04:38:18 +03:00
if err == nil {
return
2021-11-24 12:49:20 +03:00
} else if user_model . IsErrUserNotExist ( err ) {
a . ActUser = user_model . NewGhostUser ( )
2017-05-26 04:38:18 +03:00
} else {
2019-04-02 10:48:31 +03:00
log . Error ( "GetUserByID(%d): %v" , a . ActUserID , err )
2017-05-26 04:38:18 +03:00
}
}
func ( a * Action ) loadRepo ( ) {
2017-06-14 03:37:50 +03:00
if a . Repo != nil {
2017-05-26 04:38:18 +03:00
return
}
var err error
2021-12-10 04:27:50 +03:00
a . Repo , err = repo_model . GetRepositoryByID ( a . RepoID )
2017-05-26 04:38:18 +03:00
if err != nil {
2021-12-10 04:27:50 +03:00
log . Error ( "repo_model.GetRepositoryByID(%d): %v" , a . RepoID , err )
2017-05-26 04:38:18 +03:00
}
}
2018-07-05 20:48:18 +03:00
// GetActFullName gets the action's user full name.
func ( a * Action ) GetActFullName ( ) string {
2020-12-09 08:11:15 +03:00
a . LoadActUser ( )
2018-07-05 20:48:18 +03:00
return a . ActUser . FullName
}
2016-11-22 13:43:30 +03:00
// GetActUserName gets the action's user name.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetActUserName ( ) string {
2020-12-09 08:11:15 +03:00
a . LoadActUser ( )
2017-05-26 04:38:18 +03:00
return a . ActUser . Name
2014-03-15 08:50:51 +04:00
}
2016-11-22 13:43:30 +03:00
// ShortActUserName gets the action's user name trimmed to max 20
// chars.
2016-01-11 15:41:43 +03:00
func ( a * Action ) ShortActUserName ( ) string {
2017-05-26 04:38:18 +03:00
return base . EllipsisString ( a . GetActUserName ( ) , 20 )
2016-01-11 15:41:43 +03:00
}
2020-02-27 01:08:24 +03:00
// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
2019-05-08 11:41:35 +03:00
func ( a * Action ) GetDisplayName ( ) string {
if setting . UI . DefaultShowFullName {
2020-02-27 01:08:24 +03:00
trimmedFullName := strings . TrimSpace ( a . GetActFullName ( ) )
if len ( trimmedFullName ) > 0 {
return trimmedFullName
}
2019-05-08 11:41:35 +03:00
}
return a . ShortActUserName ( )
}
// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
func ( a * Action ) GetDisplayNameTitle ( ) string {
if setting . UI . DefaultShowFullName {
return a . ShortActUserName ( )
}
return a . GetActFullName ( )
}
2016-11-22 13:43:30 +03:00
// GetRepoUserName returns the name of the action repository owner.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetRepoUserName ( ) string {
2017-05-26 04:38:18 +03:00
a . loadRepo ( )
2020-01-12 12:36:21 +03:00
return a . Repo . OwnerName
2014-05-09 10:42:50 +04:00
}
2016-11-22 13:43:30 +03:00
// ShortRepoUserName returns the name of the action repository owner
// trimmed to max 20 chars.
2016-01-11 15:41:43 +03:00
func ( a * Action ) ShortRepoUserName ( ) string {
2017-05-26 04:38:18 +03:00
return base . EllipsisString ( a . GetRepoUserName ( ) , 20 )
2016-01-11 15:41:43 +03:00
}
2016-11-22 13:43:30 +03:00
// GetRepoName returns the name of the action repository.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetRepoName ( ) string {
2017-05-26 04:38:18 +03:00
a . loadRepo ( )
return a . Repo . Name
2014-03-13 09:16:14 +04:00
}
2016-11-22 13:43:30 +03:00
// ShortRepoName returns the name of the action repository
// trimmed to max 33 chars.
2016-01-11 15:41:43 +03:00
func ( a * Action ) ShortRepoName ( ) string {
2017-05-26 04:38:18 +03:00
return base . EllipsisString ( a . GetRepoName ( ) , 33 )
2016-01-11 15:41:43 +03:00
}
2016-11-22 13:43:30 +03:00
// GetRepoPath returns the virtual path to the action repository.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetRepoPath ( ) string {
2017-05-26 04:38:18 +03:00
return path . Join ( a . GetRepoUserName ( ) , a . GetRepoName ( ) )
2016-01-15 13:00:39 +03:00
}
2016-11-22 13:43:30 +03:00
// ShortRepoPath returns the virtual path to the action repository
2017-01-05 03:50:34 +03:00
// trimmed to max 20 + 1 + 33 chars.
2016-01-15 13:00:39 +03:00
func ( a * Action ) ShortRepoPath ( ) string {
2016-01-11 15:41:43 +03:00
return path . Join ( a . ShortRepoUserName ( ) , a . ShortRepoName ( ) )
2015-03-12 23:01:23 +03:00
}
2016-11-22 13:43:30 +03:00
// GetRepoLink returns relative link to action repository.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetRepoLink ( ) string {
2021-11-16 21:18:25 +03:00
// path.Join will skip empty strings
return path . Join ( setting . AppSubURL , "/" , url . PathEscape ( a . GetRepoUserName ( ) ) , url . PathEscape ( a . GetRepoName ( ) ) )
2014-07-26 08:24:27 +04:00
}
2021-12-10 04:27:50 +03:00
// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings
func GetRepositoryFromMatch ( ownerName , repoName string ) ( * repo_model . Repository , error ) {
2019-05-01 19:21:05 +03:00
var err error
2021-12-10 04:27:50 +03:00
refRepo , err := repo_model . GetRepositoryByOwnerAndName ( ownerName , repoName )
2019-05-01 19:21:05 +03:00
if err != nil {
2021-12-10 04:27:50 +03:00
if repo_model . IsErrRepoNotExist ( err ) {
2019-05-01 19:21:05 +03:00
log . Warn ( "Repository referenced in commit but does not exist: %v" , err )
return nil , err
}
2021-12-10 04:27:50 +03:00
log . Error ( "repo_model.GetRepositoryByOwnerAndName: %v" , err )
2019-05-01 19:21:05 +03:00
return nil , err
}
return refRepo , nil
}
2017-06-25 21:20:29 +03:00
// GetCommentLink returns link to action comment.
func ( a * Action ) GetCommentLink ( ) string {
2021-12-10 04:27:50 +03:00
return a . getCommentLink ( db . DefaultContext )
2018-12-13 18:55:43 +03:00
}
2021-12-10 04:27:50 +03:00
func ( a * Action ) getCommentLink ( ctx context . Context ) string {
2017-06-25 21:20:29 +03:00
if a == nil {
return "#"
}
if a . Comment == nil && a . CommentID != 0 {
2022-05-20 17:08:52 +03:00
a . Comment , _ = GetCommentByID ( ctx , a . CommentID )
2017-06-25 21:20:29 +03:00
}
if a . Comment != nil {
return a . Comment . HTMLURL ( )
}
if len ( a . GetIssueInfos ( ) ) == 0 {
return "#"
}
2021-03-14 21:52:12 +03:00
// Return link to issue
2017-06-25 21:20:29 +03:00
issueIDString := a . GetIssueInfos ( ) [ 0 ]
issueID , err := strconv . ParseInt ( issueIDString , 10 , 64 )
if err != nil {
return "#"
}
2022-05-20 17:08:52 +03:00
issue , err := getIssueByID ( ctx , issueID )
2017-06-25 21:20:29 +03:00
if err != nil {
return "#"
}
2022-04-08 12:11:15 +03:00
if err = issue . LoadRepo ( ctx ) ; err != nil {
2018-12-13 18:55:43 +03:00
return "#"
}
2017-06-25 21:20:29 +03:00
return issue . HTMLURL ( )
}
2016-11-22 13:43:30 +03:00
// GetBranch returns the action's repository branch.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetBranch ( ) string {
2020-12-14 20:08:37 +03:00
return strings . TrimPrefix ( a . RefName , git . BranchPrefix )
2014-03-16 19:30:35 +04:00
}
2021-12-16 22:01:14 +03:00
// GetRefLink returns the action's ref link.
func ( a * Action ) GetRefLink ( ) string {
switch {
case strings . HasPrefix ( a . RefName , git . BranchPrefix ) :
return a . GetRepoLink ( ) + "/src/branch/" + util . PathEscapeSegments ( strings . TrimPrefix ( a . RefName , git . BranchPrefix ) )
case strings . HasPrefix ( a . RefName , git . TagPrefix ) :
return a . GetRepoLink ( ) + "/src/tag/" + util . PathEscapeSegments ( strings . TrimPrefix ( a . RefName , git . TagPrefix ) )
case len ( a . RefName ) == 40 && git . SHAPattern . MatchString ( a . RefName ) :
return a . GetRepoLink ( ) + "/src/commit/" + a . RefName
default :
// FIXME: we will just assume it's a branch - this was the old way - at some point we may want to enforce that there is always a ref here.
return a . GetRepoLink ( ) + "/src/branch/" + util . PathEscapeSegments ( strings . TrimPrefix ( a . RefName , git . BranchPrefix ) )
}
}
2020-12-20 02:46:28 +03:00
// GetTag returns the action's repository tag.
func ( a * Action ) GetTag ( ) string {
return strings . TrimPrefix ( a . RefName , git . TagPrefix )
}
2016-11-22 13:43:30 +03:00
// GetContent returns the action's content.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetContent ( ) string {
2014-03-23 14:27:01 +04:00
return a . Content
2014-03-23 14:00:09 +04:00
}
2016-11-22 13:43:30 +03:00
// GetCreate returns the action creation time.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetCreate ( ) time . Time {
2017-12-11 07:37:04 +03:00
return a . CreatedUnix . AsTime ( )
2014-07-26 08:24:27 +04:00
}
2016-11-22 13:43:30 +03:00
// GetIssueInfos returns a list of issues associated with
// the action.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetIssueInfos ( ) [ ] string {
2021-02-11 20:32:25 +03:00
return strings . SplitN ( a . Content , "|" , 3 )
2014-07-26 08:24:27 +04:00
}
2016-11-22 13:43:30 +03:00
// GetIssueTitle returns the title of first issue associated
// with the action.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetIssueTitle ( ) string {
2020-12-25 12:59:32 +03:00
index , _ := strconv . ParseInt ( a . GetIssueInfos ( ) [ 0 ] , 10 , 64 )
2015-11-13 18:05:50 +03:00
issue , err := GetIssueByIndex ( a . RepoID , index )
2015-11-13 00:16:51 +03:00
if err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "GetIssueByIndex: %v" , err )
2015-11-13 20:11:45 +03:00
return "500 when get issue"
2015-11-13 00:16:51 +03:00
}
2016-08-14 13:32:24 +03:00
return issue . Title
2015-11-12 23:09:48 +03:00
}
2016-11-22 13:43:30 +03:00
// GetIssueContent returns the content of first issue associated with
// this action.
2016-01-11 15:41:43 +03:00
func ( a * Action ) GetIssueContent ( ) string {
2020-12-25 12:59:32 +03:00
index , _ := strconv . ParseInt ( a . GetIssueInfos ( ) [ 0 ] , 10 , 64 )
2015-11-13 20:11:45 +03:00
issue , err := GetIssueByIndex ( a . RepoID , index )
if err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "GetIssueByIndex: %v" , err )
2015-11-13 20:11:45 +03:00
return "500 when get issue"
}
return issue . Content
}
2017-06-02 03:42:25 +03:00
// GetFeedsOptions options for retrieving feeds
type GetFeedsOptions struct {
2022-03-10 17:54:51 +03:00
db . ListOptions
RequestedUser * user_model . User // the user we want activity for
2022-03-29 09:29:02 +03:00
RequestedTeam * organization . Team // the team we want activity for
2022-03-10 17:54:51 +03:00
RequestedRepo * repo_model . Repository // the repo we want activity for
Actor * user_model . User // the user viewing the activity
IncludePrivate bool // include private actions
OnlyPerformedBy bool // only actions performed by requested user
IncludeDeleted bool // include deleted actions
Date string // the day we want activity for: YYYY-MM-DD
2017-06-02 03:42:25 +03:00
}
// GetFeeds returns actions according to the provided options
2022-03-13 19:40:47 +03:00
func GetFeeds ( ctx context . Context , opts GetFeedsOptions ) ( ActionList , error ) {
2022-03-10 17:54:51 +03:00
if opts . RequestedUser == nil && opts . RequestedTeam == nil && opts . RequestedRepo == nil {
return nil , fmt . Errorf ( "need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo" )
2020-12-22 05:53:37 +03:00
}
2017-08-23 04:30:54 +03:00
2020-12-22 05:53:37 +03:00
cond , err := activityQueryCondition ( opts )
if err != nil {
return nil , err
}
2020-01-13 20:33:46 +03:00
2022-05-20 17:08:52 +03:00
sess := db . GetEngine ( ctx ) . Where ( cond ) .
2022-05-09 18:19:16 +03:00
Select ( "`action`.*" ) . // this line will avoid select other joined table's columns
Join ( "INNER" , "repository" , "`repository`.id = `action`.repo_id" )
2020-12-22 05:53:37 +03:00
2022-03-10 17:54:51 +03:00
opts . SetDefaultValues ( )
sess = db . SetSessionPagination ( sess , & opts )
actions := make ( [ ] * Action , 0 , opts . PageSize )
2022-05-05 18:39:26 +03:00
if err := sess . Desc ( "`action`.created_unix" ) . Find ( & actions ) ; err != nil {
2020-12-22 05:53:37 +03:00
return nil , fmt . Errorf ( "Find: %v" , err )
2020-01-13 20:33:46 +03:00
}
2022-05-20 17:08:52 +03:00
if err := ActionList ( actions ) . loadAttributes ( ctx ) ; err != nil {
2020-12-22 05:53:37 +03:00
return nil , fmt . Errorf ( "LoadAttributes: %v" , err )
}
return actions , nil
}
2021-11-24 12:49:20 +03:00
func activityReadable ( user , doer * user_model . User ) bool {
2022-03-10 17:54:51 +03:00
return ! user . KeepActivityPrivate ||
doer != nil && ( doer . IsAdmin || user . ID == doer . ID )
2020-12-22 05:53:37 +03:00
}
2017-08-23 04:30:54 +03:00
2020-12-22 05:53:37 +03:00
func activityQueryCondition ( opts GetFeedsOptions ) ( builder . Cond , error ) {
cond := builder . NewCond ( )
2022-03-10 17:54:51 +03:00
if opts . RequestedTeam != nil && opts . RequestedUser == nil {
org , err := 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`" ) ,
) )
2017-08-23 04:30:54 +03:00
}
2020-12-22 05:53:37 +03:00
// check readable repositories by doer/actor
2020-06-05 23:01:53 +03:00
if opts . Actor == nil || ! opts . Actor . IsAdmin {
2022-06-06 11:01:49 +03:00
cond = cond . And ( builder . In ( "repo_id" , repo_model . AccessibleRepoIDsQuery ( opts . Actor ) ) )
2022-03-10 17:54:51 +03:00
}
if opts . RequestedRepo != nil {
cond = cond . And ( builder . Eq { "repo_id" : opts . RequestedRepo . ID } )
2020-06-05 23:01:53 +03:00
}
2020-12-27 22:58:03 +03:00
if opts . RequestedTeam != nil {
2022-03-29 09:29:02 +03:00
env := organization . OrgFromUser ( opts . RequestedUser ) . AccessibleTeamReposEnv ( opts . RequestedTeam )
2020-12-27 22:58:03 +03:00
teamRepoIDs , err := env . RepoIDs ( 1 , opts . RequestedUser . NumRepos )
if err != nil {
return nil , fmt . Errorf ( "GetTeamRepositories: %v" , err )
}
cond = cond . And ( builder . In ( "repo_id" , teamRepoIDs ) )
}
2022-03-10 17:54:51 +03:00
if opts . RequestedUser != nil {
cond = cond . And ( builder . Eq { "user_id" : opts . RequestedUser . ID } )
2016-02-06 10:52:21 +03:00
2022-03-10 17:54:51 +03:00
if opts . OnlyPerformedBy {
cond = cond . And ( builder . Eq { "act_user_id" : opts . RequestedUser . ID } )
}
2017-06-02 03:42:25 +03:00
}
2022-03-10 17:54:51 +03:00
2017-06-02 03:42:25 +03:00
if ! opts . IncludePrivate {
2022-05-05 18:39:26 +03:00
cond = cond . And ( builder . Eq { "`action`.is_private" : false } )
2017-06-02 03:42:25 +03:00
}
2017-06-25 21:20:29 +03:00
if ! opts . IncludeDeleted {
2017-08-23 04:30:54 +03:00
cond = cond . And ( builder . Eq { "is_deleted" : false } )
2017-06-25 21:20:29 +03:00
}
2021-02-21 01:08:58 +03:00
if opts . Date != "" {
2021-04-01 13:52:17 +03:00
dateLow , err := time . ParseInLocation ( "2006-01-02" , opts . Date , setting . DefaultUILocation )
2021-02-21 01:08:58 +03:00
if err != nil {
log . Warn ( "Unable to parse %s, filter not applied: %v" , opts . Date , err )
} else {
dateHigh := dateLow . Add ( 86399000000000 ) // 23h59m59s
2022-05-05 18:39:26 +03:00
cond = cond . And ( builder . Gte { "`action`.created_unix" : dateLow . Unix ( ) } )
cond = cond . And ( builder . Lte { "`action`.created_unix" : dateHigh . Unix ( ) } )
2021-02-21 01:08:58 +03:00
}
}
2020-12-22 05:53:37 +03:00
return cond , nil
2014-03-13 09:16:14 +04:00
}
2021-05-01 15:17:02 +03:00
// DeleteOldActions deletes all old actions from database.
func DeleteOldActions ( olderThan time . Duration ) ( err error ) {
if olderThan <= 0 {
return nil
}
2021-09-23 18:45:36 +03:00
_ , err = db . GetEngine ( db . DefaultContext ) . Where ( "created_unix < ?" , time . Now ( ) . Add ( - olderThan ) . Unix ( ) ) . Delete ( & Action { } )
2021-05-01 15:17:02 +03:00
return
}
2021-12-12 18:48:20 +03:00
func notifyWatchers ( ctx context . Context , actions ... * Action ) error {
var watchers [ ] * repo_model . Watch
var repo * repo_model . Repository
var err error
var permCode [ ] bool
var permIssue [ ] bool
var permPR [ ] bool
e := db . GetEngine ( ctx )
for _ , act := range actions {
repoChanged := repo == nil || repo . ID != act . RepoID
if repoChanged {
// Add feeds for user self and all watchers.
watchers , err = repo_model . GetWatchers ( ctx , act . RepoID )
if err != nil {
return fmt . Errorf ( "get watchers: %v" , err )
}
}
// Add feed for actioner.
act . UserID = act . ActUserID
if _ , err = e . Insert ( act ) ; err != nil {
return fmt . Errorf ( "insert new actioner: %v" , err )
}
if repoChanged {
act . loadRepo ( )
repo = act . Repo
// check repo owner exist.
if err := act . Repo . GetOwner ( ctx ) ; err != nil {
return fmt . Errorf ( "can't get repo owner: %v" , err )
}
} else if act . Repo == nil {
act . Repo = repo
}
// Add feed for organization
if act . Repo . Owner . IsOrganization ( ) && act . ActUserID != act . Repo . Owner . ID {
act . ID = 0
act . UserID = act . Repo . Owner . ID
2022-06-04 22:18:50 +03:00
if err = db . Insert ( ctx , act ) ; err != nil {
2021-12-12 18:48:20 +03:00
return fmt . Errorf ( "insert new actioner: %v" , err )
}
}
if repoChanged {
permCode = make ( [ ] bool , len ( watchers ) )
permIssue = make ( [ ] bool , len ( watchers ) )
permPR = make ( [ ] bool , len ( watchers ) )
for i , watcher := range watchers {
2022-05-20 17:08:52 +03:00
user , err := user_model . GetUserByIDCtx ( ctx , watcher . UserID )
2021-12-12 18:48:20 +03:00
if err != nil {
permCode [ i ] = false
permIssue [ i ] = false
permPR [ i ] = false
continue
}
2022-05-11 13:09:36 +03:00
perm , err := access_model . GetUserRepoPermission ( ctx , repo , user )
2021-12-12 18:48:20 +03:00
if err != nil {
permCode [ i ] = false
permIssue [ i ] = false
permPR [ i ] = false
continue
}
permCode [ i ] = perm . CanRead ( unit . TypeCode )
permIssue [ i ] = perm . CanRead ( unit . TypeIssues )
permPR [ i ] = perm . CanRead ( unit . TypePullRequests )
}
}
for i , watcher := range watchers {
if act . ActUserID == watcher . UserID {
continue
}
act . ID = 0
act . UserID = watcher . UserID
act . Repo . Units = nil
switch act . OpType {
case ActionCommitRepo , ActionPushTag , ActionDeleteTag , ActionPublishRelease , ActionDeleteBranch :
if ! permCode [ i ] {
continue
}
case ActionCreateIssue , ActionCommentIssue , ActionCloseIssue , ActionReopenIssue :
if ! permIssue [ i ] {
continue
}
case ActionCreatePullRequest , ActionCommentPull , ActionMergePullRequest , ActionClosePullRequest , ActionReopenPullRequest :
if ! permPR [ i ] {
continue
}
}
2022-06-04 22:18:50 +03:00
if err = db . Insert ( ctx , act ) ; err != nil {
2021-12-12 18:48:20 +03:00
return fmt . Errorf ( "insert new action: %v" , err )
}
}
}
return nil
}
// NotifyWatchers creates batch of actions for every watcher.
func NotifyWatchers ( actions ... * Action ) error {
return notifyWatchers ( db . DefaultContext , actions ... )
}
// NotifyWatchersActions creates batch of actions for every watcher.
func NotifyWatchersActions ( acts [ ] * Action ) error {
ctx , committer , err := db . TxContext ( )
if err != nil {
return err
}
defer committer . Close ( )
for _ , act := range acts {
if err := notifyWatchers ( ctx , act ) ; err != nil {
return err
}
}
return committer . Commit ( )
}