migrate from github
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
package comment_service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/XingfenD/yoresee_doc/internal/constant"
|
||||
"github.com/XingfenD/yoresee_doc/internal/domain_event"
|
||||
"github.com/XingfenD/yoresee_doc/internal/dto"
|
||||
"github.com/XingfenD/yoresee_doc/internal/model"
|
||||
"github.com/XingfenD/yoresee_doc/internal/repository"
|
||||
"github.com/XingfenD/yoresee_doc/internal/repository/comment_repo"
|
||||
"github.com/XingfenD/yoresee_doc/internal/repository/document_repo"
|
||||
"github.com/XingfenD/yoresee_doc/internal/repository/knowledge_base_repo"
|
||||
"github.com/XingfenD/yoresee_doc/internal/repository/user_repo"
|
||||
"github.com/XingfenD/yoresee_doc/internal/status"
|
||||
"github.com/XingfenD/yoresee_doc/internal/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type CommentService struct {
|
||||
commentRepo *comment_repo.CommentRepository
|
||||
documentRepo *document_repo.DocumentRepository
|
||||
userRepo *user_repo.UserRepository
|
||||
kbRepo *knowledge_base_repo.KnowledgeBaseRepository
|
||||
}
|
||||
|
||||
func NewCommentService(repos *repository.Repositories) *CommentService {
|
||||
return &CommentService{
|
||||
commentRepo: repos.Comment,
|
||||
documentRepo: repos.Document,
|
||||
userRepo: repos.User,
|
||||
kbRepo: repos.KnowledgeBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CommentService) CreateComment(req *dto.CreateCommentRequest) (*model.DocumentComment, error) {
|
||||
if req == nil || strings.TrimSpace(req.DocumentExternalID) == "" || strings.TrimSpace(req.Content) == "" {
|
||||
return nil, status.StatusParamError
|
||||
}
|
||||
if strings.TrimSpace(req.CreatorExternalID) == "" {
|
||||
return nil, status.StatusTokenInvalid
|
||||
}
|
||||
doc, err := s.documentRepo.GetByExternalID(req.DocumentExternalID).Exec(context.Background())
|
||||
if err != nil || doc == nil {
|
||||
return nil, status.StatusDocumentNotFound
|
||||
}
|
||||
|
||||
creatorID, err := s.userRepo.GetIDByExternalID(req.CreatorExternalID).Exec()
|
||||
if err != nil {
|
||||
return nil, status.StatusUserNotFound
|
||||
}
|
||||
|
||||
parentID := int64(0)
|
||||
var parentComment *model.DocumentComment
|
||||
if req.ParentExternalID != nil && strings.TrimSpace(*req.ParentExternalID) != "" {
|
||||
parent, err := s.commentRepo.GetByExternalID(*req.ParentExternalID).Exec()
|
||||
if err != nil || parent == nil {
|
||||
return nil, status.StatusReadDBError
|
||||
}
|
||||
parentID = parent.ID
|
||||
parentComment = parent
|
||||
}
|
||||
|
||||
item := &model.DocumentComment{
|
||||
ExternalID: utils.GenerateExternalID(utils.ExternalIDContextComment),
|
||||
DocumentID: doc.ID,
|
||||
ParentID: parentID,
|
||||
CreatorID: creatorID,
|
||||
Content: req.Content,
|
||||
}
|
||||
if req.AnchorID != nil && strings.TrimSpace(*req.AnchorID) != "" {
|
||||
item.AnchorID = strings.TrimSpace(*req.AnchorID)
|
||||
} else if parentComment != nil && strings.TrimSpace(parentComment.AnchorID) != "" {
|
||||
item.AnchorID = parentComment.AnchorID
|
||||
}
|
||||
if strings.TrimSpace(item.AnchorID) == "" {
|
||||
return nil, status.StatusParamError
|
||||
}
|
||||
if err := s.commentRepo.Create(item).Exec(); err != nil {
|
||||
return nil, status.StatusWriteDBError
|
||||
}
|
||||
|
||||
notifyQuote := ""
|
||||
if req.Quote != nil {
|
||||
notifyQuote = strings.TrimSpace(*req.Quote)
|
||||
}
|
||||
s.notifyCommentTargets(doc, item, parentComment, notifyQuote, req.MentionedUserExternalIDs)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (s *CommentService) ListComments(req *dto.ListCommentsRequest) ([]model.DocumentComment, int64, error) {
|
||||
if req == nil || strings.TrimSpace(req.DocumentExternalID) == "" {
|
||||
return nil, 0, status.StatusParamError
|
||||
}
|
||||
doc, err := s.documentRepo.GetByExternalID(req.DocumentExternalID).Exec(context.Background())
|
||||
if err != nil || doc == nil {
|
||||
return nil, 0, status.StatusDocumentNotFound
|
||||
}
|
||||
op := s.commentRepo.ListByDocument(doc.ID).
|
||||
WithPagination(req.Page, req.PageSize)
|
||||
list, total, err := op.ExecWithTotal()
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: CommentService] list comments failed, document_external_id=%s, err=%+v", req.DocumentExternalID, err)
|
||||
return nil, 0, status.GenErrWithCustomMsg(status.StatusReadDBError, "list comments failed")
|
||||
}
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
func (s *CommentService) DeleteComment(req *dto.DeleteCommentRequest, isAdmin bool) error {
|
||||
if req == nil || strings.TrimSpace(req.ExternalID) == "" {
|
||||
return status.StatusParamError
|
||||
}
|
||||
comment, err := s.commentRepo.GetByExternalID(req.ExternalID).Exec()
|
||||
if err != nil || comment == nil {
|
||||
return status.StatusReadDBError
|
||||
}
|
||||
if !isAdmin {
|
||||
operatorID, err := s.userRepo.GetIDByExternalID(req.OperatorExternalID).Exec()
|
||||
if err != nil {
|
||||
return status.StatusUserNotFound
|
||||
}
|
||||
if operatorID != comment.CreatorID {
|
||||
return status.StatusPermissionDenied
|
||||
}
|
||||
}
|
||||
if err := s.commentRepo.Delete(comment.ID).Exec(); err != nil {
|
||||
return status.StatusWriteDBError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CommentService) UpdateComment(req *dto.UpdateCommentRequest, isAdmin bool) (*model.DocumentComment, error) {
|
||||
if req == nil || strings.TrimSpace(req.ExternalID) == "" || strings.TrimSpace(req.Content) == "" {
|
||||
return nil, status.StatusParamError
|
||||
}
|
||||
comment, err := s.commentRepo.GetByExternalID(req.ExternalID).Exec()
|
||||
if err != nil || comment == nil {
|
||||
return nil, status.StatusReadDBError
|
||||
}
|
||||
if !isAdmin {
|
||||
operatorID, err := s.userRepo.GetIDByExternalID(req.OperatorExternalID).Exec()
|
||||
if err != nil {
|
||||
return nil, status.StatusUserNotFound
|
||||
}
|
||||
if operatorID != comment.CreatorID {
|
||||
return nil, status.StatusPermissionDenied
|
||||
}
|
||||
}
|
||||
if err := s.commentRepo.UpdateContentByID(comment.ID, req.Content).Exec(); err != nil {
|
||||
return nil, status.StatusWriteDBError
|
||||
}
|
||||
comment.Content = req.Content
|
||||
return comment, nil
|
||||
}
|
||||
|
||||
var CommentSvc *CommentService
|
||||
|
||||
func (s *CommentService) notifyCommentTargets(doc *model.Document, comment *model.DocumentComment, parent *model.DocumentComment, quote string, mentionedUserExternalIDs []string) {
|
||||
if doc == nil || comment == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve knowledge base external ID for navigation payload
|
||||
kbExternalID := ""
|
||||
if doc.KnowledgeID != nil && *doc.KnowledgeID != 0 {
|
||||
kb, err := s.kbRepo.GetByID(*doc.KnowledgeID).Exec()
|
||||
if err == nil && kb != nil {
|
||||
kbExternalID = kb.ExternalID
|
||||
}
|
||||
}
|
||||
|
||||
parentExternalID := ""
|
||||
if parent != nil && parent.ID != 0 {
|
||||
parentExternalID = parent.ExternalID
|
||||
}
|
||||
|
||||
payloadBase := map[string]any{
|
||||
"document_external_id": doc.ExternalID,
|
||||
"comment_external_id": comment.ExternalID,
|
||||
"document_title": doc.Title,
|
||||
"parent_comment_external_id": parentExternalID,
|
||||
"knowledge_base_external_id": kbExternalID,
|
||||
"mentioned_user_external_ids": mentionedUserExternalIDs,
|
||||
}
|
||||
payloadJSON, _ := json.Marshal(payloadBase)
|
||||
payloadStr := string(payloadJSON)
|
||||
|
||||
publish := func(receivers []string, notifType, title string) {
|
||||
if len(receivers) == 0 {
|
||||
return
|
||||
}
|
||||
evt := domain_event.NotificationCreateEvent{
|
||||
ReceiverExternalIDs: receivers,
|
||||
Type: notifType,
|
||||
Title: title,
|
||||
Content: comment.Content,
|
||||
PayloadJSON: payloadStr,
|
||||
}
|
||||
if err := domain_event.PublishNotificationCreateEvent(context.Background(), evt); err != nil {
|
||||
logrus.Errorf("publish %s notification failed: %v", notifType, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Build mention receiver set (highest priority — skip for other types)
|
||||
mentionSet := map[string]struct{}{}
|
||||
for _, id := range mentionedUserExternalIDs {
|
||||
id = strings.TrimSpace(id)
|
||||
if id != "" && id != comment.ExternalID {
|
||||
mentionSet[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Build reply receivers (parent comment creator, excluding commenter and mention receivers)
|
||||
var replyReceivers []string
|
||||
if parent != nil && parent.ID != 0 {
|
||||
parentCreator, err := s.userRepo.GetByID(parent.CreatorID).Exec()
|
||||
if err == nil && parentCreator != nil {
|
||||
id := strings.TrimSpace(parentCreator.ExternalID)
|
||||
if id != "" && parentCreator.ID != comment.CreatorID {
|
||||
if _, isMentioned := mentionSet[id]; !isMentioned {
|
||||
replyReceivers = append(replyReceivers, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build comment receivers (document owner, excluding commenter, reply receivers, and mention receivers)
|
||||
replySet := map[string]struct{}{}
|
||||
for _, id := range replyReceivers {
|
||||
replySet[id] = struct{}{}
|
||||
}
|
||||
var commentReceivers []string
|
||||
if doc.UserID != comment.CreatorID {
|
||||
owner, err := s.userRepo.GetByID(doc.UserID).Exec()
|
||||
if err == nil && owner != nil {
|
||||
id := strings.TrimSpace(owner.ExternalID)
|
||||
if id != "" {
|
||||
if _, isMentioned := mentionSet[id]; !isMentioned {
|
||||
if _, isReply := replySet[id]; !isReply {
|
||||
commentReceivers = append(commentReceivers, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mentionReceivers := make([]string, 0, len(mentionSet))
|
||||
for id := range mentionSet {
|
||||
mentionReceivers = append(mentionReceivers, id)
|
||||
}
|
||||
|
||||
publish(mentionReceivers, constant.NotificationType_Mention, constant.GetNotificationTitle(constant.NotificationType_Mention))
|
||||
publish(replyReceivers, constant.NotificationType_Reply, constant.GetNotificationTitle(constant.NotificationType_Reply))
|
||||
publish(commentReceivers, constant.NotificationType_Comment, constant.GetNotificationTitle(constant.NotificationType_Comment))
|
||||
}
|
||||
Reference in New Issue
Block a user