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_assignees.go 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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 models
  5. import (
  6. "fmt"
  7. "code.gitea.io/gitea/models/db"
  8. "code.gitea.io/gitea/modules/util"
  9. "xorm.io/xorm"
  10. )
  11. // IssueAssignees saves all issue assignees
  12. type IssueAssignees struct {
  13. ID int64 `xorm:"pk autoincr"`
  14. AssigneeID int64 `xorm:"INDEX"`
  15. IssueID int64 `xorm:"INDEX"`
  16. }
  17. func init() {
  18. db.RegisterModel(new(IssueAssignees))
  19. }
  20. // LoadAssignees load assignees of this issue.
  21. func (issue *Issue) LoadAssignees() error {
  22. return issue.loadAssignees(db.GetEngine(db.DefaultContext))
  23. }
  24. // This loads all assignees of an issue
  25. func (issue *Issue) loadAssignees(e db.Engine) (err error) {
  26. // Reset maybe preexisting assignees
  27. issue.Assignees = []*User{}
  28. err = e.Table("`user`").
  29. Join("INNER", "issue_assignees", "assignee_id = `user`.id").
  30. Where("issue_assignees.issue_id = ?", issue.ID).
  31. Find(&issue.Assignees)
  32. if err != nil {
  33. return err
  34. }
  35. // Check if we have at least one assignee and if yes put it in as `Assignee`
  36. if len(issue.Assignees) > 0 {
  37. issue.Assignee = issue.Assignees[0]
  38. }
  39. return
  40. }
  41. // GetAssigneeIDsByIssue returns the IDs of users assigned to an issue
  42. // but skips joining with `user` for performance reasons.
  43. // User permissions must be verified elsewhere if required.
  44. func GetAssigneeIDsByIssue(issueID int64) ([]int64, error) {
  45. userIDs := make([]int64, 0, 5)
  46. return userIDs, db.GetEngine(db.DefaultContext).Table("issue_assignees").
  47. Cols("assignee_id").
  48. Where("issue_id = ?", issueID).
  49. Distinct("assignee_id").
  50. Find(&userIDs)
  51. }
  52. // GetAssigneesByIssue returns everyone assigned to that issue
  53. func GetAssigneesByIssue(issue *Issue) (assignees []*User, err error) {
  54. return getAssigneesByIssue(db.GetEngine(db.DefaultContext), issue)
  55. }
  56. func getAssigneesByIssue(e db.Engine, issue *Issue) (assignees []*User, err error) {
  57. err = issue.loadAssignees(e)
  58. if err != nil {
  59. return assignees, err
  60. }
  61. return issue.Assignees, nil
  62. }
  63. // IsUserAssignedToIssue returns true when the user is assigned to the issue
  64. func IsUserAssignedToIssue(issue *Issue, user *User) (isAssigned bool, err error) {
  65. return isUserAssignedToIssue(db.GetEngine(db.DefaultContext), issue, user)
  66. }
  67. func isUserAssignedToIssue(e db.Engine, issue *Issue, user *User) (isAssigned bool, err error) {
  68. return e.Get(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID})
  69. }
  70. // ClearAssigneeByUserID deletes all assignments of an user
  71. func clearAssigneeByUserID(sess db.Engine, userID int64) (err error) {
  72. _, err = sess.Delete(&IssueAssignees{AssigneeID: userID})
  73. return
  74. }
  75. // ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it.
  76. func (issue *Issue) ToggleAssignee(doer *User, assigneeID int64) (removed bool, comment *Comment, err error) {
  77. sess := db.NewSession(db.DefaultContext)
  78. defer sess.Close()
  79. if err := sess.Begin(); err != nil {
  80. return false, nil, err
  81. }
  82. removed, comment, err = issue.toggleAssignee(sess, doer, assigneeID, false)
  83. if err != nil {
  84. return false, nil, err
  85. }
  86. if err := sess.Commit(); err != nil {
  87. return false, nil, err
  88. }
  89. return removed, comment, nil
  90. }
  91. func (issue *Issue) toggleAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (removed bool, comment *Comment, err error) {
  92. removed, err = toggleUserAssignee(sess, issue, assigneeID)
  93. if err != nil {
  94. return false, nil, fmt.Errorf("UpdateIssueUserByAssignee: %v", err)
  95. }
  96. // Repo infos
  97. if err = issue.loadRepo(sess); err != nil {
  98. return false, nil, fmt.Errorf("loadRepo: %v", err)
  99. }
  100. opts := &CreateCommentOptions{
  101. Type: CommentTypeAssignees,
  102. Doer: doer,
  103. Repo: issue.Repo,
  104. Issue: issue,
  105. RemovedAssignee: removed,
  106. AssigneeID: assigneeID,
  107. }
  108. // Comment
  109. comment, err = createComment(sess, opts)
  110. if err != nil {
  111. return false, nil, fmt.Errorf("createComment: %v", err)
  112. }
  113. // if pull request is in the middle of creation - don't call webhook
  114. if isCreate {
  115. return removed, comment, err
  116. }
  117. return removed, comment, nil
  118. }
  119. // toggles user assignee state in database
  120. func toggleUserAssignee(e *xorm.Session, issue *Issue, assigneeID int64) (removed bool, err error) {
  121. // Check if the user exists
  122. assignee, err := getUserByID(e, assigneeID)
  123. if err != nil {
  124. return false, err
  125. }
  126. // Check if the submitted user is already assigned, if yes delete him otherwise add him
  127. var i int
  128. for i = 0; i < len(issue.Assignees); i++ {
  129. if issue.Assignees[i].ID == assigneeID {
  130. break
  131. }
  132. }
  133. assigneeIn := IssueAssignees{AssigneeID: assigneeID, IssueID: issue.ID}
  134. toBeDeleted := i < len(issue.Assignees)
  135. if toBeDeleted {
  136. issue.Assignees = append(issue.Assignees[:i], issue.Assignees[i:]...)
  137. _, err = e.Delete(assigneeIn)
  138. if err != nil {
  139. return toBeDeleted, err
  140. }
  141. } else {
  142. issue.Assignees = append(issue.Assignees, assignee)
  143. _, err = e.Insert(assigneeIn)
  144. if err != nil {
  145. return toBeDeleted, err
  146. }
  147. }
  148. return toBeDeleted, nil
  149. }
  150. // MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs
  151. func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) {
  152. var requestAssignees []string
  153. // Keeping the old assigning method for compatibility reasons
  154. if oneAssignee != "" && !util.IsStringInSlice(oneAssignee, multipleAssignees) {
  155. requestAssignees = append(requestAssignees, oneAssignee)
  156. }
  157. // Prevent empty assignees
  158. if len(multipleAssignees) > 0 && multipleAssignees[0] != "" {
  159. requestAssignees = append(requestAssignees, multipleAssignees...)
  160. }
  161. // Get the IDs of all assignees
  162. assigneeIDs, err = GetUserIDsByNames(requestAssignees, false)
  163. return
  164. }