2025-01-15 05:17:30 +00:00
|
|
|
package usecase
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
2025-01-15 05:25:55 +00:00
|
|
|
|
2025-01-15 05:46:36 +00:00
|
|
|
"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"
|
|
|
|
|
2025-01-15 05:17:30 +00:00
|
|
|
"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)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 批量構建子留言
|
2025-01-15 05:25:55 +00:00
|
|
|
replyMap := use.buildReplies(ctx, comments)
|
2025-01-15 05:17:30 +00:00
|
|
|
// 組裝結果
|
|
|
|
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)
|
2025-01-15 05:25:55 +00:00
|
|
|
|
2025-01-15 05:17:30 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2025-01-15 05:25:55 +00:00
|
|
|
func (use *CommentUseCase) buildReplies(ctx context.Context, parentComments []*entity.Comments) map[string][]*usecase.CommentDocs {
|
2025-01-15 05:17:30 +00:00
|
|
|
// 分組
|
|
|
|
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)
|
2025-01-15 05:25:55 +00:00
|
|
|
|
2025-01-15 05:17:30 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-15 05:25:55 +00:00
|
|
|
return replyMap
|
2025-01-15 05:17:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|