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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2018 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 migrations
  5. import (
  6. "code.gitea.io/gitea/modules/setting"
  7. "github.com/go-xorm/xorm"
  8. )
  9. func removeStaleWatches(x *xorm.Engine) error {
  10. type Watch struct {
  11. ID int64
  12. UserID int64
  13. RepoID int64
  14. }
  15. type IssueWatch struct {
  16. ID int64
  17. UserID int64
  18. RepoID int64
  19. IsWatching bool
  20. }
  21. type Repository struct {
  22. ID int64
  23. IsPrivate bool
  24. OwnerID int64
  25. }
  26. type Access struct {
  27. UserID int64
  28. RepoID int64
  29. Mode int
  30. }
  31. const (
  32. // AccessModeNone no access
  33. AccessModeNone int = iota // 0
  34. // AccessModeRead read access
  35. AccessModeRead // 1
  36. )
  37. accessLevel := func(userID int64, repo *Repository) (int, error) {
  38. mode := AccessModeNone
  39. if !repo.IsPrivate {
  40. mode = AccessModeRead
  41. }
  42. if userID == 0 {
  43. return mode, nil
  44. }
  45. if userID == repo.OwnerID {
  46. return 4, nil
  47. }
  48. a := &Access{UserID: userID, RepoID: repo.ID}
  49. if has, err := x.Get(a); !has || err != nil {
  50. return mode, err
  51. }
  52. return a.Mode, nil
  53. }
  54. sess := x.NewSession()
  55. defer sess.Close()
  56. if err := sess.Begin(); err != nil {
  57. return err
  58. }
  59. repoCache := make(map[int64]*Repository)
  60. err := x.BufferSize(setting.IterateBufferSize).Iterate(new(Watch),
  61. func(idx int, bean interface{}) error {
  62. watch := bean.(*Watch)
  63. repo := repoCache[watch.RepoID]
  64. if repo == nil {
  65. repo = &Repository{
  66. ID: watch.RepoID,
  67. }
  68. if _, err := x.Get(repo); err != nil {
  69. return err
  70. }
  71. repoCache[watch.RepoID] = repo
  72. }
  73. // Remove watches from now unaccessible repositories
  74. mode, err := accessLevel(watch.UserID, repo)
  75. if err != nil {
  76. return err
  77. }
  78. has := AccessModeRead <= mode
  79. if has {
  80. return nil
  81. }
  82. if _, err = sess.Delete(&Watch{0, watch.UserID, repo.ID}); err != nil {
  83. return err
  84. }
  85. _, err = sess.Exec("UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?", repo.ID)
  86. return err
  87. })
  88. if err != nil {
  89. return err
  90. }
  91. repoCache = make(map[int64]*Repository)
  92. err = x.BufferSize(setting.IterateBufferSize).
  93. Distinct("issue_watch.user_id", "issue.repo_id").
  94. Join("INNER", "issue", "issue_watch.issue_id = issue.id").
  95. Where("issue_watch.is_watching = ?", true).
  96. Iterate(new(IssueWatch),
  97. func(idx int, bean interface{}) error {
  98. watch := bean.(*IssueWatch)
  99. repo := repoCache[watch.RepoID]
  100. if repo == nil {
  101. repo = &Repository{
  102. ID: watch.RepoID,
  103. }
  104. if _, err := x.Get(repo); err != nil {
  105. return err
  106. }
  107. repoCache[watch.RepoID] = repo
  108. }
  109. // Remove issue watches from now unaccssible repositories
  110. mode, err := accessLevel(watch.UserID, repo)
  111. if err != nil {
  112. return err
  113. }
  114. has := AccessModeRead <= mode
  115. if has {
  116. return nil
  117. }
  118. iw := &IssueWatch{
  119. IsWatching: false,
  120. }
  121. _, err = sess.
  122. Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", watch.RepoID).
  123. Cols("is_watching", "updated_unix").
  124. Where("`issue_watch`.user_id = ?", watch.UserID).
  125. Update(iw)
  126. return err
  127. })
  128. if err != nil {
  129. return err
  130. }
  131. return sess.Commit()
  132. }