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_comment_list.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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. "code.gitea.io/gitea/models/db"
  7. repo_model "code.gitea.io/gitea/models/repo"
  8. )
  9. // CommentList defines a list of comments
  10. type CommentList []*Comment
  11. func (comments CommentList) getPosterIDs() []int64 {
  12. posterIDs := make(map[int64]struct{}, len(comments))
  13. for _, comment := range comments {
  14. if _, ok := posterIDs[comment.PosterID]; !ok {
  15. posterIDs[comment.PosterID] = struct{}{}
  16. }
  17. }
  18. return keysInt64(posterIDs)
  19. }
  20. func (comments CommentList) loadPosters(e db.Engine) error {
  21. if len(comments) == 0 {
  22. return nil
  23. }
  24. posterIDs := comments.getPosterIDs()
  25. posterMaps := make(map[int64]*User, len(posterIDs))
  26. left := len(posterIDs)
  27. for left > 0 {
  28. limit := defaultMaxInSize
  29. if left < limit {
  30. limit = left
  31. }
  32. err := e.
  33. In("id", posterIDs[:limit]).
  34. Find(&posterMaps)
  35. if err != nil {
  36. return err
  37. }
  38. left -= limit
  39. posterIDs = posterIDs[limit:]
  40. }
  41. for _, comment := range comments {
  42. if comment.PosterID <= 0 {
  43. continue
  44. }
  45. var ok bool
  46. if comment.Poster, ok = posterMaps[comment.PosterID]; !ok {
  47. comment.Poster = NewGhostUser()
  48. }
  49. }
  50. return nil
  51. }
  52. func (comments CommentList) getCommentIDs() []int64 {
  53. ids := make([]int64, 0, len(comments))
  54. for _, comment := range comments {
  55. ids = append(ids, comment.ID)
  56. }
  57. return ids
  58. }
  59. func (comments CommentList) getLabelIDs() []int64 {
  60. ids := make(map[int64]struct{}, len(comments))
  61. for _, comment := range comments {
  62. if _, ok := ids[comment.LabelID]; !ok {
  63. ids[comment.LabelID] = struct{}{}
  64. }
  65. }
  66. return keysInt64(ids)
  67. }
  68. func (comments CommentList) loadLabels(e db.Engine) error {
  69. if len(comments) == 0 {
  70. return nil
  71. }
  72. labelIDs := comments.getLabelIDs()
  73. commentLabels := make(map[int64]*Label, len(labelIDs))
  74. left := len(labelIDs)
  75. for left > 0 {
  76. limit := defaultMaxInSize
  77. if left < limit {
  78. limit = left
  79. }
  80. rows, err := e.
  81. In("id", labelIDs[:limit]).
  82. Rows(new(Label))
  83. if err != nil {
  84. return err
  85. }
  86. for rows.Next() {
  87. var label Label
  88. err = rows.Scan(&label)
  89. if err != nil {
  90. _ = rows.Close()
  91. return err
  92. }
  93. commentLabels[label.ID] = &label
  94. }
  95. _ = rows.Close()
  96. left -= limit
  97. labelIDs = labelIDs[limit:]
  98. }
  99. for _, comment := range comments {
  100. comment.Label = commentLabels[comment.ID]
  101. }
  102. return nil
  103. }
  104. func (comments CommentList) getMilestoneIDs() []int64 {
  105. ids := make(map[int64]struct{}, len(comments))
  106. for _, comment := range comments {
  107. if _, ok := ids[comment.MilestoneID]; !ok {
  108. ids[comment.MilestoneID] = struct{}{}
  109. }
  110. }
  111. return keysInt64(ids)
  112. }
  113. func (comments CommentList) loadMilestones(e db.Engine) error {
  114. if len(comments) == 0 {
  115. return nil
  116. }
  117. milestoneIDs := comments.getMilestoneIDs()
  118. if len(milestoneIDs) == 0 {
  119. return nil
  120. }
  121. milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
  122. left := len(milestoneIDs)
  123. for left > 0 {
  124. limit := defaultMaxInSize
  125. if left < limit {
  126. limit = left
  127. }
  128. err := e.
  129. In("id", milestoneIDs[:limit]).
  130. Find(&milestoneMaps)
  131. if err != nil {
  132. return err
  133. }
  134. left -= limit
  135. milestoneIDs = milestoneIDs[limit:]
  136. }
  137. for _, issue := range comments {
  138. issue.Milestone = milestoneMaps[issue.MilestoneID]
  139. }
  140. return nil
  141. }
  142. func (comments CommentList) getOldMilestoneIDs() []int64 {
  143. ids := make(map[int64]struct{}, len(comments))
  144. for _, comment := range comments {
  145. if _, ok := ids[comment.OldMilestoneID]; !ok {
  146. ids[comment.OldMilestoneID] = struct{}{}
  147. }
  148. }
  149. return keysInt64(ids)
  150. }
  151. func (comments CommentList) loadOldMilestones(e db.Engine) error {
  152. if len(comments) == 0 {
  153. return nil
  154. }
  155. milestoneIDs := comments.getOldMilestoneIDs()
  156. if len(milestoneIDs) == 0 {
  157. return nil
  158. }
  159. milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
  160. left := len(milestoneIDs)
  161. for left > 0 {
  162. limit := defaultMaxInSize
  163. if left < limit {
  164. limit = left
  165. }
  166. err := e.
  167. In("id", milestoneIDs[:limit]).
  168. Find(&milestoneMaps)
  169. if err != nil {
  170. return err
  171. }
  172. left -= limit
  173. milestoneIDs = milestoneIDs[limit:]
  174. }
  175. for _, issue := range comments {
  176. issue.OldMilestone = milestoneMaps[issue.MilestoneID]
  177. }
  178. return nil
  179. }
  180. func (comments CommentList) getAssigneeIDs() []int64 {
  181. ids := make(map[int64]struct{}, len(comments))
  182. for _, comment := range comments {
  183. if _, ok := ids[comment.AssigneeID]; !ok {
  184. ids[comment.AssigneeID] = struct{}{}
  185. }
  186. }
  187. return keysInt64(ids)
  188. }
  189. func (comments CommentList) loadAssignees(e db.Engine) error {
  190. if len(comments) == 0 {
  191. return nil
  192. }
  193. assigneeIDs := comments.getAssigneeIDs()
  194. assignees := make(map[int64]*User, len(assigneeIDs))
  195. left := len(assigneeIDs)
  196. for left > 0 {
  197. limit := defaultMaxInSize
  198. if left < limit {
  199. limit = left
  200. }
  201. rows, err := e.
  202. In("id", assigneeIDs[:limit]).
  203. Rows(new(User))
  204. if err != nil {
  205. return err
  206. }
  207. for rows.Next() {
  208. var user User
  209. err = rows.Scan(&user)
  210. if err != nil {
  211. rows.Close()
  212. return err
  213. }
  214. assignees[user.ID] = &user
  215. }
  216. _ = rows.Close()
  217. left -= limit
  218. assigneeIDs = assigneeIDs[limit:]
  219. }
  220. for _, comment := range comments {
  221. comment.Assignee = assignees[comment.AssigneeID]
  222. }
  223. return nil
  224. }
  225. // getIssueIDs returns all the issue ids on this comment list which issue hasn't been loaded
  226. func (comments CommentList) getIssueIDs() []int64 {
  227. ids := make(map[int64]struct{}, len(comments))
  228. for _, comment := range comments {
  229. if comment.Issue != nil {
  230. continue
  231. }
  232. if _, ok := ids[comment.IssueID]; !ok {
  233. ids[comment.IssueID] = struct{}{}
  234. }
  235. }
  236. return keysInt64(ids)
  237. }
  238. // Issues returns all the issues of comments
  239. func (comments CommentList) Issues() IssueList {
  240. issues := make(map[int64]*Issue, len(comments))
  241. for _, comment := range comments {
  242. if comment.Issue != nil {
  243. if _, ok := issues[comment.Issue.ID]; !ok {
  244. issues[comment.Issue.ID] = comment.Issue
  245. }
  246. }
  247. }
  248. issueList := make([]*Issue, 0, len(issues))
  249. for _, issue := range issues {
  250. issueList = append(issueList, issue)
  251. }
  252. return issueList
  253. }
  254. func (comments CommentList) loadIssues(e db.Engine) error {
  255. if len(comments) == 0 {
  256. return nil
  257. }
  258. issueIDs := comments.getIssueIDs()
  259. issues := make(map[int64]*Issue, len(issueIDs))
  260. left := len(issueIDs)
  261. for left > 0 {
  262. limit := defaultMaxInSize
  263. if left < limit {
  264. limit = left
  265. }
  266. rows, err := e.
  267. In("id", issueIDs[:limit]).
  268. Rows(new(Issue))
  269. if err != nil {
  270. return err
  271. }
  272. for rows.Next() {
  273. var issue Issue
  274. err = rows.Scan(&issue)
  275. if err != nil {
  276. rows.Close()
  277. return err
  278. }
  279. issues[issue.ID] = &issue
  280. }
  281. _ = rows.Close()
  282. left -= limit
  283. issueIDs = issueIDs[limit:]
  284. }
  285. for _, comment := range comments {
  286. if comment.Issue == nil {
  287. comment.Issue = issues[comment.IssueID]
  288. }
  289. }
  290. return nil
  291. }
  292. func (comments CommentList) getDependentIssueIDs() []int64 {
  293. ids := make(map[int64]struct{}, len(comments))
  294. for _, comment := range comments {
  295. if comment.DependentIssue != nil {
  296. continue
  297. }
  298. if _, ok := ids[comment.DependentIssueID]; !ok {
  299. ids[comment.DependentIssueID] = struct{}{}
  300. }
  301. }
  302. return keysInt64(ids)
  303. }
  304. func (comments CommentList) loadDependentIssues(e db.Engine) error {
  305. if len(comments) == 0 {
  306. return nil
  307. }
  308. issueIDs := comments.getDependentIssueIDs()
  309. issues := make(map[int64]*Issue, len(issueIDs))
  310. left := len(issueIDs)
  311. for left > 0 {
  312. limit := defaultMaxInSize
  313. if left < limit {
  314. limit = left
  315. }
  316. rows, err := e.
  317. In("id", issueIDs[:limit]).
  318. Rows(new(Issue))
  319. if err != nil {
  320. return err
  321. }
  322. for rows.Next() {
  323. var issue Issue
  324. err = rows.Scan(&issue)
  325. if err != nil {
  326. _ = rows.Close()
  327. return err
  328. }
  329. issues[issue.ID] = &issue
  330. }
  331. _ = rows.Close()
  332. left -= limit
  333. issueIDs = issueIDs[limit:]
  334. }
  335. for _, comment := range comments {
  336. if comment.DependentIssue == nil {
  337. comment.DependentIssue = issues[comment.DependentIssueID]
  338. if comment.DependentIssue != nil {
  339. if err := comment.DependentIssue.loadRepo(e); err != nil {
  340. return err
  341. }
  342. }
  343. }
  344. }
  345. return nil
  346. }
  347. func (comments CommentList) loadAttachments(e db.Engine) (err error) {
  348. if len(comments) == 0 {
  349. return nil
  350. }
  351. attachments := make(map[int64][]*repo_model.Attachment, len(comments))
  352. commentsIDs := comments.getCommentIDs()
  353. left := len(commentsIDs)
  354. for left > 0 {
  355. limit := defaultMaxInSize
  356. if left < limit {
  357. limit = left
  358. }
  359. rows, err := e.Table("attachment").
  360. Join("INNER", "comment", "comment.id = attachment.comment_id").
  361. In("comment.id", commentsIDs[:limit]).
  362. Rows(new(repo_model.Attachment))
  363. if err != nil {
  364. return err
  365. }
  366. for rows.Next() {
  367. var attachment repo_model.Attachment
  368. err = rows.Scan(&attachment)
  369. if err != nil {
  370. _ = rows.Close()
  371. return err
  372. }
  373. attachments[attachment.CommentID] = append(attachments[attachment.CommentID], &attachment)
  374. }
  375. _ = rows.Close()
  376. left -= limit
  377. commentsIDs = commentsIDs[limit:]
  378. }
  379. for _, comment := range comments {
  380. comment.Attachments = attachments[comment.ID]
  381. }
  382. return nil
  383. }
  384. func (comments CommentList) getReviewIDs() []int64 {
  385. ids := make(map[int64]struct{}, len(comments))
  386. for _, comment := range comments {
  387. if _, ok := ids[comment.ReviewID]; !ok {
  388. ids[comment.ReviewID] = struct{}{}
  389. }
  390. }
  391. return keysInt64(ids)
  392. }
  393. func (comments CommentList) loadReviews(e db.Engine) error {
  394. if len(comments) == 0 {
  395. return nil
  396. }
  397. reviewIDs := comments.getReviewIDs()
  398. reviews := make(map[int64]*Review, len(reviewIDs))
  399. left := len(reviewIDs)
  400. for left > 0 {
  401. limit := defaultMaxInSize
  402. if left < limit {
  403. limit = left
  404. }
  405. rows, err := e.
  406. In("id", reviewIDs[:limit]).
  407. Rows(new(Review))
  408. if err != nil {
  409. return err
  410. }
  411. for rows.Next() {
  412. var review Review
  413. err = rows.Scan(&review)
  414. if err != nil {
  415. _ = rows.Close()
  416. return err
  417. }
  418. reviews[review.ID] = &review
  419. }
  420. _ = rows.Close()
  421. left -= limit
  422. reviewIDs = reviewIDs[limit:]
  423. }
  424. for _, comment := range comments {
  425. comment.Review = reviews[comment.ReviewID]
  426. }
  427. return nil
  428. }
  429. // loadAttributes loads all attributes
  430. func (comments CommentList) loadAttributes(e db.Engine) (err error) {
  431. if err = comments.loadPosters(e); err != nil {
  432. return
  433. }
  434. if err = comments.loadLabels(e); err != nil {
  435. return
  436. }
  437. if err = comments.loadMilestones(e); err != nil {
  438. return
  439. }
  440. if err = comments.loadOldMilestones(e); err != nil {
  441. return
  442. }
  443. if err = comments.loadAssignees(e); err != nil {
  444. return
  445. }
  446. if err = comments.loadAttachments(e); err != nil {
  447. return
  448. }
  449. if err = comments.loadReviews(e); err != nil {
  450. return
  451. }
  452. if err = comments.loadIssues(e); err != nil {
  453. return
  454. }
  455. if err = comments.loadDependentIssues(e); err != nil {
  456. return
  457. }
  458. return nil
  459. }
  460. // LoadAttributes loads attributes of the comments, except for attachments and
  461. // comments
  462. func (comments CommentList) LoadAttributes() error {
  463. return comments.loadAttributes(db.GetEngine(db.DefaultContext))
  464. }
  465. // LoadAttachments loads attachments
  466. func (comments CommentList) LoadAttachments() error {
  467. return comments.loadAttachments(db.GetEngine(db.DefaultContext))
  468. }
  469. // LoadPosters loads posters
  470. func (comments CommentList) LoadPosters() error {
  471. return comments.loadPosters(db.GetEngine(db.DefaultContext))
  472. }
  473. // LoadIssues loads issues of comments
  474. func (comments CommentList) LoadIssues() error {
  475. return comments.loadIssues(db.GetEngine(db.DefaultContext))
  476. }