2019-11-03 20:59:09 +00:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package action
import (
"fmt"
2019-11-15 08:06:11 +00:00
"path"
2019-11-14 02:57:36 +00:00
"strings"
2019-11-03 20:59:09 +00:00
"code.gitea.io/gitea/models"
2022-04-08 09:11:15 +00:00
"code.gitea.io/gitea/models/db"
2021-12-10 01:27:50 +00:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-24 09:49:20 +00:00
user_model "code.gitea.io/gitea/models/user"
2022-01-19 23:26:57 +00:00
"code.gitea.io/gitea/modules/graceful"
2021-07-24 16:03:58 +00:00
"code.gitea.io/gitea/modules/json"
2019-11-03 20:59:09 +00:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification/base"
2022-01-19 23:26:57 +00:00
"code.gitea.io/gitea/modules/process"
2020-01-10 09:34:21 +00:00
"code.gitea.io/gitea/modules/repository"
2021-12-09 05:41:17 +00:00
"code.gitea.io/gitea/modules/util"
2019-11-03 20:59:09 +00:00
)
type actionNotifier struct {
base . NullNotifier
}
2022-01-20 17:46:10 +00:00
var _ base . Notifier = & actionNotifier { }
2019-11-03 20:59:09 +00:00
2019-11-08 20:54:50 +00:00
// NewNotifier create a new actionNotifier notifier
2019-11-03 20:59:09 +00:00
func NewNotifier ( ) base . Notifier {
return & actionNotifier { }
}
2021-11-24 09:49:20 +00:00
func ( a * actionNotifier ) NotifyNewIssue ( issue * models . Issue , mentions [ ] * user_model . User ) {
2019-11-03 20:59:09 +00:00
if err := issue . LoadPoster ( ) ; err != nil {
log . Error ( "issue.LoadPoster: %v" , err )
return
}
2022-04-08 09:11:15 +00:00
if err := issue . LoadRepo ( db . DefaultContext ) ; err != nil {
2019-11-03 20:59:09 +00:00
log . Error ( "issue.LoadRepo: %v" , err )
return
}
repo := issue . Repo
if err := models . NotifyWatchers ( & models . Action {
ActUserID : issue . Poster . ID ,
ActUser : issue . Poster ,
OpType : models . ActionCreateIssue ,
Content : fmt . Sprintf ( "%d|%s" , issue . Index , issue . Title ) ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
} ) ; err != nil {
log . Error ( "NotifyWatchers: %v" , err )
}
}
2019-12-15 21:57:34 +00:00
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers
2021-11-24 09:49:20 +00:00
func ( a * actionNotifier ) NotifyIssueChangeStatus ( doer * user_model . User , issue * models . Issue , actionComment * models . Comment , closeOrReopen bool ) {
2019-12-15 21:57:34 +00:00
// Compose comment action, could be plain comment, close or reopen issue/pull request.
// This object will be used to notify watchers in the end of function.
act := & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
Content : fmt . Sprintf ( "%d|%s" , issue . Index , "" ) ,
RepoID : issue . Repo . ID ,
Repo : issue . Repo ,
Comment : actionComment ,
CommentID : actionComment . ID ,
IsPrivate : issue . Repo . IsPrivate ,
}
// Check comment type.
if closeOrReopen {
act . OpType = models . ActionCloseIssue
if issue . IsPull {
act . OpType = models . ActionClosePullRequest
}
} else {
act . OpType = models . ActionReopenIssue
if issue . IsPull {
act . OpType = models . ActionReopenPullRequest
}
}
// Notify watchers for whatever action comes in, ignore if no action type.
if err := models . NotifyWatchers ( act ) ; err != nil {
log . Error ( "NotifyWatchers: %v" , err )
}
}
// NotifyCreateIssueComment notifies comment on an issue to notifiers
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifyCreateIssueComment ( doer * user_model . User , repo * repo_model . Repository ,
2022-02-23 20:16:07 +00:00
issue * models . Issue , comment * models . Comment , mentions [ ] * user_model . User ,
) {
2019-12-15 21:57:34 +00:00
act := & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
RepoID : issue . Repo . ID ,
Repo : issue . Repo ,
Comment : comment ,
CommentID : comment . ID ,
IsPrivate : issue . Repo . IsPrivate ,
}
2020-09-18 07:38:21 +00:00
2021-12-09 05:41:17 +00:00
truncatedContent , truncatedRight := util . SplitStringAtByteN ( comment . Content , 200 )
if truncatedRight != "" {
// in case the content is in a Latin family language, we remove the last broken word.
lastSpaceIdx := strings . LastIndex ( truncatedContent , " " )
if lastSpaceIdx != - 1 && ( len ( truncatedContent ) - lastSpaceIdx < 15 ) {
truncatedContent = truncatedContent [ : lastSpaceIdx ] + "…"
}
2020-09-18 07:38:21 +00:00
}
2021-12-09 05:41:17 +00:00
act . Content = fmt . Sprintf ( "%d|%s" , issue . Index , truncatedContent )
2020-09-18 07:38:21 +00:00
2019-12-22 08:29:26 +00:00
if issue . IsPull {
act . OpType = models . ActionCommentPull
} else {
act . OpType = models . ActionCommentIssue
}
2019-12-15 21:57:34 +00:00
// Notify watchers for whatever action comes in, ignore if no action type.
if err := models . NotifyWatchers ( act ) ; err != nil {
log . Error ( "NotifyWatchers: %v" , err )
}
}
2021-11-24 09:49:20 +00:00
func ( a * actionNotifier ) NotifyNewPullRequest ( pull * models . PullRequest , mentions [ ] * user_model . User ) {
2019-11-03 20:59:09 +00:00
if err := pull . LoadIssue ( ) ; err != nil {
log . Error ( "pull.LoadIssue: %v" , err )
return
}
2022-04-08 09:11:15 +00:00
if err := pull . Issue . LoadRepo ( db . DefaultContext ) ; err != nil {
2019-11-03 20:59:09 +00:00
log . Error ( "pull.Issue.LoadRepo: %v" , err )
return
}
if err := pull . Issue . LoadPoster ( ) ; err != nil {
log . Error ( "pull.Issue.LoadPoster: %v" , err )
return
}
if err := models . NotifyWatchers ( & models . Action {
ActUserID : pull . Issue . Poster . ID ,
ActUser : pull . Issue . Poster ,
OpType : models . ActionCreatePullRequest ,
Content : fmt . Sprintf ( "%d|%s" , pull . Issue . Index , pull . Issue . Title ) ,
RepoID : pull . Issue . Repo . ID ,
Repo : pull . Issue . Repo ,
IsPrivate : pull . Issue . Repo . IsPrivate ,
} ) ; err != nil {
log . Error ( "NotifyWatchers: %v" , err )
}
}
2019-11-08 20:54:50 +00:00
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifyRenameRepository ( doer * user_model . User , repo * repo_model . Repository , oldRepoName string ) {
2019-11-08 20:54:50 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : models . ActionRenameRepo ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
2019-11-15 08:06:11 +00:00
Content : oldRepoName ,
2019-11-08 20:54:50 +00:00
} ) ; err != nil {
2019-11-15 08:06:11 +00:00
log . Error ( "NotifyWatchers: %v" , err )
}
}
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifyTransferRepository ( doer * user_model . User , repo * repo_model . Repository , oldOwnerName string ) {
2019-11-15 08:06:11 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : models . ActionTransferRepo ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
Content : path . Join ( oldOwnerName , repo . Name ) ,
} ) ; err != nil {
log . Error ( "NotifyWatchers: %v" , err )
2019-11-08 20:54:50 +00:00
}
}
2019-11-11 03:39:41 +00:00
2021-12-20 04:41:31 +00:00
func ( a * actionNotifier ) NotifyCreateRepository ( doer , u * user_model . User , repo * repo_model . Repository ) {
2019-11-11 03:39:41 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : models . ActionCreateRepo ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
} ) ; err != nil {
log . Error ( "notify watchers '%d/%d': %v" , doer . ID , repo . ID , err )
}
}
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifyForkRepository ( doer * user_model . User , oldRepo , repo * repo_model . Repository ) {
2019-11-11 03:39:41 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : models . ActionCreateRepo ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
} ) ; err != nil {
log . Error ( "notify watchers '%d/%d': %v" , doer . ID , repo . ID , err )
}
}
2019-11-14 02:57:36 +00:00
2021-11-24 09:49:20 +00:00
func ( a * actionNotifier ) NotifyPullRequestReview ( pr * models . PullRequest , review * models . Review , comment * models . Comment , mentions [ ] * user_model . User ) {
2022-01-19 23:26:57 +00:00
ctx , _ , finished := process . GetManager ( ) . AddContext ( graceful . GetManager ( ) . HammerContext ( ) , fmt . Sprintf ( "actionNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]" , pr . ID , pr . Index , pr . BaseRepoID ) )
defer finished ( )
2019-11-14 02:57:36 +00:00
if err := review . LoadReviewer ( ) ; err != nil {
log . Error ( "LoadReviewer '%d/%d': %v" , review . ID , review . ReviewerID , err )
return
}
2022-01-19 23:26:57 +00:00
if err := review . LoadCodeComments ( ctx ) ; err != nil {
2019-11-14 02:57:36 +00:00
log . Error ( "LoadCodeComments '%d/%d': %v" , review . Reviewer . ID , review . ID , err )
return
}
2022-01-20 17:46:10 +00:00
actions := make ( [ ] * models . Action , 0 , 10 )
2019-11-14 02:57:36 +00:00
for _ , lines := range review . CodeComments {
for _ , comments := range lines {
for _ , comm := range comments {
actions = append ( actions , & models . Action {
ActUserID : review . Reviewer . ID ,
ActUser : review . Reviewer ,
Content : fmt . Sprintf ( "%d|%s" , review . Issue . Index , strings . Split ( comm . Content , "\n" ) [ 0 ] ) ,
2019-12-22 08:29:26 +00:00
OpType : models . ActionCommentPull ,
2019-11-14 02:57:36 +00:00
RepoID : review . Issue . RepoID ,
Repo : review . Issue . Repo ,
IsPrivate : review . Issue . Repo . IsPrivate ,
Comment : comm ,
CommentID : comm . ID ,
} )
}
}
}
2019-11-14 23:52:18 +00:00
if review . Type != models . ReviewTypeComment || strings . TrimSpace ( comment . Content ) != "" {
action := & models . Action {
2019-11-14 02:57:36 +00:00
ActUserID : review . Reviewer . ID ,
ActUser : review . Reviewer ,
Content : fmt . Sprintf ( "%d|%s" , review . Issue . Index , strings . Split ( comment . Content , "\n" ) [ 0 ] ) ,
RepoID : review . Issue . RepoID ,
Repo : review . Issue . Repo ,
IsPrivate : review . Issue . Repo . IsPrivate ,
Comment : comment ,
CommentID : comment . ID ,
2019-11-14 23:52:18 +00:00
}
switch review . Type {
case models . ReviewTypeApprove :
action . OpType = models . ActionApprovePullRequest
case models . ReviewTypeReject :
action . OpType = models . ActionRejectPullRequest
default :
2019-12-22 08:29:26 +00:00
action . OpType = models . ActionCommentPull
2019-11-14 23:52:18 +00:00
}
actions = append ( actions , action )
2019-11-14 02:57:36 +00:00
}
if err := models . NotifyWatchersActions ( actions ) ; err != nil {
log . Error ( "notify watchers '%d/%d': %v" , review . Reviewer . ID , review . Issue . RepoID , err )
}
}
2019-11-21 17:08:42 +00:00
2021-11-24 09:49:20 +00:00
func ( * actionNotifier ) NotifyMergePullRequest ( pr * models . PullRequest , doer * user_model . User ) {
2019-11-21 17:08:42 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : models . ActionMergePullRequest ,
Content : fmt . Sprintf ( "%d|%s" , pr . Issue . Index , pr . Issue . Title ) ,
RepoID : pr . Issue . Repo . ID ,
Repo : pr . Issue . Repo ,
IsPrivate : pr . Issue . Repo . IsPrivate ,
} ) ; err != nil {
log . Error ( "NotifyWatchers [%d]: %v" , pr . ID , err )
}
}
2019-11-24 05:16:59 +00:00
2021-11-24 09:49:20 +00:00
func ( * actionNotifier ) NotifyPullRevieweDismiss ( doer * user_model . User , review * models . Review , comment * models . Comment ) {
2021-02-11 17:32:25 +00:00
reviewerName := review . Reviewer . Name
if len ( review . OriginalAuthor ) > 0 {
reviewerName = review . OriginalAuthor
}
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : models . ActionPullReviewDismissed ,
Content : fmt . Sprintf ( "%d|%s|%s" , review . Issue . Index , reviewerName , comment . Content ) ,
RepoID : review . Issue . Repo . ID ,
Repo : review . Issue . Repo ,
IsPrivate : review . Issue . Repo . IsPrivate ,
CommentID : comment . ID ,
Comment : comment ,
} ) ; err != nil {
log . Error ( "NotifyWatchers [%d]: %v" , review . Issue . ID , err )
}
}
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifyPushCommits ( pusher * user_model . User , repo * repo_model . Repository , opts * repository . PushUpdateOptions , commits * repository . PushCommits ) {
2020-12-08 02:23:18 +00:00
data , err := json . Marshal ( commits )
if err != nil {
log . Error ( "Marshal: %v" , err )
return
}
opType := models . ActionCommitRepo
// Check it's tag push or branch.
if opts . IsTag ( ) {
opType = models . ActionPushTag
if opts . IsDelRef ( ) {
opType = models . ActionDeleteTag
}
} else if opts . IsDelRef ( ) {
opType = models . ActionDeleteBranch
}
if err = models . NotifyWatchers ( & models . Action {
ActUserID : pusher . ID ,
ActUser : pusher ,
OpType : opType ,
Content : string ( data ) ,
RepoID : repo . ID ,
Repo : repo ,
RefName : opts . RefFullName ,
IsPrivate : repo . IsPrivate ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}
2022-01-19 23:26:57 +00:00
func ( a * actionNotifier ) NotifyCreateRef ( doer * user_model . User , repo * repo_model . Repository , refType , refFullName , refID string ) {
2020-12-08 02:23:18 +00:00
opType := models . ActionCommitRepo
if refType == "tag" {
2021-03-21 10:11:22 +00:00
// has sent same action in `NotifyPushCommits`, so skip it.
return
2020-12-08 02:23:18 +00:00
}
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : opType ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
RefName : refFullName ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifyDeleteRef ( doer * user_model . User , repo * repo_model . Repository , refType , refFullName string ) {
2020-12-08 02:23:18 +00:00
opType := models . ActionDeleteBranch
if refType == "tag" {
2021-03-21 10:11:22 +00:00
// has sent same action in `NotifyPushCommits`, so skip it.
return
2020-12-08 02:23:18 +00:00
}
if err := models . NotifyWatchers ( & models . Action {
ActUserID : doer . ID ,
ActUser : doer ,
OpType : opType ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
RefName : refFullName ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifySyncPushCommits ( pusher * user_model . User , repo * repo_model . Repository , opts * repository . PushUpdateOptions , commits * repository . PushCommits ) {
2019-11-24 05:16:59 +00:00
data , err := json . Marshal ( commits )
if err != nil {
log . Error ( "json.Marshal: %v" , err )
return
}
if err := models . NotifyWatchers ( & models . Action {
ActUserID : repo . OwnerID ,
ActUser : repo . MustOwner ( ) ,
OpType : models . ActionMirrorSyncPush ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
2020-10-30 21:59:02 +00:00
RefName : opts . RefFullName ,
2019-11-24 05:16:59 +00:00
Content : string ( data ) ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}
2022-01-19 23:26:57 +00:00
func ( a * actionNotifier ) NotifySyncCreateRef ( doer * user_model . User , repo * repo_model . Repository , refType , refFullName , refID string ) {
2019-11-24 05:16:59 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : repo . OwnerID ,
ActUser : repo . MustOwner ( ) ,
OpType : models . ActionMirrorSyncCreate ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
RefName : refFullName ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}
2021-12-10 01:27:50 +00:00
func ( a * actionNotifier ) NotifySyncDeleteRef ( doer * user_model . User , repo * repo_model . Repository , refType , refFullName string ) {
2019-11-24 05:16:59 +00:00
if err := models . NotifyWatchers ( & models . Action {
ActUserID : repo . OwnerID ,
ActUser : repo . MustOwner ( ) ,
2020-11-01 02:09:16 +00:00
OpType : models . ActionMirrorSyncDelete ,
2019-11-24 05:16:59 +00:00
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
RefName : refFullName ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}
2020-07-29 19:20:54 +00:00
func ( a * actionNotifier ) NotifyNewRelease ( rel * models . Release ) {
if err := rel . LoadAttributes ( ) ; err != nil {
log . Error ( "NotifyNewRelease: %v" , err )
return
}
if err := models . NotifyWatchers ( & models . Action {
ActUserID : rel . PublisherID ,
ActUser : rel . Publisher ,
OpType : models . ActionPublishRelease ,
RepoID : rel . RepoID ,
Repo : rel . Repo ,
IsPrivate : rel . Repo . IsPrivate ,
Content : rel . Title ,
RefName : rel . TagName ,
} ) ; err != nil {
log . Error ( "notifyWatchers: %v" , err )
}
}