You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

action.go 9.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package action
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "path"
  9. "strings"
  10. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/git"
  12. "code.gitea.io/gitea/modules/log"
  13. "code.gitea.io/gitea/modules/notification/base"
  14. "code.gitea.io/gitea/modules/repository"
  15. )
  16. type actionNotifier struct {
  17. base.NullNotifier
  18. }
  19. var (
  20. _ base.Notifier = &actionNotifier{}
  21. )
  22. // NewNotifier create a new actionNotifier notifier
  23. func NewNotifier() base.Notifier {
  24. return &actionNotifier{}
  25. }
  26. func (a *actionNotifier) NotifyNewIssue(issue *models.Issue) {
  27. if err := issue.LoadPoster(); err != nil {
  28. log.Error("issue.LoadPoster: %v", err)
  29. return
  30. }
  31. if err := issue.LoadRepo(); err != nil {
  32. log.Error("issue.LoadRepo: %v", err)
  33. return
  34. }
  35. repo := issue.Repo
  36. if err := models.NotifyWatchers(&models.Action{
  37. ActUserID: issue.Poster.ID,
  38. ActUser: issue.Poster,
  39. OpType: models.ActionCreateIssue,
  40. Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
  41. RepoID: repo.ID,
  42. Repo: repo,
  43. IsPrivate: repo.IsPrivate,
  44. }); err != nil {
  45. log.Error("NotifyWatchers: %v", err)
  46. }
  47. }
  48. // NotifyIssueChangeStatus notifies close or reopen issue to notifiers
  49. func (a *actionNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, closeOrReopen bool) {
  50. // Compose comment action, could be plain comment, close or reopen issue/pull request.
  51. // This object will be used to notify watchers in the end of function.
  52. act := &models.Action{
  53. ActUserID: doer.ID,
  54. ActUser: doer,
  55. Content: fmt.Sprintf("%d|%s", issue.Index, ""),
  56. RepoID: issue.Repo.ID,
  57. Repo: issue.Repo,
  58. Comment: actionComment,
  59. CommentID: actionComment.ID,
  60. IsPrivate: issue.Repo.IsPrivate,
  61. }
  62. // Check comment type.
  63. if closeOrReopen {
  64. act.OpType = models.ActionCloseIssue
  65. if issue.IsPull {
  66. act.OpType = models.ActionClosePullRequest
  67. }
  68. } else {
  69. act.OpType = models.ActionReopenIssue
  70. if issue.IsPull {
  71. act.OpType = models.ActionReopenPullRequest
  72. }
  73. }
  74. // Notify watchers for whatever action comes in, ignore if no action type.
  75. if err := models.NotifyWatchers(act); err != nil {
  76. log.Error("NotifyWatchers: %v", err)
  77. }
  78. }
  79. // NotifyCreateIssueComment notifies comment on an issue to notifiers
  80. func (a *actionNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
  81. issue *models.Issue, comment *models.Comment) {
  82. act := &models.Action{
  83. ActUserID: doer.ID,
  84. ActUser: doer,
  85. Content: fmt.Sprintf("%d|%s", issue.Index, comment.Content),
  86. RepoID: issue.Repo.ID,
  87. Repo: issue.Repo,
  88. Comment: comment,
  89. CommentID: comment.ID,
  90. IsPrivate: issue.Repo.IsPrivate,
  91. }
  92. if issue.IsPull {
  93. act.OpType = models.ActionCommentPull
  94. } else {
  95. act.OpType = models.ActionCommentIssue
  96. }
  97. // Notify watchers for whatever action comes in, ignore if no action type.
  98. if err := models.NotifyWatchers(act); err != nil {
  99. log.Error("NotifyWatchers: %v", err)
  100. }
  101. }
  102. func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
  103. if err := pull.LoadIssue(); err != nil {
  104. log.Error("pull.LoadIssue: %v", err)
  105. return
  106. }
  107. if err := pull.Issue.LoadRepo(); err != nil {
  108. log.Error("pull.Issue.LoadRepo: %v", err)
  109. return
  110. }
  111. if err := pull.Issue.LoadPoster(); err != nil {
  112. log.Error("pull.Issue.LoadPoster: %v", err)
  113. return
  114. }
  115. if err := models.NotifyWatchers(&models.Action{
  116. ActUserID: pull.Issue.Poster.ID,
  117. ActUser: pull.Issue.Poster,
  118. OpType: models.ActionCreatePullRequest,
  119. Content: fmt.Sprintf("%d|%s", pull.Issue.Index, pull.Issue.Title),
  120. RepoID: pull.Issue.Repo.ID,
  121. Repo: pull.Issue.Repo,
  122. IsPrivate: pull.Issue.Repo.IsPrivate,
  123. }); err != nil {
  124. log.Error("NotifyWatchers: %v", err)
  125. }
  126. }
  127. func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string) {
  128. log.Trace("action.ChangeRepositoryName: %s/%s", doer.Name, repo.Name)
  129. if err := models.NotifyWatchers(&models.Action{
  130. ActUserID: doer.ID,
  131. ActUser: doer,
  132. OpType: models.ActionRenameRepo,
  133. RepoID: repo.ID,
  134. Repo: repo,
  135. IsPrivate: repo.IsPrivate,
  136. Content: oldRepoName,
  137. }); err != nil {
  138. log.Error("NotifyWatchers: %v", err)
  139. }
  140. }
  141. func (a *actionNotifier) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) {
  142. if err := models.NotifyWatchers(&models.Action{
  143. ActUserID: doer.ID,
  144. ActUser: doer,
  145. OpType: models.ActionTransferRepo,
  146. RepoID: repo.ID,
  147. Repo: repo,
  148. IsPrivate: repo.IsPrivate,
  149. Content: path.Join(oldOwnerName, repo.Name),
  150. }); err != nil {
  151. log.Error("NotifyWatchers: %v", err)
  152. }
  153. }
  154. func (a *actionNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) {
  155. if err := models.NotifyWatchers(&models.Action{
  156. ActUserID: doer.ID,
  157. ActUser: doer,
  158. OpType: models.ActionCreateRepo,
  159. RepoID: repo.ID,
  160. Repo: repo,
  161. IsPrivate: repo.IsPrivate,
  162. }); err != nil {
  163. log.Error("notify watchers '%d/%d': %v", doer.ID, repo.ID, err)
  164. }
  165. }
  166. func (a *actionNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
  167. if err := models.NotifyWatchers(&models.Action{
  168. ActUserID: doer.ID,
  169. ActUser: doer,
  170. OpType: models.ActionCreateRepo,
  171. RepoID: repo.ID,
  172. Repo: repo,
  173. IsPrivate: repo.IsPrivate,
  174. }); err != nil {
  175. log.Error("notify watchers '%d/%d': %v", doer.ID, repo.ID, err)
  176. }
  177. }
  178. func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
  179. if err := review.LoadReviewer(); err != nil {
  180. log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err)
  181. return
  182. }
  183. if err := review.LoadCodeComments(); err != nil {
  184. log.Error("LoadCodeComments '%d/%d': %v", review.Reviewer.ID, review.ID, err)
  185. return
  186. }
  187. var actions = make([]*models.Action, 0, 10)
  188. for _, lines := range review.CodeComments {
  189. for _, comments := range lines {
  190. for _, comm := range comments {
  191. actions = append(actions, &models.Action{
  192. ActUserID: review.Reviewer.ID,
  193. ActUser: review.Reviewer,
  194. Content: fmt.Sprintf("%d|%s", review.Issue.Index, strings.Split(comm.Content, "\n")[0]),
  195. OpType: models.ActionCommentPull,
  196. RepoID: review.Issue.RepoID,
  197. Repo: review.Issue.Repo,
  198. IsPrivate: review.Issue.Repo.IsPrivate,
  199. Comment: comm,
  200. CommentID: comm.ID,
  201. })
  202. }
  203. }
  204. }
  205. if review.Type != models.ReviewTypeComment || strings.TrimSpace(comment.Content) != "" {
  206. action := &models.Action{
  207. ActUserID: review.Reviewer.ID,
  208. ActUser: review.Reviewer,
  209. Content: fmt.Sprintf("%d|%s", review.Issue.Index, strings.Split(comment.Content, "\n")[0]),
  210. RepoID: review.Issue.RepoID,
  211. Repo: review.Issue.Repo,
  212. IsPrivate: review.Issue.Repo.IsPrivate,
  213. Comment: comment,
  214. CommentID: comment.ID,
  215. }
  216. switch review.Type {
  217. case models.ReviewTypeApprove:
  218. action.OpType = models.ActionApprovePullRequest
  219. case models.ReviewTypeReject:
  220. action.OpType = models.ActionRejectPullRequest
  221. default:
  222. action.OpType = models.ActionCommentPull
  223. }
  224. actions = append(actions, action)
  225. }
  226. if err := models.NotifyWatchersActions(actions); err != nil {
  227. log.Error("notify watchers '%d/%d': %v", review.Reviewer.ID, review.Issue.RepoID, err)
  228. }
  229. }
  230. func (*actionNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User, baseRepo *git.Repository) {
  231. if err := models.NotifyWatchers(&models.Action{
  232. ActUserID: doer.ID,
  233. ActUser: doer,
  234. OpType: models.ActionMergePullRequest,
  235. Content: fmt.Sprintf("%d|%s", pr.Issue.Index, pr.Issue.Title),
  236. RepoID: pr.Issue.Repo.ID,
  237. Repo: pr.Issue.Repo,
  238. IsPrivate: pr.Issue.Repo.IsPrivate,
  239. }); err != nil {
  240. log.Error("NotifyWatchers [%d]: %v", pr.ID, err)
  241. }
  242. }
  243. func (a *actionNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) {
  244. data, err := json.Marshal(commits)
  245. if err != nil {
  246. log.Error("json.Marshal: %v", err)
  247. return
  248. }
  249. if err := models.NotifyWatchers(&models.Action{
  250. ActUserID: repo.OwnerID,
  251. ActUser: repo.MustOwner(),
  252. OpType: models.ActionMirrorSyncPush,
  253. RepoID: repo.ID,
  254. Repo: repo,
  255. IsPrivate: repo.IsPrivate,
  256. RefName: refName,
  257. Content: string(data),
  258. }); err != nil {
  259. log.Error("notifyWatchers: %v", err)
  260. }
  261. }
  262. func (a *actionNotifier) NotifySyncCreateRef(doer *models.User, repo *models.Repository, refType, refFullName string) {
  263. if err := models.NotifyWatchers(&models.Action{
  264. ActUserID: repo.OwnerID,
  265. ActUser: repo.MustOwner(),
  266. OpType: models.ActionMirrorSyncCreate,
  267. RepoID: repo.ID,
  268. Repo: repo,
  269. IsPrivate: repo.IsPrivate,
  270. RefName: refFullName,
  271. }); err != nil {
  272. log.Error("notifyWatchers: %v", err)
  273. }
  274. }
  275. func (a *actionNotifier) NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) {
  276. if err := models.NotifyWatchers(&models.Action{
  277. ActUserID: repo.OwnerID,
  278. ActUser: repo.MustOwner(),
  279. OpType: models.ActionMirrorSyncCreate,
  280. RepoID: repo.ID,
  281. Repo: repo,
  282. IsPrivate: repo.IsPrivate,
  283. RefName: refFullName,
  284. }); err != nil {
  285. log.Error("notifyWatchers: %v", err)
  286. }
  287. }