package usecase import ( "context" "encoding/base64" "fmt" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/comment" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/entity" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/repository" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/usecase" "github.com/golang/snappy" "github.com/zeromicro/go-zero/core/logx" "code.30cm.net/digimon/library-go/errs" "code.30cm.net/digimon/library-go/errs/code" ) type CommentUseCaseParam struct { Comment repository.CommentRepository } type CommentUseCase struct { CommentUseCaseParam } func MustCommentUseCase(param CommentUseCaseParam) usecase.CommentUseCase { return &CommentUseCase{ param, } } func (use *CommentUseCase) CreateCommentItem(ctx context.Context, info usecase.CreateCommentDocs) error { insert := &entity.Comments{ UID: info.UID, ReferenceID: info.ReferenceID, Level: comment.TopLevelComment, } snappyContent := snappy.Encode(nil, []byte(info.Message)) insert.Message = base64.StdEncoding.EncodeToString(snappyContent) if info.ParentCommentID != "" { insert.ParentCommentID = info.ParentCommentID insert.Level = comment.SubLevelComment } err := use.Comment.CreateComment(ctx, insert) if err != nil { return errs.DatabaseErrorWithScopeL( code.CloudEPComment, domain.CreateCommentErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "info", Value: info}, {Key: "func", Value: "Comment.CreateComment"}, {Key: "err", Value: err.Error()}, }, "failed to create comment").Wrap(err) } return nil } func (use *CommentUseCase) GetCommentItem(ctx context.Context, id string) (*usecase.CommentDocs, error) { item, _, err := use.Comment.ListComments(ctx, repository.ListCommentRequest{ ReferenceID: &id, PageIndex: 1, PageSize: 20, }) if err != nil { return nil, errs.DatabaseErrorWithScopeL( code.CloudEPComment, domain.GetCommentErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "id", Value: id}, {Key: "func", Value: "Comment.ListComments"}, {Key: "err", Value: err.Error()}, }, "failed to get comment").Wrap(err) } decodeB64Content, _ := base64.StdEncoding.DecodeString(item[0].Message) snappyContent, _ := snappy.Decode(nil, decodeB64Content) item[0].Message = string(snappyContent) return &usecase.CommentDocs{ ID: item[0].ID.Hex(), UID: item[0].UID, ReferenceID: item[0].ReferenceID, ParentCommentID: item[0].ParentCommentID, Message: item[0].Message, UpdatedAt: item[0].UpdatedAt, CreatedAt: item[0].CreatedAt, }, nil } func (use *CommentUseCase) UpdateCommentMessage(ctx context.Context, id string, message string) error { err := use.Comment.UpdateCommentMessage(ctx, id, message) if err != nil { return errs.DatabaseErrorWithScopeL( code.CloudEPComment, domain.UpdateCommentErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "id", Value: id}, {Key: "func", Value: "Comment.UpdateCommentMessage"}, {Key: "err", Value: err.Error()}, }, "failed to update comment").Wrap(err) } return nil } func (use *CommentUseCase) RemoveCommentItem(ctx context.Context, id string) error { // 也需要把子留言給刪除 err := use.Comment.DeleteCommentByID(ctx, id) if err != nil { return errs.DatabaseErrorWithScopeL( code.CloudEPComment, domain.DelCommentErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "id", Value: id}, {Key: "func", Value: "Comment.DeleteCommentByID"}, {Key: "err", Value: err.Error()}, }, "failed to del comment").Wrap(err) } return nil } func (use *CommentUseCase) ListComment(ctx context.Context, req usecase.ListCommentRequest) ([]*usecase.CommentDocs, int64, error) { // 查詢主層留言 comments, total, err := use.Comment.ListComments(ctx, repository.ListCommentRequest{ ParentID: req.ParentID, PageSize: req.PageSize, PageIndex: req.PageIndex, ReferenceID: req.ReferenceID, }) if err != nil { return nil, 0, errs.DatabaseErrorWithScopeL( code.CloudEPComment, domain.ListCommentErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "req", Value: req}, {Key: "func", Value: "Comment.ListComments"}, {Key: "err", Value: err.Error()}, }, "failed to list comment").Wrap(err) } // 批量構建子留言 replyMap := use.buildReplies(ctx, comments) // 組裝結果 results := make([]*usecase.CommentDocs, 0, len(comments)) for _, item := range comments { decodedMessage, err := decodeMessage(item.Message) if err != nil { logx.WithContext(ctx).Errorf("Failed to decode message: %v", err) continue } results = append(results, &usecase.CommentDocs{ ID: item.ID.Hex(), UID: item.UID, ReferenceID: item.ReferenceID, ParentCommentID: item.ParentCommentID, Message: decodedMessage, UpdatedAt: item.UpdatedAt, CreatedAt: item.CreatedAt, Replies: replyMap[item.ID.Hex()], }) } return results, total, nil } func (use *CommentUseCase) buildReplies(ctx context.Context, parentComments []*entity.Comments) map[string][]*usecase.CommentDocs { // 分組 replyMap := make(map[string][]*usecase.CommentDocs) // 查詢子留言 for _, item := range parentComments { id := item.ID.Hex() subComments, _, err := use.Comment.ListComments(ctx, repository.ListCommentRequest{ ParentID: &id, PageSize: 20, PageIndex: 1, // 可調整分頁大小 }) if err != nil { continue } for _, sub := range subComments { decodedMessage, err := decodeMessage(sub.Message) if err != nil { logx.WithContext(ctx).Errorf("Failed to decode message: %v", err) continue } replyMap[sub.ParentCommentID] = append(replyMap[sub.ParentCommentID], &usecase.CommentDocs{ ID: sub.ID.Hex(), UID: sub.UID, ReferenceID: sub.ReferenceID, ParentCommentID: sub.ParentCommentID, Message: decodedMessage, UpdatedAt: sub.UpdatedAt, CreatedAt: sub.CreatedAt, }) } } return replyMap } func decodeMessage(encodedMessage string) (string, error) { // Base64 解碼 decodedBase64, err := base64.StdEncoding.DecodeString(encodedMessage) if err != nil { return "", fmt.Errorf("failed to decode Base64: %w", err) } // Snappy 解碼 decodedSnappy, err := snappy.Decode(nil, decodedBase64) if err != nil { return "", fmt.Errorf("failed to decode Snappy: %w", err) } return string(decodedSnappy), nil }