app-cloudep-comment-server/pkg/usecase/comment.go

237 lines
6.5 KiB
Go

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
}