gitea/models/conversations/comment_list.go

194 lines
5.0 KiB
Go

// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package conversations
import (
"context"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/container"
)
// CommentList defines a list of comments
type CommentList []*ConversationComment
// LoadPosters loads posters
func (comments CommentList) LoadPosters(ctx context.Context) error {
if len(comments) == 0 {
return nil
}
posterIDs := container.FilterSlice(comments, func(c *ConversationComment) (int64, bool) {
return c.PosterID, c.Poster == nil && c.PosterID > 0
})
posterMaps, err := getPostersByIDs(ctx, posterIDs)
if err != nil {
return err
}
for _, comment := range comments {
if comment.Poster == nil {
comment.Poster = getPoster(comment.PosterID, posterMaps)
}
}
return nil
}
// getConversationIDs returns all the conversation ids on this comment list which conversation hasn't been loaded
func (comments CommentList) getConversationIDs() []int64 {
return container.FilterSlice(comments, func(comment *ConversationComment) (int64, bool) {
return comment.ConversationID, comment.Conversation == nil
})
}
// Conversations returns all the conversations of comments
func (comments CommentList) Conversations() ConversationList {
conversations := make(map[int64]*Conversation, len(comments))
for _, comment := range comments {
if comment.Conversation != nil {
if _, ok := conversations[comment.Conversation.ID]; !ok {
conversations[comment.Conversation.ID] = comment.Conversation
}
}
}
conversationList := make([]*Conversation, 0, len(conversations))
for _, conversation := range conversations {
conversationList = append(conversationList, conversation)
}
return conversationList
}
// LoadConversations loads conversations of comments
func (comments CommentList) LoadConversations(ctx context.Context) error {
if len(comments) == 0 {
return nil
}
conversationIDs := comments.getConversationIDs()
conversations := make(map[int64]*Conversation, len(conversationIDs))
left := len(conversationIDs)
for left > 0 {
limit := db.DefaultMaxInSize
if left < limit {
limit = left
}
rows, err := db.GetEngine(ctx).
In("id", conversationIDs[:limit]).
Rows(new(Conversation))
if err != nil {
return err
}
for rows.Next() {
var conversation Conversation
err = rows.Scan(&conversation)
if err != nil {
rows.Close()
return err
}
conversations[conversation.ID] = &conversation
}
_ = rows.Close()
left -= limit
conversationIDs = conversationIDs[limit:]
}
for _, comment := range comments {
if comment.Conversation == nil {
comment.Conversation = conversations[comment.ConversationID]
}
}
return nil
}
// getAttachmentCommentIDs only return the comment ids which possibly has attachments
func (comments CommentList) getAttachmentCommentIDs() []int64 {
return container.FilterSlice(comments, func(comment *ConversationComment) (int64, bool) {
return comment.ID, comment.Type.HasAttachmentSupport()
})
}
// LoadAttachmentsByConversation loads attachments by conversation id
func (comments CommentList) LoadAttachmentsByConversation(ctx context.Context) error {
if len(comments) == 0 {
return nil
}
attachments := make([]*repo_model.Attachment, 0, len(comments)/2)
if err := db.GetEngine(ctx).Where("conversation_id=? AND comment_id>0", comments[0].ConversationID).Find(&attachments); err != nil {
return err
}
commentAttachmentsMap := make(map[int64][]*repo_model.Attachment, len(comments))
for _, attach := range attachments {
commentAttachmentsMap[attach.CommentID] = append(commentAttachmentsMap[attach.CommentID], attach)
}
for _, comment := range comments {
comment.Attachments = commentAttachmentsMap[comment.ID]
}
return nil
}
// LoadAttachments loads attachments
func (comments CommentList) LoadAttachments(ctx context.Context) (err error) {
if len(comments) == 0 {
return nil
}
attachments := make(map[int64][]*repo_model.Attachment, len(comments))
commentsIDs := comments.getAttachmentCommentIDs()
left := len(commentsIDs)
for left > 0 {
limit := db.DefaultMaxInSize
if left < limit {
limit = left
}
rows, err := db.GetEngine(ctx).
In("comment_id", commentsIDs[:limit]).
Rows(new(repo_model.Attachment))
if err != nil {
return err
}
for rows.Next() {
var attachment repo_model.Attachment
err = rows.Scan(&attachment)
if err != nil {
_ = rows.Close()
return err
}
attachments[attachment.CommentID] = append(attachments[attachment.CommentID], &attachment)
}
_ = rows.Close()
left -= limit
commentsIDs = commentsIDs[limit:]
}
for _, comment := range comments {
comment.Attachments = attachments[comment.ID]
}
return nil
}
// LoadAttributes loads attributes of the comments, except for attachments and
// comments
func (comments CommentList) LoadAttributes(ctx context.Context) (err error) {
if err = comments.LoadPosters(ctx); err != nil {
return err
}
if err = comments.LoadAttachments(ctx); err != nil {
return err
}
return comments.LoadConversations(ctx)
}