feature/post_v2 #2
|
@ -9,7 +9,8 @@ message OKResp {}
|
||||||
message NoneReq {}
|
message NoneReq {}
|
||||||
|
|
||||||
// 分頁信息
|
// 分頁信息
|
||||||
message Pager {
|
message Pager
|
||||||
|
{
|
||||||
int64 total = 1; // 總數量
|
int64 total = 1; // 總數量
|
||||||
int64 size = 2; // 每頁數量
|
int64 size = 2; // 每頁數量
|
||||||
int64 index = 3; // 當前頁碼
|
int64 index = 3; // 當前頁碼
|
||||||
|
@ -18,7 +19,8 @@ message Pager {
|
||||||
// ========== 貼文區 ===========
|
// ========== 貼文區 ===========
|
||||||
|
|
||||||
// ------ NewPost 新增貼文--------
|
// ------ NewPost 新增貼文--------
|
||||||
message NewPostReq {
|
message NewPostReq
|
||||||
|
{
|
||||||
string uid = 1; // 發佈貼文的用戶ID
|
string uid = 1; // 發佈貼文的用戶ID
|
||||||
string content = 2; // 貼文內容
|
string content = 2; // 貼文內容
|
||||||
repeated string tags = 3; // 貼文相關標籤
|
repeated string tags = 3; // 貼文相關標籤
|
||||||
|
@ -26,26 +28,30 @@ message NewPostReq {
|
||||||
bool is_ad = 5; // 是否為廣告
|
bool is_ad = 5; // 是否為廣告
|
||||||
}
|
}
|
||||||
|
|
||||||
message Media {
|
message Media
|
||||||
|
{
|
||||||
string type = 1;
|
string type = 1;
|
||||||
string url = 2;
|
string url = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 貼文回應
|
// 貼文回應
|
||||||
message PostResp {
|
message PostResp
|
||||||
|
{
|
||||||
string post_id = 1; // 創建成功的貼文ID
|
string post_id = 1; // 創建成功的貼文ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ DeletePost 刪除貼文 ------
|
// ------ DeletePost 刪除貼文 ------
|
||||||
|
|
||||||
// 刪除貼文的請求
|
// 刪除貼文的請求
|
||||||
message DeletePostsReq {
|
message DeletePostsReq
|
||||||
|
{
|
||||||
repeated string post_id = 1; // 貼文ID
|
repeated string post_id = 1; // 貼文ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ UpdatePost 更新貼文 ------
|
// ------ UpdatePost 更新貼文 ------
|
||||||
// 更新貼文的請求
|
// 更新貼文的請求
|
||||||
message UpdatePostReq {
|
message UpdatePostReq
|
||||||
|
{
|
||||||
string post_id = 1; // 貼文ID
|
string post_id = 1; // 貼文ID
|
||||||
repeated string tags = 2; // 新的標籤列表
|
repeated string tags = 2; // 新的標籤列表
|
||||||
repeated Media media = 3; // 這筆文章的所有 Media URL
|
repeated Media media = 3; // 這筆文章的所有 Media URL
|
||||||
|
@ -56,7 +62,8 @@ message UpdatePostReq {
|
||||||
|
|
||||||
// ------ListPosts 查詢貼文 ------
|
// ------ListPosts 查詢貼文 ------
|
||||||
// 查詢貼文的請求
|
// 查詢貼文的請求
|
||||||
message QueryPostsReq {
|
message QueryPostsReq
|
||||||
|
{
|
||||||
repeated string uid = 1; // 可選:根據用戶ID篩選貼文
|
repeated string uid = 1; // 可選:根據用戶ID篩選貼文
|
||||||
repeated string post_id = 2; // 可選:根據貼文ID篩選貼文
|
repeated string post_id = 2; // 可選:根據貼文ID篩選貼文
|
||||||
optional int32 only_ads = 3; // 可選:是否只顯示廣告 0 不篩選 1 只顯示廣告 2 不顯示廣告
|
optional int32 only_ads = 3; // 可選:是否只顯示廣告 0 不篩選 1 只顯示廣告 2 不顯示廣告
|
||||||
|
@ -65,7 +72,8 @@ message QueryPostsReq {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 貼文詳情
|
// 貼文詳情
|
||||||
message PostDetailItem {
|
message PostDetailItem
|
||||||
|
{
|
||||||
string post_id = 1; // 貼文ID
|
string post_id = 1; // 貼文ID
|
||||||
string uid = 2; // 發佈用戶ID
|
string uid = 2; // 發佈用戶ID
|
||||||
string content = 3; // 貼文內容
|
string content = 3; // 貼文內容
|
||||||
|
@ -79,12 +87,14 @@ message PostDetailItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 貼文列表回應
|
// 貼文列表回應
|
||||||
message ListPostsResp {
|
message ListPostsResp
|
||||||
|
{
|
||||||
repeated PostDetailItem posts = 1; // 貼文列表
|
repeated PostDetailItem posts = 1; // 貼文列表
|
||||||
Pager page = 2;
|
Pager page = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ModifyLikeDislikeCountReq {
|
message ModifyLikeDislikeCountReq
|
||||||
|
{
|
||||||
string post_id = 1; // 貼文的 ID
|
string post_id = 1; // 貼文的 ID
|
||||||
int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚
|
int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚
|
||||||
bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少)
|
bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少)
|
||||||
|
@ -92,7 +102,8 @@ message ModifyLikeDislikeCountReq {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 定義貼文服務(最基本單位,不要把邏輯放進來,也考慮是否要做快取) ==========
|
// ========== 定義貼文服務(最基本單位,不要把邏輯放進來,也考慮是否要做快取) ==========
|
||||||
service PostService {
|
service PostService
|
||||||
|
{
|
||||||
// CreatePost 新增貼文
|
// CreatePost 新增貼文
|
||||||
rpc CreatePost(NewPostReq) returns (PostResp);
|
rpc CreatePost(NewPostReq) returns (PostResp);
|
||||||
// DeletePost 刪除貼文
|
// DeletePost 刪除貼文
|
||||||
|
@ -102,3 +113,72 @@ service PostService {
|
||||||
// ListPosts 查詢貼文
|
// ListPosts 查詢貼文
|
||||||
rpc ListPosts(QueryPostsReq) returns (ListPostsResp);
|
rpc ListPosts(QueryPostsReq) returns (ListPostsResp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =================================================================================================
|
||||||
|
|
||||||
|
// ------------ 評論貼文的請求 ------------
|
||||||
|
message CommentPostReq
|
||||||
|
{
|
||||||
|
string post_id = 1; // 貼文ID
|
||||||
|
string uid = 2; // 評論者ID
|
||||||
|
string content = 3; // 評論內容
|
||||||
|
}
|
||||||
|
|
||||||
|
message CommentPostResp
|
||||||
|
{
|
||||||
|
string comment_id = 1; // 回應ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------ 查詢評論的請求 ------------
|
||||||
|
message GetCommentsReq
|
||||||
|
{
|
||||||
|
string post_id = 1; // 貼文ID
|
||||||
|
int32 page_index = 2; // 分頁頁碼
|
||||||
|
int32 page_size = 3; // 每頁顯示數量
|
||||||
|
}
|
||||||
|
|
||||||
|
// 評論詳情
|
||||||
|
message CommentDetail
|
||||||
|
{
|
||||||
|
string comment_id = 1; // 評論ID
|
||||||
|
string uid = 2; // 評論者ID
|
||||||
|
string content = 3; // 評論內容
|
||||||
|
int64 created_at = 4; // 創建時間
|
||||||
|
int64 like_count = 5; // 讚數
|
||||||
|
int64 dislike_count = 6; // 不喜歡數量
|
||||||
|
}
|
||||||
|
|
||||||
|
// 評論列表回應
|
||||||
|
message GetCommentsResp
|
||||||
|
{
|
||||||
|
repeated CommentDetail comments = 1; // 評論列表
|
||||||
|
Pager page = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------ 刪除評論請求 ------------
|
||||||
|
message DeleteCommentReq
|
||||||
|
{
|
||||||
|
repeated string comment_id = 1; // 評論ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新評論請求
|
||||||
|
message UpdateCommentReq
|
||||||
|
{
|
||||||
|
string comment_id = 1; // 評論ID
|
||||||
|
string content = 2; // 更新後的評論內容
|
||||||
|
optional int64 like_count = 3; // 讚數
|
||||||
|
optional int64 dislike_count = 4; // 不喜歡數量
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定義評論服務
|
||||||
|
service CommentService
|
||||||
|
{
|
||||||
|
// NewComment 發表評論
|
||||||
|
rpc NewComment(CommentPostReq) returns (CommentPostResp);
|
||||||
|
// GetComments 查詢評論
|
||||||
|
rpc GetComments(GetCommentsReq) returns (GetCommentsResp);
|
||||||
|
// DeleteComment 刪除評論
|
||||||
|
rpc DeleteComment(DeleteCommentReq) returns (OKResp);
|
||||||
|
// UpdateComment 更新評論
|
||||||
|
rpc UpdateComment(UpdateCommentReq) returns (OKResp);
|
||||||
|
}
|
|
@ -1,5 +1,13 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"code.30cm.net/digimon/library-go/errs/code"
|
||||||
|
"fmt"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type ErrorCode uint32
|
type ErrorCode uint32
|
||||||
|
|
||||||
func (e ErrorCode) ToUint32() uint32 {
|
func (e ErrorCode) ToUint32() uint32 {
|
||||||
|
@ -15,3 +23,25 @@ const (
|
||||||
UpdatePostError
|
UpdatePostError
|
||||||
ListPostError
|
ListPostError
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CommentFoundErrorCode ErrorCode = iota + 10
|
||||||
|
CommentInsertErrorCode
|
||||||
|
CommentDeleteErrorCode
|
||||||
|
CommentUpdateErrorCode
|
||||||
|
CommentListErrorCode
|
||||||
|
)
|
||||||
|
|
||||||
|
func CommentError(ec ErrorCode, s ...string) *ers.LibError {
|
||||||
|
return ers.NewError(code.CloudEPTweeting, code.DBError,
|
||||||
|
ec.ToUint32(),
|
||||||
|
fmt.Sprintf("%s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func CommentErrorL(ec ErrorCode,
|
||||||
|
l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError {
|
||||||
|
e := CommentError(ec, s...)
|
||||||
|
l.WithCallerSkip(1).WithFields(filed...).Error(e.Error())
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package commentservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteCommentLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDeleteCommentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteCommentLogic {
|
||||||
|
return &DeleteCommentLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteComment 刪除評論
|
||||||
|
func (l *DeleteCommentLogic) DeleteComment(in *tweeting.DeleteCommentReq) (*tweeting.OKResp, error) {
|
||||||
|
_, err := l.svcCtx.CommentModel.DeleteMany(l.ctx, in.GetCommentId()...)
|
||||||
|
if err != nil {
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.CommentDeleteErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "CommentModel.DeleteMany"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to del comment").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.OKResp{}, nil
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package commentservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetCommentsLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetCommentsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCommentsLogic {
|
||||||
|
return &GetCommentsLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只列出要驗證的資料
|
||||||
|
type listReq struct {
|
||||||
|
PostID string `json:"post_id" validate:"required"`
|
||||||
|
PageSize int64 `json:"page_size" validate:"required"`
|
||||||
|
PageIndex int64 `json:"page_index" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 將單個 Post 轉換為 PostDetailItem
|
||||||
|
func convertToCommentDetailItem(item *model.Comment) *tweeting.CommentDetail {
|
||||||
|
return &tweeting.CommentDetail{
|
||||||
|
CommentId: item.ID.Hex(),
|
||||||
|
Uid: item.UID,
|
||||||
|
Content: item.Content,
|
||||||
|
CreatedAt: item.CreateAt,
|
||||||
|
LikeCount: int64(item.LikeCount),
|
||||||
|
DislikeCount: int64(item.DisLikeCount),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetComments 查詢評論
|
||||||
|
// 目前應該是沒有需求是要看 uid 在哪裡留過言,如果未來業務邏輯有再新增
|
||||||
|
func (l *GetCommentsLogic) GetComments(in *tweeting.GetCommentsReq) (*tweeting.GetCommentsResp, error) {
|
||||||
|
// 將 PageSize 和 PageIndex 提前轉換為 int64
|
||||||
|
pageSize := int64(in.GetPageSize())
|
||||||
|
pageIndex := int64(in.GetPageIndex())
|
||||||
|
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&listReq{
|
||||||
|
PageSize: pageSize,
|
||||||
|
PageIndex: pageIndex,
|
||||||
|
PostID: in.GetPostId(),
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 構建查詢條件
|
||||||
|
query := &model.QueryCommentModelReq{
|
||||||
|
PostID: in.GetPostId(),
|
||||||
|
PageSize: pageSize,
|
||||||
|
PageIndex: pageIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 執行查詢
|
||||||
|
find, count, err := l.svcCtx.CommentModel.Find(l.ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.CommentListErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "query", Value: query},
|
||||||
|
{Key: "func", Value: "CommentModel.Find"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to find comment").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
// 將查詢結果轉換為 API 回應格式
|
||||||
|
result := make([]*tweeting.CommentDetail, 0, count)
|
||||||
|
for _, item := range find {
|
||||||
|
result = append(result, convertToCommentDetailItem(item))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回結果
|
||||||
|
return &tweeting.GetCommentsResp{
|
||||||
|
Comments: result,
|
||||||
|
Page: &tweeting.Pager{
|
||||||
|
Total: count,
|
||||||
|
Index: pageIndex,
|
||||||
|
Size: pageSize,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package commentservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NewCommentLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNewCommentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewCommentLogic {
|
||||||
|
return &NewCommentLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 輸入的定義 -> 檢查用
|
||||||
|
type newCommentReq struct {
|
||||||
|
UID string `json:"uid" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required,lte=500"` // 貼文限制 500 字內
|
||||||
|
PostID string `json:"post_id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewComment 發表評論
|
||||||
|
func (l *NewCommentLogic) NewComment(in *tweeting.CommentPostReq) (*tweeting.CommentPostResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&newCommentReq{
|
||||||
|
UID: in.GetUid(),
|
||||||
|
Content: in.GetContent(),
|
||||||
|
PostID: in.GetPostId(),
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查是否有這個文章
|
||||||
|
_, err := l.svcCtx.PostModel.FindOne(l.ctx, in.GetPostId())
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(model.ErrNotFound, err) {
|
||||||
|
// 錯誤代碼 05-031-00
|
||||||
|
return nil, ers.ResourceNotFound("failed to find post: ", in.GetPostId())
|
||||||
|
}
|
||||||
|
// 錯誤代碼 05-021-10
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.CommentFoundErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.FindOne"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to find post:", in.GetPostId()).Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &model.Comment{
|
||||||
|
PostID: in.GetPostId(),
|
||||||
|
UID: in.GetUid(),
|
||||||
|
Content: in.GetContent(),
|
||||||
|
LikeCount: 0,
|
||||||
|
DisLikeCount: 0,
|
||||||
|
}
|
||||||
|
err = l.svcCtx.CommentModel.Insert(l.ctx, data)
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-11
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.CommentInsertErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "CommentModel.Insert"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to insert comment:", in.GetPostId()).Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.CommentPostResp{
|
||||||
|
CommentId: data.ID.Hex(),
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package commentservicelogic
|
|
@ -0,0 +1,81 @@
|
||||||
|
package commentservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateCommentLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpdateCommentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateCommentLogic {
|
||||||
|
return &UpdateCommentLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type checkCommentId struct {
|
||||||
|
CommentId string `validate:"required"`
|
||||||
|
Content string `json:"content,omitempty" validate:"lte=500"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateComment 更新評論
|
||||||
|
func (l *UpdateCommentLogic) UpdateComment(in *tweeting.UpdateCommentReq) (*tweeting.OKResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&checkCommentId{
|
||||||
|
CommentId: in.GetCommentId(),
|
||||||
|
Content: in.GetContent(),
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
// 沒有就沒有,有就走全覆蓋
|
||||||
|
update := model.Comment{}
|
||||||
|
oid, err := primitive.ObjectIDFromHex(in.GetCommentId())
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat("failed to get correct comment id")
|
||||||
|
}
|
||||||
|
update.ID = oid
|
||||||
|
update.Content = in.GetContent()
|
||||||
|
// 因為 0 也有意義,所以如果是真的沒帶進來,用 -1 帶進去表示不作動
|
||||||
|
if in.LikeCount == nil {
|
||||||
|
update.LikeCount = -1
|
||||||
|
} else {
|
||||||
|
update.LikeCount = in.GetLikeCount()
|
||||||
|
}
|
||||||
|
if in.DislikeCount == nil {
|
||||||
|
update.DisLikeCount = -1
|
||||||
|
} else {
|
||||||
|
update.DisLikeCount = in.GetDislikeCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = l.svcCtx.CommentModel.UpdateOptional(l.ctx, &update)
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-13
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.CommentUpdateErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "CommentModel.UpdateOptional"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to update comment:", in.CommentId).Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.OKResp{}, nil
|
||||||
|
}
|
|
@ -80,8 +80,19 @@ func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKRe
|
||||||
}
|
}
|
||||||
update.MediaURL = media
|
update.MediaURL = media
|
||||||
update.Content = in.GetContent()
|
update.Content = in.GetContent()
|
||||||
update.Like = uint64(in.GetLikeCount())
|
|
||||||
update.DisLike = uint64(in.GetDislikeCount())
|
// 因為 0 也有意義,所以如果是真的沒帶進來,用 -1 帶進去表示不作動
|
||||||
|
if in.LikeCount == nil {
|
||||||
|
update.Like = -1
|
||||||
|
} else {
|
||||||
|
update.Like = in.GetLikeCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.DislikeCount == nil {
|
||||||
|
update.DisLike = -1
|
||||||
|
} else {
|
||||||
|
update.DisLike = in.GetDislikeCount()
|
||||||
|
}
|
||||||
|
|
||||||
_, err = l.svcCtx.PostModel.UpdateOptional(l.ctx, &update)
|
_, err = l.svcCtx.PostModel.UpdateOptional(l.ctx, &update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "github.com/zeromicro/go-zero/core/stores/mon"
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/mon"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
var _ CommentModel = (*customCommentModel)(nil)
|
var _ CommentModel = (*customCommentModel)(nil)
|
||||||
|
|
||||||
|
@ -9,13 +17,27 @@ type (
|
||||||
// and implement the added methods in customCommentModel.
|
// and implement the added methods in customCommentModel.
|
||||||
CommentModel interface {
|
CommentModel interface {
|
||||||
commentModel
|
commentModel
|
||||||
|
DeleteMany(ctx context.Context, id ...string) (int64, error)
|
||||||
|
UpdateOptional(ctx context.Context, data *Comment) (*mongo.UpdateResult, error)
|
||||||
|
Find(ctx context.Context, param *QueryCommentModelReq) ([]*Comment, int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
customCommentModel struct {
|
customCommentModel struct {
|
||||||
*defaultCommentModel
|
*defaultCommentModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryCommentModelReq struct {
|
||||||
|
PostID string
|
||||||
|
PageSize int64
|
||||||
|
PageIndex int64
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (xw customCommentModel) Find(ctx context.Context, param *QueryCommentModelReq) ([]*Comment, int64, error) {
|
||||||
|
// TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
// NewCommentModel returns a model for the mongo.
|
// NewCommentModel returns a model for the mongo.
|
||||||
func NewCommentModel(url, db, collection string) CommentModel {
|
func NewCommentModel(url, db, collection string) CommentModel {
|
||||||
conn := mon.MustNewModel(url, db, collection)
|
conn := mon.MustNewModel(url, db, collection)
|
||||||
|
@ -23,3 +45,56 @@ func NewCommentModel(url, db, collection string) CommentModel {
|
||||||
defaultCommentModel: newDefaultCommentModel(conn),
|
defaultCommentModel: newDefaultCommentModel(conn),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *defaultCommentModel) DeleteMany(ctx context.Context, id ...string) (int64, error) {
|
||||||
|
objectIDs := make([]primitive.ObjectID, 0, len(id))
|
||||||
|
|
||||||
|
// prepare
|
||||||
|
for _, item := range id {
|
||||||
|
oid, err := primitive.ObjectIDFromHex(item)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "defaultPostModel.DeleteMany"),
|
||||||
|
logx.Field("id", item),
|
||||||
|
).Error(err.Error())
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
objectIDs = append(objectIDs, oid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查是否有有效的 ObjectIDs
|
||||||
|
if len(objectIDs) == 0 {
|
||||||
|
return 0, ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刪除文檔
|
||||||
|
res, err := m.conn.DeleteMany(ctx, bson.M{"_id": bson.M{"$in": objectIDs}})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultCommentModel) UpdateOptional(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) {
|
||||||
|
update := bson.M{"$set": bson.M{}}
|
||||||
|
|
||||||
|
if data.Content != "" {
|
||||||
|
update["$set"].(bson.M)["content"] = data.Content
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.LikeCount != -1 {
|
||||||
|
update["$set"].(bson.M)["like_count"] = data.LikeCount
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.DisLikeCount != -1 {
|
||||||
|
update["$set"].(bson.M)["dis_like_count"] = data.DisLikeCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAt 是每次都需要更新的,不用檢查
|
||||||
|
update["$set"].(bson.M)["updateAt"] = time.Now().UTC().UnixNano()
|
||||||
|
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, update)
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ func newDefaultCommentModel(conn *mon.Model) *defaultCommentModel {
|
||||||
func (m *defaultCommentModel) Insert(ctx context.Context, data *Comment) error {
|
func (m *defaultCommentModel) Insert(ctx context.Context, data *Comment) error {
|
||||||
if data.ID.IsZero() {
|
if data.ID.IsZero() {
|
||||||
data.ID = primitive.NewObjectID()
|
data.ID = primitive.NewObjectID()
|
||||||
data.CreateAt = time.Now()
|
data.CreateAt = time.Now().UTC().UnixNano()
|
||||||
data.UpdateAt = time.Now()
|
data.UpdateAt = time.Now().UTC().UnixNano()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := m.conn.InsertOne(ctx, data)
|
_, err := m.conn.InsertOne(ctx, data)
|
||||||
|
@ -57,7 +57,7 @@ func (m *defaultCommentModel) FindOne(ctx context.Context, id string) (*Comment,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultCommentModel) Update(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) {
|
func (m *defaultCommentModel) Update(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) {
|
||||||
data.UpdateAt = time.Now()
|
data.UpdateAt = time.Now().UTC().UnixNano()
|
||||||
|
|
||||||
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||||
// TODO: Fill your own fields
|
PostID string `bson:"post_id" json:"post_id"`
|
||||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
UID string `bson:"uid" json:"uid"` // 留下留言的人
|
||||||
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
Content string `bson:"content" json:"content"` // 留言內容
|
||||||
|
LikeCount int64 `bson:"like_count" json:"like_count"` // 喜歡這則留言的人
|
||||||
|
DisLikeCount int64 `bson:"dis_like_count" json:"dis_like_count"` // 不喜歡這則留言的人
|
||||||
|
UpdateAt int64 `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
||||||
|
CreateAt int64 `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Comment) CollectionName() string {
|
||||||
|
return "comment"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 照邏輯,應該需要建立的索引有
|
||||||
|
// 複合索引:(PostID + CreateAt)
|
||||||
|
|
|
@ -106,11 +106,11 @@ func (m *defaultPostModel) UpdateOptional(ctx context.Context, data *Post) (*mon
|
||||||
update["$set"].(bson.M)["media_url"] = data.MediaURL
|
update["$set"].(bson.M)["media_url"] = data.MediaURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Like != 0 {
|
if data.Like != -1 {
|
||||||
update["$set"].(bson.M)["like"] = data.Like
|
update["$set"].(bson.M)["like"] = data.Like
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.DisLike != 0 {
|
if data.DisLike != -1 {
|
||||||
update["$set"].(bson.M)["dislike"] = data.DisLike
|
update["$set"].(bson.M)["dislike"] = data.DisLike
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ type Post struct {
|
||||||
IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文 -> 過濾條件
|
IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文 -> 過濾條件
|
||||||
Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除)
|
Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除)
|
||||||
MediaURL []Media `bson:"media_url" json:"media_url"` // 網址
|
MediaURL []Media `bson:"media_url" json:"media_url"` // 網址
|
||||||
Like uint64 `bson:"like" json:"like"` // 讚數量
|
Like int64 `bson:"like" json:"like"` // 讚數量
|
||||||
DisLike uint64 `bson:"dislike" json:"dislike"` // 不讚數量
|
DisLike int64 `bson:"dislike" json:"dislike"` // 不讚數量
|
||||||
UpdateAt int64 `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
UpdateAt int64 `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
||||||
CreateAt int64 `bson:"createAt,omitempty" json:"createAt,omitempty"` // -> 排序條件
|
CreateAt int64 `bson:"createAt,omitempty" json:"createAt,omitempty"` // -> 排序條件
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
// Source: tweeting.proto
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/logic/commentservice"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommentServiceServer struct {
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
tweeting.UnimplementedCommentServiceServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCommentServiceServer(svcCtx *svc.ServiceContext) *CommentServiceServer {
|
||||||
|
return &CommentServiceServer{
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewComment 發表評論
|
||||||
|
func (s *CommentServiceServer) NewComment(ctx context.Context, in *tweeting.CommentPostReq) (*tweeting.CommentPostResp, error) {
|
||||||
|
l := commentservicelogic.NewNewCommentLogic(ctx, s.svcCtx)
|
||||||
|
return l.NewComment(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetComments 查詢評論
|
||||||
|
func (s *CommentServiceServer) GetComments(ctx context.Context, in *tweeting.GetCommentsReq) (*tweeting.GetCommentsResp, error) {
|
||||||
|
l := commentservicelogic.NewGetCommentsLogic(ctx, s.svcCtx)
|
||||||
|
return l.GetComments(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteComment 刪除評論
|
||||||
|
func (s *CommentServiceServer) DeleteComment(ctx context.Context, in *tweeting.DeleteCommentReq) (*tweeting.OKResp, error) {
|
||||||
|
l := commentservicelogic.NewDeleteCommentLogic(ctx, s.svcCtx)
|
||||||
|
return l.DeleteComment(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateComment 更新評論
|
||||||
|
func (s *CommentServiceServer) UpdateComment(ctx context.Context, in *tweeting.UpdateCommentReq) (*tweeting.OKResp, error) {
|
||||||
|
l := commentservicelogic.NewUpdateCommentLogic(ctx, s.svcCtx)
|
||||||
|
return l.UpdateComment(in)
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
postservicelogic "app-cloudep-tweeting-service/internal/logic/postservice"
|
"app-cloudep-tweeting-service/internal/logic/postservice"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,9 +45,3 @@ func (s *PostServiceServer) ListPosts(ctx context.Context, in *tweeting.QueryPos
|
||||||
l := postservicelogic.NewListPostsLogic(ctx, s.svcCtx)
|
l := postservicelogic.NewListPostsLogic(ctx, s.svcCtx)
|
||||||
return l.ListPosts(in)
|
return l.ListPosts(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModifyLikeDislikeCount 調整讚或不讚數量
|
|
||||||
func (s *PostServiceServer) ModifyLikeDislikeCount(ctx context.Context, in *tweeting.ModifyLikeDislikeCountReq) (*tweeting.OKResp, error) {
|
|
||||||
l := postservicelogic.NewModifyLikeDislikeCountLogic(ctx, s.svcCtx)
|
|
||||||
return l.ModifyLikeDislikeCount(in)
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,14 @@ func mustMongoConnectUrl(c config.Config) string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 思考快取做在那邊
|
||||||
|
|
||||||
func MustPostModel(c config.Config) model.PostModel {
|
func MustPostModel(c config.Config) model.PostModel {
|
||||||
postCollection := model.Post{}
|
postCollection := model.Post{}
|
||||||
return model.NewPostModel(mustMongoConnectUrl(c), c.Mongo.Database, postCollection.CollectionName())
|
return model.NewPostModel(mustMongoConnectUrl(c), c.Mongo.Database, postCollection.CollectionName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustCommentModel(c config.Config) model.CommentModel {
|
||||||
|
m := model.Comment{}
|
||||||
|
return model.NewCommentModel(mustMongoConnectUrl(c), c.Mongo.Database, m.CollectionName())
|
||||||
|
}
|
||||||
|
|
|
@ -12,13 +12,14 @@ type ServiceContext struct {
|
||||||
Validate vi.Validate
|
Validate vi.Validate
|
||||||
|
|
||||||
PostModel model.PostModel
|
PostModel model.PostModel
|
||||||
|
CommentModel model.CommentModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config) *ServiceContext {
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
Validate: vi.MustValidator(),
|
Validate: vi.MustValidator(),
|
||||||
|
|
||||||
PostModel: MustPostModel(c),
|
PostModel: MustPostModel(c),
|
||||||
|
CommentModel: MustCommentModel(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue