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

issue_watch.go 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // Copyright 2017 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 models
  5. import (
  6. "code.gitea.io/gitea/modules/timeutil"
  7. )
  8. // IssueWatch is connection request for receiving issue notification.
  9. type IssueWatch struct {
  10. ID int64 `xorm:"pk autoincr"`
  11. UserID int64 `xorm:"UNIQUE(watch) NOT NULL"`
  12. IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"`
  13. IsWatching bool `xorm:"NOT NULL"`
  14. CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
  15. UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"`
  16. }
  17. // IssueWatchList contains IssueWatch
  18. type IssueWatchList []*IssueWatch
  19. // CreateOrUpdateIssueWatch set watching for a user and issue
  20. func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error {
  21. iw, exists, err := getIssueWatch(x, userID, issueID)
  22. if err != nil {
  23. return err
  24. }
  25. if !exists {
  26. iw = &IssueWatch{
  27. UserID: userID,
  28. IssueID: issueID,
  29. IsWatching: isWatching,
  30. }
  31. if _, err := x.Insert(iw); err != nil {
  32. return err
  33. }
  34. } else {
  35. iw.IsWatching = isWatching
  36. if _, err := x.ID(iw.ID).Cols("is_watching", "updated_unix").Update(iw); err != nil {
  37. return err
  38. }
  39. }
  40. return nil
  41. }
  42. // GetIssueWatch returns all IssueWatch objects from db by user and issue
  43. // the current Web-UI need iw object for watchers AND explicit non-watchers
  44. func GetIssueWatch(userID, issueID int64) (iw *IssueWatch, exists bool, err error) {
  45. return getIssueWatch(x, userID, issueID)
  46. }
  47. // Return watcher AND explicit non-watcher if entry in db exist
  48. func getIssueWatch(e Engine, userID, issueID int64) (iw *IssueWatch, exists bool, err error) {
  49. iw = new(IssueWatch)
  50. exists, err = e.
  51. Where("user_id = ?", userID).
  52. And("issue_id = ?", issueID).
  53. Get(iw)
  54. return
  55. }
  56. // CheckIssueWatch check if an user is watching an issue
  57. // it takes participants and repo watch into account
  58. func CheckIssueWatch(user *User, issue *Issue) (bool, error) {
  59. iw, exist, err := getIssueWatch(x, user.ID, issue.ID)
  60. if err != nil {
  61. return false, err
  62. }
  63. if exist {
  64. return iw.IsWatching, nil
  65. }
  66. w, err := getWatch(x, user.ID, issue.RepoID)
  67. if err != nil {
  68. return false, err
  69. }
  70. return isWatchMode(w.Mode) || IsUserParticipantsOfIssue(user, issue), nil
  71. }
  72. // GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id
  73. // but avoids joining with `user` for performance reasons
  74. // User permissions must be verified elsewhere if required
  75. func GetIssueWatchersIDs(issueID int64, watching bool) ([]int64, error) {
  76. return getIssueWatchersIDs(x, issueID, watching)
  77. }
  78. func getIssueWatchersIDs(e Engine, issueID int64, watching bool) ([]int64, error) {
  79. ids := make([]int64, 0, 64)
  80. return ids, e.Table("issue_watch").
  81. Where("issue_id=?", issueID).
  82. And("is_watching = ?", watching).
  83. Select("user_id").
  84. Find(&ids)
  85. }
  86. // GetIssueWatchers returns watchers/unwatchers of a given issue
  87. func GetIssueWatchers(issueID int64, listOptions ListOptions) (IssueWatchList, error) {
  88. return getIssueWatchers(x, issueID, listOptions)
  89. }
  90. func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions) (IssueWatchList, error) {
  91. sess := e.
  92. Where("`issue_watch`.issue_id = ?", issueID).
  93. And("`issue_watch`.is_watching = ?", true).
  94. And("`user`.is_active = ?", true).
  95. And("`user`.prohibit_login = ?", false).
  96. Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id")
  97. if listOptions.Page != 0 {
  98. sess = listOptions.setSessionPagination(sess)
  99. watches := make([]*IssueWatch, 0, listOptions.PageSize)
  100. return watches, sess.Find(&watches)
  101. }
  102. watches := make([]*IssueWatch, 0, 8)
  103. return watches, sess.Find(&watches)
  104. }
  105. func removeIssueWatchersByRepoID(e Engine, userID int64, repoID int64) error {
  106. _, err := e.
  107. Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID).
  108. Where("`issue_watch`.user_id = ?", userID).
  109. Delete(new(IssueWatch))
  110. return err
  111. }