From c99ac1a6b31933ccf493160f09ef73960c7c80b8 Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Thu, 29 Aug 2024 23:53:43 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E9=87=8D=E6=A7=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/tweeting.yaml | 6 -- go.mod | 88 ------------------- internal/config/config.go | 7 -- .../logic/commentservice/count_like_logic.go | 31 ------- .../commentservice/delete_comment_logic.go | 31 ------- .../commentservice/get_comments_logic.go | 31 ------- .../commentservice/get_like_status_logic.go | 31 ------- .../commentservice/like_comment_logic.go | 31 ------- .../logic/commentservice/like_list_logic.go | 31 ------- .../logic/commentservice/new_comment_logic.go | 31 ------- .../commentservice/update_comment_logic.go | 31 ------- .../logic/postservice/count_like_logic.go | 31 ------- .../logic/postservice/delete_post_logic.go | 31 ------- .../postservice/get_like_status_logic.go | 31 ------- internal/logic/postservice/like_list_logic.go | 31 ------- internal/logic/postservice/like_logic.go | 31 ------- .../logic/postservice/list_posts_logic.go | 31 ------- internal/logic/postservice/new_post_logic.go | 31 ------- .../logic/postservice/update_post_logic.go | 31 ------- internal/model/mongo/comment_likes_model.go | 25 ------ .../model/mongo/comment_likes_model_gen.go | 74 ---------------- internal/model/mongo/comment_likes_types.go | 14 --- internal/model/mongo/comment_model.go | 28 ------ internal/model/mongo/comment_model_gen.go | 77 ---------------- internal/model/mongo/comment_types.go | 14 --- internal/model/mongo/error.go | 12 --- internal/model/mongo/post_likes_model.go | 25 ------ internal/model/mongo/post_likes_model_gen.go | 74 ---------------- internal/model/mongo/post_likes_types.go | 14 --- internal/model/mongo/post_model.go | 28 ------ internal/model/mongo/post_model_gen.go | 77 ---------------- internal/model/mongo/post_types.go | 14 --- internal/model/mongo/tags_model.go | 25 ------ internal/model/mongo/tags_model_gen.go | 74 ---------------- internal/model/mongo/tags_types.go | 14 --- .../commentservice/comment_service_server.go | 71 --------------- .../server/postservice/post_service_server.go | 71 --------------- internal/svc/service_context.go | 13 --- tweeting.go | 41 --------- 39 files changed, 1382 deletions(-) delete mode 100644 etc/tweeting.yaml delete mode 100644 go.mod delete mode 100755 internal/config/config.go delete mode 100644 internal/logic/commentservice/count_like_logic.go delete mode 100644 internal/logic/commentservice/delete_comment_logic.go delete mode 100644 internal/logic/commentservice/get_comments_logic.go delete mode 100644 internal/logic/commentservice/get_like_status_logic.go delete mode 100644 internal/logic/commentservice/like_comment_logic.go delete mode 100644 internal/logic/commentservice/like_list_logic.go delete mode 100644 internal/logic/commentservice/new_comment_logic.go delete mode 100644 internal/logic/commentservice/update_comment_logic.go delete mode 100644 internal/logic/postservice/count_like_logic.go delete mode 100644 internal/logic/postservice/delete_post_logic.go delete mode 100644 internal/logic/postservice/get_like_status_logic.go delete mode 100644 internal/logic/postservice/like_list_logic.go delete mode 100644 internal/logic/postservice/like_logic.go delete mode 100644 internal/logic/postservice/list_posts_logic.go delete mode 100644 internal/logic/postservice/new_post_logic.go delete mode 100644 internal/logic/postservice/update_post_logic.go delete mode 100644 internal/model/mongo/comment_likes_model.go delete mode 100644 internal/model/mongo/comment_likes_model_gen.go delete mode 100644 internal/model/mongo/comment_likes_types.go delete mode 100644 internal/model/mongo/comment_model.go delete mode 100644 internal/model/mongo/comment_model_gen.go delete mode 100644 internal/model/mongo/comment_types.go delete mode 100644 internal/model/mongo/error.go delete mode 100644 internal/model/mongo/post_likes_model.go delete mode 100644 internal/model/mongo/post_likes_model_gen.go delete mode 100644 internal/model/mongo/post_likes_types.go delete mode 100644 internal/model/mongo/post_model.go delete mode 100644 internal/model/mongo/post_model_gen.go delete mode 100644 internal/model/mongo/post_types.go delete mode 100644 internal/model/mongo/tags_model.go delete mode 100644 internal/model/mongo/tags_model_gen.go delete mode 100644 internal/model/mongo/tags_types.go delete mode 100644 internal/server/commentservice/comment_service_server.go delete mode 100644 internal/server/postservice/post_service_server.go delete mode 100644 internal/svc/service_context.go delete mode 100644 tweeting.go diff --git a/etc/tweeting.yaml b/etc/tweeting.yaml deleted file mode 100644 index c611c48..0000000 --- a/etc/tweeting.yaml +++ /dev/null @@ -1,6 +0,0 @@ -Name: tweeting.rpc -ListenOn: 0.0.0.0:8080 -Etcd: - Hosts: - - 127.0.0.1:2379 - Key: tweeting.rpc diff --git a/go.mod b/go.mod deleted file mode 100644 index 1be6bfb..0000000 --- a/go.mod +++ /dev/null @@ -1,88 +0,0 @@ -module app-cloudep-tweeting-service - -go 1.22.3 - -require ( - github.com/zeromicro/go-zero v1.7.0 - google.golang.org/grpc v1.66.0 - google.golang.org/protobuf v1.34.2 -) - -require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/fatih/color v1.17.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openzipkin/zipkin-go v0.4.3 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/redis/go-redis/v9 v9.6.1 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.15 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect - go.etcd.io/etcd/client/v3 v3.5.15 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/automaxprocs v1.5.3 // indirect - go.uber.org/multierr v1.9.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.29.3 // indirect - k8s.io/apimachinery v0.29.4 // indirect - k8s.io/client-go v0.29.3 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect -) diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100755 index c1f85b9..0000000 --- a/internal/config/config.go +++ /dev/null @@ -1,7 +0,0 @@ -package config - -import "github.com/zeromicro/go-zero/zrpc" - -type Config struct { - zrpc.RpcServerConf -} diff --git a/internal/logic/commentservice/count_like_logic.go b/internal/logic/commentservice/count_like_logic.go deleted file mode 100644 index c656dc8..0000000 --- a/internal/logic/commentservice/count_like_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type CountLikeLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewCountLikeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CountLikeLogic { - return &CountLikeLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// CountLike 取得讚/不讚評論數量 -func (l *CountLikeLogic) CountLike(in *tweeting.LikeCountReq) (*tweeting.LikeCountResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.LikeCountResp{}, nil -} diff --git a/internal/logic/commentservice/delete_comment_logic.go b/internal/logic/commentservice/delete_comment_logic.go deleted file mode 100644 index 665cf06..0000000 --- a/internal/logic/commentservice/delete_comment_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "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) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/commentservice/get_comments_logic.go b/internal/logic/commentservice/get_comments_logic.go deleted file mode 100644 index 5f54081..0000000 --- a/internal/logic/commentservice/get_comments_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "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), - } -} - -// GetComments 查詢評論 -func (l *GetCommentsLogic) GetComments(in *tweeting.GetCommentsReq) (*tweeting.GetCommentsResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.GetCommentsResp{}, nil -} diff --git a/internal/logic/commentservice/get_like_status_logic.go b/internal/logic/commentservice/get_like_status_logic.go deleted file mode 100644 index 6dbce00..0000000 --- a/internal/logic/commentservice/get_like_status_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type GetLikeStatusLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewGetLikeStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLikeStatusLogic { - return &GetLikeStatusLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// GetLikeStatus 取得讚/不讚評論狀態 -func (l *GetLikeStatusLogic) GetLikeStatus(in *tweeting.LikeReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/commentservice/like_comment_logic.go b/internal/logic/commentservice/like_comment_logic.go deleted file mode 100644 index 60cd2c4..0000000 --- a/internal/logic/commentservice/like_comment_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type LikeCommentLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewLikeCommentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeCommentLogic { - return &LikeCommentLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// LikeComment 點讚/取消讚 評論 -func (l *LikeCommentLogic) LikeComment(in *tweeting.LikeReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/commentservice/like_list_logic.go b/internal/logic/commentservice/like_list_logic.go deleted file mode 100644 index 351a367..0000000 --- a/internal/logic/commentservice/like_list_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type LikeListLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewLikeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeListLogic { - return &LikeListLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// LikeList 取得讚/不讚評論列表 -func (l *LikeListLogic) LikeList(in *tweeting.LikeListReq) (*tweeting.LikeListResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.LikeListResp{}, nil -} diff --git a/internal/logic/commentservice/new_comment_logic.go b/internal/logic/commentservice/new_comment_logic.go deleted file mode 100644 index 5dcc84f..0000000 --- a/internal/logic/commentservice/new_comment_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "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), - } -} - -// NewComment 發表評論 -func (l *NewCommentLogic) NewComment(in *tweeting.CommentPostReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/commentservice/update_comment_logic.go b/internal/logic/commentservice/update_comment_logic.go deleted file mode 100644 index f38e6de..0000000 --- a/internal/logic/commentservice/update_comment_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package commentservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "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), - } -} - -// UpdateComment 更新評論 -func (l *UpdateCommentLogic) UpdateComment(in *tweeting.UpdateCommentReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/postservice/count_like_logic.go b/internal/logic/postservice/count_like_logic.go deleted file mode 100644 index 4fb4e67..0000000 --- a/internal/logic/postservice/count_like_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type CountLikeLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewCountLikeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CountLikeLogic { - return &CountLikeLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// CountLike 取得讚/不讚數量 -func (l *CountLikeLogic) CountLike(in *tweeting.LikeCountReq) (*tweeting.LikeCountResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.LikeCountResp{}, nil -} diff --git a/internal/logic/postservice/delete_post_logic.go b/internal/logic/postservice/delete_post_logic.go deleted file mode 100644 index 714e1f5..0000000 --- a/internal/logic/postservice/delete_post_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type DeletePostLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewDeletePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeletePostLogic { - return &DeletePostLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// DeletePost 刪除貼文 -func (l *DeletePostLogic) DeletePost(in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/postservice/get_like_status_logic.go b/internal/logic/postservice/get_like_status_logic.go deleted file mode 100644 index ba92101..0000000 --- a/internal/logic/postservice/get_like_status_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type GetLikeStatusLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewGetLikeStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLikeStatusLogic { - return &GetLikeStatusLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// GetLikeStatus 取得讚/不讚狀態 -func (l *GetLikeStatusLogic) GetLikeStatus(in *tweeting.LikeReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/postservice/like_list_logic.go b/internal/logic/postservice/like_list_logic.go deleted file mode 100644 index 6f4023b..0000000 --- a/internal/logic/postservice/like_list_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type LikeListLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewLikeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeListLogic { - return &LikeListLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// LikeList 取得讚/不讚列表 -func (l *LikeListLogic) LikeList(in *tweeting.LikeListReq) (*tweeting.LikeListResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.LikeListResp{}, nil -} diff --git a/internal/logic/postservice/like_logic.go b/internal/logic/postservice/like_logic.go deleted file mode 100644 index 3965b38..0000000 --- a/internal/logic/postservice/like_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type LikeLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewLikeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeLogic { - return &LikeLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// Like 點讚/取消讚 貼文 -func (l *LikeLogic) Like(in *tweeting.LikeReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/logic/postservice/list_posts_logic.go b/internal/logic/postservice/list_posts_logic.go deleted file mode 100644 index abba88d..0000000 --- a/internal/logic/postservice/list_posts_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type ListPostsLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewListPostsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPostsLogic { - return &ListPostsLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// ListPosts 查詢貼文 -func (l *ListPostsLogic) ListPosts(in *tweeting.QueryPostsReq) (*tweeting.ListPostsResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.ListPostsResp{}, nil -} diff --git a/internal/logic/postservice/new_post_logic.go b/internal/logic/postservice/new_post_logic.go deleted file mode 100644 index a755c05..0000000 --- a/internal/logic/postservice/new_post_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type NewPostLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewNewPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewPostLogic { - return &NewPostLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// NewPost 新增貼文 -func (l *NewPostLogic) NewPost(in *tweeting.NewPostReq) (*tweeting.PostResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.PostResp{}, nil -} diff --git a/internal/logic/postservice/update_post_logic.go b/internal/logic/postservice/update_post_logic.go deleted file mode 100644 index 454844b..0000000 --- a/internal/logic/postservice/update_post_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package postservicelogic - -import ( - "context" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type UpdatePostLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewUpdatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePostLogic { - return &UpdatePostLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// UpdatePost 更新貼文 -func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.OKResp{}, nil -} diff --git a/internal/model/mongo/comment_likes_model.go b/internal/model/mongo/comment_likes_model.go deleted file mode 100644 index 720b166..0000000 --- a/internal/model/mongo/comment_likes_model.go +++ /dev/null @@ -1,25 +0,0 @@ -package model - -import "github.com/zeromicro/go-zero/core/stores/mon" - -var _ Comment_likesModel = (*customComment_likesModel)(nil) - -type ( - // Comment_likesModel is an interface to be customized, add more methods here, - // and implement the added methods in customComment_likesModel. - Comment_likesModel interface { - comment_likesModel - } - - customComment_likesModel struct { - *defaultComment_likesModel - } -) - -// NewComment_likesModel returns a model for the mongo. -func NewComment_likesModel(url, db, collection string) Comment_likesModel { - conn := mon.MustNewModel(url, db, collection) - return &customComment_likesModel{ - defaultComment_likesModel: newDefaultComment_likesModel(conn), - } -} diff --git a/internal/model/mongo/comment_likes_model_gen.go b/internal/model/mongo/comment_likes_model_gen.go deleted file mode 100644 index cf5a194..0000000 --- a/internal/model/mongo/comment_likes_model_gen.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package model - -import ( - "context" - "time" - - "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" -) - -type comment_likesModel interface { - Insert(ctx context.Context, data *Comment_likes) error - FindOne(ctx context.Context, id string) (*Comment_likes, error) - Update(ctx context.Context, data *Comment_likes) (*mongo.UpdateResult, error) - Delete(ctx context.Context, id string) (int64, error) -} - -type defaultComment_likesModel struct { - conn *mon.Model -} - -func newDefaultComment_likesModel(conn *mon.Model) *defaultComment_likesModel { - return &defaultComment_likesModel{conn: conn} -} - -func (m *defaultComment_likesModel) Insert(ctx context.Context, data *Comment_likes) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - _, err := m.conn.InsertOne(ctx, data) - return err -} - -func (m *defaultComment_likesModel) FindOne(ctx context.Context, id string) (*Comment_likes, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data Comment_likes - - err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case mon.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultComment_likesModel) Update(ctx context.Context, data *Comment_likes) (*mongo.UpdateResult, error) { - data.UpdateAt = time.Now() - - res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data}) - return res, err -} - -func (m *defaultComment_likesModel) Delete(ctx context.Context, id string) (int64, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return 0, ErrInvalidObjectId - } - - res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid}) - return res, err -} diff --git a/internal/model/mongo/comment_likes_types.go b/internal/model/mongo/comment_likes_types.go deleted file mode 100644 index be19d28..0000000 --- a/internal/model/mongo/comment_likes_types.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Comment_likes struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` -} diff --git a/internal/model/mongo/comment_model.go b/internal/model/mongo/comment_model.go deleted file mode 100644 index 00478ac..0000000 --- a/internal/model/mongo/comment_model.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -import ( - "github.com/zeromicro/go-zero/core/stores/cache" - "github.com/zeromicro/go-zero/core/stores/monc" -) - -var _ CommentModel = (*customCommentModel)(nil) - -type ( - // CommentModel is an interface to be customized, add more methods here, - // and implement the added methods in customCommentModel. - CommentModel interface { - commentModel - } - - customCommentModel struct { - *defaultCommentModel - } -) - -// NewCommentModel returns a model for the mongo. -func NewCommentModel(url, db, collection string, c cache.CacheConf) CommentModel { - conn := monc.MustNewModel(url, db, collection, c) - return &customCommentModel{ - defaultCommentModel: newDefaultCommentModel(conn), - } -} diff --git a/internal/model/mongo/comment_model_gen.go b/internal/model/mongo/comment_model_gen.go deleted file mode 100644 index 85b05dd..0000000 --- a/internal/model/mongo/comment_model_gen.go +++ /dev/null @@ -1,77 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package model - -import ( - "context" - "time" - - "github.com/zeromicro/go-zero/core/stores/monc" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" -) - -var prefixCommentCacheKey = "cache:comment:" - -type commentModel interface { - Insert(ctx context.Context, data *Comment) error - FindOne(ctx context.Context, id string) (*Comment, error) - Update(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) - Delete(ctx context.Context, id string) (int64, error) -} - -type defaultCommentModel struct { - conn *monc.Model -} - -func newDefaultCommentModel(conn *monc.Model) *defaultCommentModel { - return &defaultCommentModel{conn: conn} -} - -func (m *defaultCommentModel) Insert(ctx context.Context, data *Comment) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - key := prefixCommentCacheKey + data.ID.Hex() - _, err := m.conn.InsertOne(ctx, key, data) - return err -} - -func (m *defaultCommentModel) FindOne(ctx context.Context, id string) (*Comment, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data Comment - key := prefixCommentCacheKey + id - err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case monc.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultCommentModel) Update(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) { - data.UpdateAt = time.Now() - key := prefixCommentCacheKey + data.ID.Hex() - res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data}) - return res, err -} - -func (m *defaultCommentModel) Delete(ctx context.Context, id string) (int64, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return 0, ErrInvalidObjectId - } - key := prefixCommentCacheKey + id - res, err := m.conn.DeleteOne(ctx, key, bson.M{"_id": oid}) - return res, err -} diff --git a/internal/model/mongo/comment_types.go b/internal/model/mongo/comment_types.go deleted file mode 100644 index f82cabc..0000000 --- a/internal/model/mongo/comment_types.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Comment struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` -} diff --git a/internal/model/mongo/error.go b/internal/model/mongo/error.go deleted file mode 100644 index 27d9244..0000000 --- a/internal/model/mongo/error.go +++ /dev/null @@ -1,12 +0,0 @@ -package model - -import ( - "errors" - - "github.com/zeromicro/go-zero/core/stores/mon" -) - -var ( - ErrNotFound = mon.ErrNotFound - ErrInvalidObjectId = errors.New("invalid objectId") -) diff --git a/internal/model/mongo/post_likes_model.go b/internal/model/mongo/post_likes_model.go deleted file mode 100644 index 9d1a52a..0000000 --- a/internal/model/mongo/post_likes_model.go +++ /dev/null @@ -1,25 +0,0 @@ -package model - -import "github.com/zeromicro/go-zero/core/stores/mon" - -var _ Post_likesModel = (*customPost_likesModel)(nil) - -type ( - // Post_likesModel is an interface to be customized, add more methods here, - // and implement the added methods in customPost_likesModel. - Post_likesModel interface { - post_likesModel - } - - customPost_likesModel struct { - *defaultPost_likesModel - } -) - -// NewPost_likesModel returns a model for the mongo. -func NewPost_likesModel(url, db, collection string) Post_likesModel { - conn := mon.MustNewModel(url, db, collection) - return &customPost_likesModel{ - defaultPost_likesModel: newDefaultPost_likesModel(conn), - } -} diff --git a/internal/model/mongo/post_likes_model_gen.go b/internal/model/mongo/post_likes_model_gen.go deleted file mode 100644 index e0499b7..0000000 --- a/internal/model/mongo/post_likes_model_gen.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package model - -import ( - "context" - "time" - - "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" -) - -type post_likesModel interface { - Insert(ctx context.Context, data *Post_likes) error - FindOne(ctx context.Context, id string) (*Post_likes, error) - Update(ctx context.Context, data *Post_likes) (*mongo.UpdateResult, error) - Delete(ctx context.Context, id string) (int64, error) -} - -type defaultPost_likesModel struct { - conn *mon.Model -} - -func newDefaultPost_likesModel(conn *mon.Model) *defaultPost_likesModel { - return &defaultPost_likesModel{conn: conn} -} - -func (m *defaultPost_likesModel) Insert(ctx context.Context, data *Post_likes) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - _, err := m.conn.InsertOne(ctx, data) - return err -} - -func (m *defaultPost_likesModel) FindOne(ctx context.Context, id string) (*Post_likes, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data Post_likes - - err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case mon.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultPost_likesModel) Update(ctx context.Context, data *Post_likes) (*mongo.UpdateResult, error) { - data.UpdateAt = time.Now() - - res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data}) - return res, err -} - -func (m *defaultPost_likesModel) Delete(ctx context.Context, id string) (int64, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return 0, ErrInvalidObjectId - } - - res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid}) - return res, err -} diff --git a/internal/model/mongo/post_likes_types.go b/internal/model/mongo/post_likes_types.go deleted file mode 100644 index 5b8f595..0000000 --- a/internal/model/mongo/post_likes_types.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Post_likes struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` -} diff --git a/internal/model/mongo/post_model.go b/internal/model/mongo/post_model.go deleted file mode 100644 index 096dda8..0000000 --- a/internal/model/mongo/post_model.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -import ( - "github.com/zeromicro/go-zero/core/stores/cache" - "github.com/zeromicro/go-zero/core/stores/monc" -) - -var _ PostModel = (*customPostModel)(nil) - -type ( - // PostModel is an interface to be customized, add more methods here, - // and implement the added methods in customPostModel. - PostModel interface { - postModel - } - - customPostModel struct { - *defaultPostModel - } -) - -// NewPostModel returns a model for the mongo. -func NewPostModel(url, db, collection string, c cache.CacheConf) PostModel { - conn := monc.MustNewModel(url, db, collection, c) - return &customPostModel{ - defaultPostModel: newDefaultPostModel(conn), - } -} diff --git a/internal/model/mongo/post_model_gen.go b/internal/model/mongo/post_model_gen.go deleted file mode 100644 index c7aa965..0000000 --- a/internal/model/mongo/post_model_gen.go +++ /dev/null @@ -1,77 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package model - -import ( - "context" - "time" - - "github.com/zeromicro/go-zero/core/stores/monc" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" -) - -var prefixPostCacheKey = "cache:post:" - -type postModel interface { - Insert(ctx context.Context, data *Post) error - FindOne(ctx context.Context, id string) (*Post, error) - Update(ctx context.Context, data *Post) (*mongo.UpdateResult, error) - Delete(ctx context.Context, id string) (int64, error) -} - -type defaultPostModel struct { - conn *monc.Model -} - -func newDefaultPostModel(conn *monc.Model) *defaultPostModel { - return &defaultPostModel{conn: conn} -} - -func (m *defaultPostModel) Insert(ctx context.Context, data *Post) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - key := prefixPostCacheKey + data.ID.Hex() - _, err := m.conn.InsertOne(ctx, key, data) - return err -} - -func (m *defaultPostModel) FindOne(ctx context.Context, id string) (*Post, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data Post - key := prefixPostCacheKey + id - err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case monc.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultPostModel) Update(ctx context.Context, data *Post) (*mongo.UpdateResult, error) { - data.UpdateAt = time.Now() - key := prefixPostCacheKey + data.ID.Hex() - res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data}) - return res, err -} - -func (m *defaultPostModel) Delete(ctx context.Context, id string) (int64, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return 0, ErrInvalidObjectId - } - key := prefixPostCacheKey + id - res, err := m.conn.DeleteOne(ctx, key, bson.M{"_id": oid}) - return res, err -} diff --git a/internal/model/mongo/post_types.go b/internal/model/mongo/post_types.go deleted file mode 100644 index 1a5802f..0000000 --- a/internal/model/mongo/post_types.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Post struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` -} diff --git a/internal/model/mongo/tags_model.go b/internal/model/mongo/tags_model.go deleted file mode 100644 index 6863721..0000000 --- a/internal/model/mongo/tags_model.go +++ /dev/null @@ -1,25 +0,0 @@ -package model - -import "github.com/zeromicro/go-zero/core/stores/mon" - -var _ TagsModel = (*customTagsModel)(nil) - -type ( - // TagsModel is an interface to be customized, add more methods here, - // and implement the added methods in customTagsModel. - TagsModel interface { - tagsModel - } - - customTagsModel struct { - *defaultTagsModel - } -) - -// NewTagsModel returns a model for the mongo. -func NewTagsModel(url, db, collection string) TagsModel { - conn := mon.MustNewModel(url, db, collection) - return &customTagsModel{ - defaultTagsModel: newDefaultTagsModel(conn), - } -} diff --git a/internal/model/mongo/tags_model_gen.go b/internal/model/mongo/tags_model_gen.go deleted file mode 100644 index db82d2b..0000000 --- a/internal/model/mongo/tags_model_gen.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package model - -import ( - "context" - "time" - - "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" -) - -type tagsModel interface { - Insert(ctx context.Context, data *Tags) error - FindOne(ctx context.Context, id string) (*Tags, error) - Update(ctx context.Context, data *Tags) (*mongo.UpdateResult, error) - Delete(ctx context.Context, id string) (int64, error) -} - -type defaultTagsModel struct { - conn *mon.Model -} - -func newDefaultTagsModel(conn *mon.Model) *defaultTagsModel { - return &defaultTagsModel{conn: conn} -} - -func (m *defaultTagsModel) Insert(ctx context.Context, data *Tags) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - _, err := m.conn.InsertOne(ctx, data) - return err -} - -func (m *defaultTagsModel) FindOne(ctx context.Context, id string) (*Tags, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data Tags - - err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case mon.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultTagsModel) Update(ctx context.Context, data *Tags) (*mongo.UpdateResult, error) { - data.UpdateAt = time.Now() - - res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data}) - return res, err -} - -func (m *defaultTagsModel) Delete(ctx context.Context, id string) (int64, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return 0, ErrInvalidObjectId - } - - res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid}) - return res, err -} diff --git a/internal/model/mongo/tags_types.go b/internal/model/mongo/tags_types.go deleted file mode 100644 index 6972376..0000000 --- a/internal/model/mongo/tags_types.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Tags struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` -} diff --git a/internal/server/commentservice/comment_service_server.go b/internal/server/commentservice/comment_service_server.go deleted file mode 100644 index 8e4eab8..0000000 --- a/internal/server/commentservice/comment_service_server.go +++ /dev/null @@ -1,71 +0,0 @@ -// 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.OKResp, 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) -} - -// LikeComment 點讚/取消讚 評論 -func (s *CommentServiceServer) LikeComment(ctx context.Context, in *tweeting.LikeReq) (*tweeting.OKResp, error) { - l := commentservicelogic.NewLikeCommentLogic(ctx, s.svcCtx) - return l.LikeComment(in) -} - -// GetLikeStatus 取得讚/不讚評論狀態 -func (s *CommentServiceServer) GetLikeStatus(ctx context.Context, in *tweeting.LikeReq) (*tweeting.OKResp, error) { - l := commentservicelogic.NewGetLikeStatusLogic(ctx, s.svcCtx) - return l.GetLikeStatus(in) -} - -// LikeList 取得讚/不讚評論列表 -func (s *CommentServiceServer) LikeList(ctx context.Context, in *tweeting.LikeListReq) (*tweeting.LikeListResp, error) { - l := commentservicelogic.NewLikeListLogic(ctx, s.svcCtx) - return l.LikeList(in) -} - -// CountLike 取得讚/不讚評論數量 -func (s *CommentServiceServer) CountLike(ctx context.Context, in *tweeting.LikeCountReq) (*tweeting.LikeCountResp, error) { - l := commentservicelogic.NewCountLikeLogic(ctx, s.svcCtx) - return l.CountLike(in) -} diff --git a/internal/server/postservice/post_service_server.go b/internal/server/postservice/post_service_server.go deleted file mode 100644 index b5fdaad..0000000 --- a/internal/server/postservice/post_service_server.go +++ /dev/null @@ -1,71 +0,0 @@ -// 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/postservice" - "app-cloudep-tweeting-service/internal/svc" -) - -type PostServiceServer struct { - svcCtx *svc.ServiceContext - tweeting.UnimplementedPostServiceServer -} - -func NewPostServiceServer(svcCtx *svc.ServiceContext) *PostServiceServer { - return &PostServiceServer{ - svcCtx: svcCtx, - } -} - -// NewPost 新增貼文 -func (s *PostServiceServer) NewPost(ctx context.Context, in *tweeting.NewPostReq) (*tweeting.PostResp, error) { - l := postservicelogic.NewNewPostLogic(ctx, s.svcCtx) - return l.NewPost(in) -} - -// DeletePost 刪除貼文 -func (s *PostServiceServer) DeletePost(ctx context.Context, in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) { - l := postservicelogic.NewDeletePostLogic(ctx, s.svcCtx) - return l.DeletePost(in) -} - -// UpdatePost 更新貼文 -func (s *PostServiceServer) UpdatePost(ctx context.Context, in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) { - l := postservicelogic.NewUpdatePostLogic(ctx, s.svcCtx) - return l.UpdatePost(in) -} - -// ListPosts 查詢貼文 -func (s *PostServiceServer) ListPosts(ctx context.Context, in *tweeting.QueryPostsReq) (*tweeting.ListPostsResp, error) { - l := postservicelogic.NewListPostsLogic(ctx, s.svcCtx) - return l.ListPosts(in) -} - -// Like 點讚/取消讚 貼文 -func (s *PostServiceServer) Like(ctx context.Context, in *tweeting.LikeReq) (*tweeting.OKResp, error) { - l := postservicelogic.NewLikeLogic(ctx, s.svcCtx) - return l.Like(in) -} - -// GetLikeStatus 取得讚/不讚狀態 -func (s *PostServiceServer) GetLikeStatus(ctx context.Context, in *tweeting.LikeReq) (*tweeting.OKResp, error) { - l := postservicelogic.NewGetLikeStatusLogic(ctx, s.svcCtx) - return l.GetLikeStatus(in) -} - -// LikeList 取得讚/不讚列表 -func (s *PostServiceServer) LikeList(ctx context.Context, in *tweeting.LikeListReq) (*tweeting.LikeListResp, error) { - l := postservicelogic.NewLikeListLogic(ctx, s.svcCtx) - return l.LikeList(in) -} - -// CountLike 取得讚/不讚數量 -func (s *PostServiceServer) CountLike(ctx context.Context, in *tweeting.LikeCountReq) (*tweeting.LikeCountResp, error) { - l := postservicelogic.NewCountLikeLogic(ctx, s.svcCtx) - return l.CountLike(in) -} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go deleted file mode 100644 index 37ac177..0000000 --- a/internal/svc/service_context.go +++ /dev/null @@ -1,13 +0,0 @@ -package svc - -import "app-cloudep-tweeting-service/internal/config" - -type ServiceContext struct { - Config config.Config -} - -func NewServiceContext(c config.Config) *ServiceContext { - return &ServiceContext{ - Config: c, - } -} diff --git a/tweeting.go b/tweeting.go deleted file mode 100644 index 64e8540..0000000 --- a/tweeting.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "flag" - "fmt" - - "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/config" - commentserviceServer "app-cloudep-tweeting-service/internal/server/commentservice" - postserviceServer "app-cloudep-tweeting-service/internal/server/postservice" - "app-cloudep-tweeting-service/internal/svc" - - "github.com/zeromicro/go-zero/core/conf" - "github.com/zeromicro/go-zero/core/service" - "github.com/zeromicro/go-zero/zrpc" - "google.golang.org/grpc" - "google.golang.org/grpc/reflection" -) - -var configFile = flag.String("f", "etc/tweeting.yaml", "the config file") - -func main() { - flag.Parse() - - var c config.Config - conf.MustLoad(*configFile, &c) - ctx := svc.NewServiceContext(c) - - s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { - tweeting.RegisterPostServiceServer(grpcServer, postserviceServer.NewPostServiceServer(ctx)) - tweeting.RegisterCommentServiceServer(grpcServer, commentserviceServer.NewCommentServiceServer(ctx)) - - if c.Mode == service.DevMode || c.Mode == service.TestMode { - reflection.Register(grpcServer) - } - }) - defer s.Stop() - - fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) - s.Start() -} -- 2.40.1 From f0816e0c93e9ead27b54f8c0e4d93434a8fbfd4f Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Fri, 30 Aug 2024 10:44:35 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=B0=87=20post=20service=20=E5=AF=AB?= =?UTF-8?q?=E5=AE=8C=E5=8A=A0=E4=B8=8A=E6=B8=AC=E8=A9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 22 +- etc/tweeting.yaml | 14 ++ .../mongodb/20240829054501_post.up.js | 9 + generate/protobuf/tweeting.proto | 201 +++++------------- go.mod | 108 ++++++++++ internal/config/config.go | 15 ++ internal/domain/const.go | 13 ++ internal/domain/errors.go | 17 ++ internal/domain/status.go | 12 ++ .../logic/postservice/create_post_logic.go | 114 ++++++++++ .../postservice/create_post_logic_test.go | 107 ++++++++++ .../logic/postservice/delete_post_logic.go | 63 ++++++ .../postservice/delete_post_logic_test.go | 81 +++++++ .../logic/postservice/list_posts_logic.go | 139 ++++++++++++ .../postservice/list_posts_logic_test.go | 164 ++++++++++++++ .../logic/postservice/update_post_logic.go | 100 +++++++++ .../postservice/update_post_logic_test.go | 118 ++++++++++ internal/mock/lib/validate.go | 73 +++++++ internal/mock/model/post_model.go | 152 +++++++++++++ internal/mock/model/post_model_gen.go | 101 +++++++++ internal/model/mongo/comment_model.go | 25 +++ internal/model/mongo/comment_model_gen.go | 74 +++++++ internal/model/mongo/comment_types.go | 14 ++ internal/model/mongo/error.go | 12 ++ internal/model/mongo/post_model.go | 185 ++++++++++++++++ internal/model/mongo/post_model_gen.go | 74 +++++++ internal/model/mongo/post_types.go | 32 +++ .../server/postservice/post_service_server.go | 53 +++++ internal/svc/init_mongo.go | 20 ++ internal/svc/service_context.go | 24 +++ tweeting.go | 39 ++++ 31 files changed, 2022 insertions(+), 153 deletions(-) create mode 100644 etc/tweeting.yaml create mode 100644 generate/database/mongodb/20240829054501_post.up.js create mode 100644 go.mod create mode 100755 internal/config/config.go create mode 100644 internal/domain/const.go create mode 100644 internal/domain/errors.go create mode 100644 internal/domain/status.go create mode 100644 internal/logic/postservice/create_post_logic.go create mode 100644 internal/logic/postservice/create_post_logic_test.go create mode 100644 internal/logic/postservice/delete_post_logic.go create mode 100644 internal/logic/postservice/delete_post_logic_test.go create mode 100644 internal/logic/postservice/list_posts_logic.go create mode 100644 internal/logic/postservice/list_posts_logic_test.go create mode 100644 internal/logic/postservice/update_post_logic.go create mode 100644 internal/logic/postservice/update_post_logic_test.go create mode 100644 internal/mock/lib/validate.go create mode 100644 internal/mock/model/post_model.go create mode 100644 internal/mock/model/post_model_gen.go create mode 100644 internal/model/mongo/comment_model.go create mode 100644 internal/model/mongo/comment_model_gen.go create mode 100644 internal/model/mongo/comment_types.go create mode 100644 internal/model/mongo/error.go create mode 100644 internal/model/mongo/post_model.go create mode 100644 internal/model/mongo/post_model_gen.go create mode 100644 internal/model/mongo/post_types.go create mode 100644 internal/server/postservice/post_service_server.go create mode 100644 internal/svc/init_mongo.go create mode 100644 internal/svc/service_context.go create mode 100644 tweeting.go diff --git a/Makefile b/Makefile index 5a391e5..7872af5 100644 --- a/Makefile +++ b/Makefile @@ -49,9 +49,19 @@ build-docker: gen-mongo-model: # 建立 rpc 資料庫 # 只產生 Model 剩下的要自己撰寫,連欄位名稱也是 - goctl model mongo -c no -t post --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) - goctl model mongo -c no -t comment --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) - goctl model mongo -t tags --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) - goctl model mongo -t post_likes --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) - goctl model mongo -t comment_likes --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) - @echo "Generate mongo model files successfully" \ No newline at end of file + goctl model mongo -t post --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) + goctl model mongo -t comment --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) +# goctl model mongo -t tags --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) +# goctl model mongo -t post_likes --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) +# goctl model mongo -t comment_likes --dir ./internal/model/mongo --style $(GO_ZERO_STYLE) + @echo "Generate mongo model files successfully" + +.PHONY: mock-gen +mock-gen: # 建立 mock 資料 + mockgen -source=./internal/model/mongo/post_model_gen.go -destination=./internal/mock/model/post_model_gen.go -package=mock + mockgen -source=./internal/model/mongo/post_model.go -destination=./internal/mock/model/post_model.go -package=mock + @echo "Generate mock files successfully" + +.PHONY: migrate-database +migrate-database: + migrate -source file://generate/database/migrations/mongodb -database 'mongodb://127.0.0.1:27017/digimon_tweeting' up diff --git a/etc/tweeting.yaml b/etc/tweeting.yaml new file mode 100644 index 0000000..279f3cb --- /dev/null +++ b/etc/tweeting.yaml @@ -0,0 +1,14 @@ +Name: tweeting.rpc +ListenOn: 0.0.0.0:8080 +Etcd: + Hosts: + - 127.0.0.1:2379 + Key: tweeting.rpc + +Mongo: + Schema: mongodb + Host: 127.0.0.1 + User: "" + Password: "" + Port: "27017" + Database: digimon_tweeting \ No newline at end of file diff --git a/generate/database/mongodb/20240829054501_post.up.js b/generate/database/mongodb/20240829054501_post.up.js new file mode 100644 index 0000000..d2dabbb --- /dev/null +++ b/generate/database/mongodb/20240829054501_post.up.js @@ -0,0 +1,9 @@ +use digimon_tweeting; +db.post.createIndex({ "uid": 1}); +db.post.createIndex({ "status": 1}); +db.post.createIndex({ "is_ad": 1}); +db.post.createIndex({ "createAt": 1 }); +db.post.createIndex({ "uid": 1,"status": 1, "createAt": 1 }); +db.post.createIndex({ "uid": 1, "createAt": 1 }); + +// TODO 看是否有要刪除過多的索引,要在測試一下 \ No newline at end of file diff --git a/generate/protobuf/tweeting.proto b/generate/protobuf/tweeting.proto index be6b914..968a1aa 100644 --- a/generate/protobuf/tweeting.proto +++ b/generate/protobuf/tweeting.proto @@ -1,27 +1,34 @@ syntax = "proto3"; package tweeting; -option go_package="./tweeting"; +option go_package = "./tweeting"; -// 基本回應 -message OKResp {} +// ========== 基本回應 =========== +message OKResp {} // 空的請求 -message NoneReq {} +message NoneReq {} // 分頁信息 message Pager { - int64 total =1; // 總數量 - int64 size=2; // 每頁數量 - int64 index=3; // 當前頁碼 + int64 total = 1; // 總數量 + int64 size = 2; // 每頁數量 + int64 index = 3; // 當前頁碼 } -// 新增貼文的請求 +// ========== 貼文區 =========== + +// ------ NewPost 新增貼文-------- message NewPostReq { - int64 user_id = 1; // 發佈貼文的用戶ID - string content = 2; // 貼文內容 - repeated string tags = 3; // 貼文相關標籤 - repeated string media_url = 4; // 這筆文章的所有 Media URL - bool is_ad = 5; // 是否為廣告 + string uid = 1; // 發佈貼文的用戶ID + string content = 2; // 貼文內容 + repeated string tags = 3; // 貼文相關標籤 + repeated Media media = 4; // 這筆文章的所有 Media URL + bool is_ad = 5; // 是否為廣告 +} + +message Media { + string type = 1; + string url = 2; } // 貼文回應 @@ -29,169 +36,69 @@ message PostResp { string post_id = 1; // 創建成功的貼文ID } +// ------ DeletePost 刪除貼文 ------ + // 刪除貼文的請求 message DeletePostsReq { - repeated string post_id = 1; // 貼文ID + repeated string post_id = 1; // 貼文ID } +// ------ UpdatePost 更新貼文 ------ // 更新貼文的請求 message UpdatePostReq { - string post_id = 1; // 貼文ID - repeated string tags = 2; // 新的標籤列表 - repeated string media_url = 3; // 這筆文章的所有 Media URL - optional string content = 4; // 新的貼文內容 - optional int64 like_count = 5; // 喜歡數量 - optional int64 dislike_count = 6; // 不喜歡數量 + string post_id = 1; // 貼文ID + repeated string tags = 2; // 新的標籤列表 + repeated Media media = 3; // 這筆文章的所有 Media URL + optional string content = 4; // 新的貼文內容 + optional int64 like_count = 5; // 喜歡數量 + optional int64 dislike_count = 6; // 不喜歡數量 } +// ------ListPosts 查詢貼文 ------ // 查詢貼文的請求 message QueryPostsReq { - repeated int64 user_id = 1; // 可選:根據用戶ID篩選貼文 - repeated int64 id = 2; // 可選:根據貼文ID篩選貼文 - repeated string tags = 3; // 可選:根據標籤篩選貼文 - optional bool only_ads = 4; // 可選:是否只顯示廣告 - int32 page_index = 5; // 分頁的頁碼 - int32 page_size = 6; // 每頁顯示的數量 + repeated string uid = 1; // 可選:根據用戶ID篩選貼文 + repeated string post_id = 2; // 可選:根據貼文ID篩選貼文 + optional int32 only_ads = 3; // 可選:是否只顯示廣告 0 不篩選 1 只顯示廣告 2 不顯示廣告 + int32 page_index = 4; // 分頁的頁碼 + int32 page_size = 5; // 每頁顯示的數量 } // 貼文詳情 message PostDetailItem { - string post_id = 1; // 貼文ID - int64 user_id = 2; // 發佈用戶ID - string content = 3; // 貼文內容 - repeated string tags = 4; // 標籤 - repeated string media_url = 5; // 圖片URL - bool is_ad = 6; // 是否為廣告 - int64 created_at = 7; // 發佈時間 - int64 update_at = 8; // 更新時間 - int64 like_count = 9; // 讚數 - int64 dislike_count = 10; // 不喜歡數量 + string post_id = 1; // 貼文ID + string uid = 2; // 發佈用戶ID + string content = 3; // 貼文內容 + repeated string tags = 4; // 標籤 + repeated Media media = 5; // 圖片URL + bool is_ad = 6; // 是否為廣告 + int64 created_at = 7; // 發佈時間 + int64 update_at = 8; // 更新時間 + int64 like_count = 9; // 讚數 + int64 dislike_count = 10; // 不喜歡數量 } // 貼文列表回應 message ListPostsResp { repeated PostDetailItem posts = 1; // 貼文列表 - Pager page =2; -} - -// 讚/不讚請求 -message LikeReq { - string target_id = 1; // 目標ID(可以是貼文ID或評論ID) - int64 user_id = 2; // 點讚的用戶ID - int64 like_type = 3; // 讚或爛的類型 -} - -// 讚/不讚項目 -message LikeItem { - string target_id = 1; // 目標ID(可以是貼文ID或評論ID) - int64 user_id = 2; // 點讚的用戶ID - int64 like_type = 3; // 讚或爛的類型 -} - -// 讚/不讚列表請求 -message LikeListReq { - string target_id = 1; // 目標ID(可以是貼文ID或評論ID) - int64 like_type = 2; // 讚或爛的類型 - int32 page_index = 3; // 當前頁碼 - int32 page_size = 4; // 每頁顯示數量 -} - -// 讚/不讚列表回應 -message LikeListResp { - repeated LikeItem list = 1; // 讚/不讚列表 Pager page = 2; } -// 讚/不讚數量請求 -message LikeCountReq { - string target_id = 1; // 目標ID(可以是貼文ID或評論ID) - int64 like_type = 2; // 讚或爛的類型 +message ModifyLikeDislikeCountReq { + string post_id = 1; // 貼文的 ID + int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚 + bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少) + int64 count = 4; // 異動數量 } -// 讚/不讚數量回應 -message LikeCountResp { - string count = 1; // 總共按讚數量 -} - -// 評論貼文的請求 -message CommentPostReq { - string post_id = 1; // 貼文ID - int64 user_id = 2; // 評論者ID - string content = 3; // 評論內容 -} - -// 查詢評論的請求 -message GetCommentsReq { - string post_id = 1; // 貼文ID - int32 page_index = 2; // 分頁頁碼 - int32 page_size = 3; // 每頁顯示數量 -} - -// 評論詳情 -message CommentDetail { - string comment_id = 1; // 評論ID - int64 user_id = 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 { - string comment_id = 1; // 評論ID -} - -// 更新評論請求 -message UpdateCommentReq { - string comment_id = 1; // 評論ID - string content = 2; // 更新後的評論內容 -} - -// 定義貼文服務 +// ========== 定義貼文服務(最基本單位,不要把邏輯放進來,也考慮是否要做快取) ========== service PostService { - // NewPost 新增貼文 - rpc NewPost(NewPostReq) returns(PostResp); + // CreatePost 新增貼文 + rpc CreatePost(NewPostReq) returns (PostResp); // DeletePost 刪除貼文 rpc DeletePost(DeletePostsReq) returns (OKResp); // UpdatePost 更新貼文 rpc UpdatePost(UpdatePostReq) returns (OKResp); // ListPosts 查詢貼文 rpc ListPosts(QueryPostsReq) returns (ListPostsResp); - - // Like 點讚/取消讚 貼文 - rpc Like(LikeReq) returns (OKResp); - // GetLikeStatus 取得讚/不讚狀態 - rpc GetLikeStatus(LikeReq) returns (OKResp); - // LikeList 取得讚/不讚列表 - rpc LikeList(LikeListReq) returns (LikeListResp); - // CountLike 取得讚/不讚數量 - rpc CountLike(LikeCountReq) returns (LikeCountResp); } - -// 定義評論服務 -service CommentService { - // NewComment 發表評論 - rpc NewComment(CommentPostReq) returns (OKResp); - // GetComments 查詢評論 - rpc GetComments(GetCommentsReq) returns (GetCommentsResp); - // DeleteComment 刪除評論 - rpc DeleteComment(DeleteCommentReq) returns (OKResp); - // UpdateComment 更新評論 - rpc UpdateComment(UpdateCommentReq) returns (OKResp); - - // LikeComment 點讚/取消讚 評論 - rpc LikeComment(LikeReq) returns (OKResp); - // GetLikeStatus 取得讚/不讚評論狀態 - rpc GetLikeStatus(LikeReq) returns (OKResp); - // LikeList 取得讚/不讚評論列表 - rpc LikeList(LikeListReq) returns (LikeListResp); - // CountLike 取得讚/不讚評論數量 - rpc CountLike(LikeCountReq) returns (LikeCountResp); -} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ea41a6a --- /dev/null +++ b/go.mod @@ -0,0 +1,108 @@ +module app-cloudep-tweeting-service + +go 1.22.3 + +require ( + code.30cm.net/digimon/library-go/errs v1.2.4 + code.30cm.net/digimon/library-go/validator v1.0.0 + github.com/stretchr/testify v1.9.0 + github.com/zeromicro/go-zero v1.7.0 + go.mongodb.org/mongo-driver v1.16.0 + go.uber.org/mock v0.4.0 + google.golang.org/grpc v1.66.0 + google.golang.org/protobuf v1.34.2 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/openzipkin/zipkin-go v0.4.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/redis/go-redis/v9 v9.6.1 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect + go.etcd.io/etcd/api/v3 v3.5.15 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect + go.etcd.io/etcd/client/v3 v3.5.15 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/automaxprocs v1.5.3 // indirect + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.3 // indirect + k8s.io/apimachinery v0.29.4 // indirect + k8s.io/client-go v0.29.3 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100755 index 0000000..73cf966 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,15 @@ +package config + +import "github.com/zeromicro/go-zero/zrpc" + +type Config struct { + zrpc.RpcServerConf + Mongo struct { + Schema string + User string + Password string + Host string + Port string + Database string + } +} diff --git a/internal/domain/const.go b/internal/domain/const.go new file mode 100644 index 0000000..0e7211b --- /dev/null +++ b/internal/domain/const.go @@ -0,0 +1,13 @@ +package domain + +type AdType int32 + +func (a AdType) ToInt32() int32 { + return int32(a) +} + +const ( + AdTypeAll AdType = iota + AdTypeOnlyAd + AdTypeOnlyNotAd +) diff --git a/internal/domain/errors.go b/internal/domain/errors.go new file mode 100644 index 0000000..6c63b9d --- /dev/null +++ b/internal/domain/errors.go @@ -0,0 +1,17 @@ +package domain + +type ErrorCode uint32 + +func (e ErrorCode) ToUint32() uint32 { + return uint32(e) +} + +// Error Code 統一這邊改 +const ( + _ = iota + PostMongoErrorCode ErrorCode = iota + CreatePostError + DelPostError + UpdatePostError + ListPostError +) diff --git a/internal/domain/status.go b/internal/domain/status.go new file mode 100644 index 0000000..abe9593 --- /dev/null +++ b/internal/domain/status.go @@ -0,0 +1,12 @@ +package domain + +type TweetingStatus int8 + +func (t TweetingStatus) ToInt8() int8 { + return int8(t) +} + +const ( + TweetingStatusNotReviewedYet TweetingStatus = iota + 1 + TweetingStatusPass +) diff --git a/internal/logic/postservice/create_post_logic.go b/internal/logic/postservice/create_post_logic.go new file mode 100644 index 0000000..73023e7 --- /dev/null +++ b/internal/logic/postservice/create_post_logic.go @@ -0,0 +1,114 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/internal/domain" + model "app-cloudep-tweeting-service/internal/model/mongo" + + "code.30cm.net/digimon/library-go/errs/code" + + "context" + "fmt" + "strings" + + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/svc" + + ers "code.30cm.net/digimon/library-go/errs" + "github.com/zeromicro/go-zero/core/logx" +) + +type CreatePostLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCreatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreatePostLogic { + return &CreatePostLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// TODO 要調查一下內容如果存 html 是否有需要Encode +// 輸入的定義 -> 檢查用 +type newTweetingReq struct { + UID string `json:"uid" validate:"required"` + Content string `json:"content" validate:"required,lte=500"` // 貼文限制 500 字內 + Tags []string `json:"tags"` + MediaUrl []string `json:"media_url"` + IsAd bool `json:"is_ad"` // default false +} + +// 定義 Error + +// CreatePostError 0502102 資料庫錯誤 +func CreatePostError(s ...string) *ers.LibError { + return ers.NewError(code.CloudEPTweeting, code.DBError, + domain.CreatePostError.ToUint32(), + fmt.Sprintf("%s", strings.Join(s, " "))) +} + +// CreatePostErrorL logs error message and returns Error +func CreatePostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { + e := CreatePostError(s...) + l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) + + return e +} + +// CreatePost 新增貼文 +func (l *CreatePostLogic) CreatePost(in *tweeting.NewPostReq) (*tweeting.PostResp, error) { + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&newTweetingReq{ + UID: in.GetUid(), + Content: in.GetContent(), + }); err != nil { + // 錯誤代碼 05-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + // ============ prepare ============ + // 新增資料 + tweet := &model.Post{ + UID: in.GetUid(), + Content: in.GetContent(), + Status: domain.TweetingStatusNotReviewedYet.ToInt8(), + IsAd: in.IsAd, + } + if len(in.GetTags()) > 0 { + // 存在貼文內的不提供搜尋,純顯示用,只不過在原始的tag 發生變動的時候,並不會一起改變 + // 搜尋會貼文與Tag 的表會再另外一邊做關聯 + // 暫時業務邏輯上tag 只提供新增,不提供修改以及刪除,故目前版本可行 + tweet.Tags = in.GetTags() + } + + if len(in.Media) > 0 { + // 將 Media 存入 + var media []model.Media + for _, item := range in.GetMedia() { + media = append(media, model.Media{ + Links: item.Url, + Type: item.Type, + }) + } + tweet.MediaURL = media + } + // ============ insert ============ + err := l.svcCtx.PostModel.Insert(l.ctx, tweet) + if err != nil { + e := CreatePostErrorL( + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "req", Value: in}, + {Key: "func", Value: "PostModel.Insert"}, + {Key: "err", Value: err}, + }, + "failed to add new post").Wrap(err) + return nil, e + } + + return &tweeting.PostResp{ + PostId: tweet.ID.Hex(), + }, nil +} diff --git a/internal/logic/postservice/create_post_logic_test.go b/internal/logic/postservice/create_post_logic_test.go new file mode 100644 index 0000000..d7deaf5 --- /dev/null +++ b/internal/logic/postservice/create_post_logic_test.go @@ -0,0 +1,107 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "testing" + + mocklib "app-cloudep-tweeting-service/internal/mock/lib" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" +) + +func TestCreatePost(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockPostModel := mockmodel.NewMockPostModel(ctrl) + mockValidate := mocklib.NewMockValidate(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + PostModel: mockPostModel, + Validate: mockValidate, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.NewPostReq + prepare func() + expectErr bool + }{ + { + name: "成功創建貼文", + input: &tweeting.NewPostReq{ + Uid: "12345", + Content: "Test content", + IsAd: false, + Tags: []string{"tag1", "tag2"}, + Media: []*tweeting.Media{ + { + Url: "http://example.com/image.png", + Type: "image", + }, + }, + }, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + mockPostModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1) + }, + expectErr: false, + }, + { + name: "驗證失敗", + input: &tweeting.NewPostReq{ + Uid: "", + Content: "", + }, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1) + }, + expectErr: true, + }, + { + name: "插入貼文失敗", + input: &tweeting.NewPostReq{ + Uid: "12345", + Content: "Test content", + IsAd: false, + }, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + mockPostModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(errors.New("insert failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 CreatePostLogic + logic := CreatePostLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 CreatePost + _, err := logic.CreatePost(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/internal/logic/postservice/delete_post_logic.go b/internal/logic/postservice/delete_post_logic.go new file mode 100644 index 0000000..33a9e81 --- /dev/null +++ b/internal/logic/postservice/delete_post_logic.go @@ -0,0 +1,63 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/internal/domain" + "context" + "fmt" + "strings" + + ers "code.30cm.net/digimon/library-go/errs" + "code.30cm.net/digimon/library-go/errs/code" + + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type DeletePostLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewDeletePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeletePostLogic { + return &DeletePostLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// DeletePostError 0502103 資料庫錯誤 +func DeletePostError(s ...string) *ers.LibError { + return ers.NewError(code.CloudEPTweeting, code.DBError, + domain.DelPostError.ToUint32(), + fmt.Sprintf("%s", strings.Join(s, " "))) +} + +// DeletePostErrorL logs error message and returns Error +func DeletePostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { + e := DeletePostError(s...) + l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) + + return e +} + +// DeletePost 刪除貼文 +func (l *DeletePostLogic) DeletePost(in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) { + _, err := l.svcCtx.PostModel.DeleteMany(l.ctx, in.GetPostId()...) + if err != nil { + e := DeletePostErrorL( + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "req", Value: in}, + {Key: "func", Value: "PostModel.DeleteMany"}, + {Key: "err", Value: err}, + }, + "failed to del post").Wrap(err) + return nil, e + } + + return &tweeting.OKResp{}, nil +} diff --git a/internal/logic/postservice/delete_post_logic_test.go b/internal/logic/postservice/delete_post_logic_test.go new file mode 100644 index 0000000..adb2cbe --- /dev/null +++ b/internal/logic/postservice/delete_post_logic_test.go @@ -0,0 +1,81 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" +) + +func TestDeletePost(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockPostModel := mockmodel.NewMockPostModel(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + PostModel: mockPostModel, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.DeletePostsReq + prepare func() + expectErr bool + }{ + { + name: "成功刪除貼文", + input: &tweeting.DeletePostsReq{ + PostId: []string{"12345", "67890"}, + }, + prepare: func() { + // 模擬 DeleteMany 成功 + mockPostModel.EXPECT().DeleteMany(gomock.Any(), "12345", "67890").Return(int64(2), nil).Times(1) + }, + expectErr: false, + }, + { + name: "刪除貼文失敗", + input: &tweeting.DeletePostsReq{ + PostId: []string{"12345", "67890"}, + }, + prepare: func() { + // 模擬 DeleteMany 失敗 + mockPostModel.EXPECT().DeleteMany(gomock.Any(), "12345", "67890").Return(int64(0), errors.New("delete failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 DeletePostLogic + logic := DeletePostLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 DeletePost + _, err := logic.DeletePost(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/internal/logic/postservice/list_posts_logic.go b/internal/logic/postservice/list_posts_logic.go new file mode 100644 index 0000000..a3e7f08 --- /dev/null +++ b/internal/logic/postservice/list_posts_logic.go @@ -0,0 +1,139 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/internal/domain" + model "app-cloudep-tweeting-service/internal/model/mongo" + "context" + "fmt" + "strings" + + ers "code.30cm.net/digimon/library-go/errs" + "code.30cm.net/digimon/library-go/errs/code" + "google.golang.org/protobuf/proto" + + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ListPostsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewListPostsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPostsLogic { + return &ListPostsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 只列出要驗證的資料 +type listReq struct { + OnlyAdds int32 `json:"only_adds" validate:"oneof=0 1 2 3"` + PageSize int64 `json:"page_size" validate:"required"` + PageIndex int64 `json:"page_index" validate:"required"` +} + +// ListPostError 0502105 資料庫錯誤 +func ListPostError(s ...string) *ers.LibError { + return ers.NewError(code.CloudEPTweeting, code.DBError, + domain.ListPostError.ToUint32(), + fmt.Sprintf("%s", strings.Join(s, " "))) +} + +// ListPostErrorL logs error message and returns Error +func ListPostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { + e := ListPostError(s...) + l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) + + return e +} + +// 將單個 Post 轉換為 PostDetailItem +func convertToPostDetailItem(item *model.Post) *tweeting.PostDetailItem { + media := make([]*tweeting.Media, 0, len(item.MediaURL)) + for _, subItem := range item.MediaURL { + media = append(media, &tweeting.Media{ + Type: subItem.Type, + Url: subItem.Links, + }) + } + + return &tweeting.PostDetailItem{ + PostId: item.ID.Hex(), + Uid: item.UID, + Content: item.Content, + Tags: item.Tags, + Media: media, + IsAd: item.IsAd, + CreatedAt: item.CreateAt, + UpdateAt: item.UpdateAt, + LikeCount: int64(item.Like), + DislikeCount: int64(item.DisLike), + } +} + +// ListPosts 查詢貼文 -> 主流程 +func (l *ListPostsLogic) ListPosts(in *tweeting.QueryPostsReq) (*tweeting.ListPostsResp, error) { + // 將 PageSize 和 PageIndex 提前轉換為 int64 + pageSize := int64(in.GetPageSize()) + pageIndex := int64(in.GetPageIndex()) + + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&listReq{ + PageSize: pageSize, + PageIndex: pageIndex, + OnlyAdds: in.GetOnlyAds(), + }); err != nil { + // 錯誤代碼 05-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + + // 構建查詢條件 + query := &model.QueryPostModelReq{ + UID: in.GetUid(), + Id: in.GetPostId(), + PageSize: pageSize, + PageIndex: pageIndex, + } + + // 處理 OnlyAds 條件 + if in.OnlyAds != nil { + onlyAds := in.GetOnlyAds() + query.OnlyAds = proto.Bool(onlyAds == domain.AdTypeOnlyAd.ToInt32()) + } + + // 執行查詢 + find, count, err := l.svcCtx.PostModel.Find(l.ctx, query) + if err != nil { + e := ListPostErrorL( + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "query", Value: query}, + {Key: "func", Value: "PostModel.Find"}, + {Key: "err", Value: err}, + }, + "failed to find posts").Wrap(err) + return nil, e + } + + // 將查詢結果轉換為 API 回應格式 + result := make([]*tweeting.PostDetailItem, 0, count) + for _, item := range find { + result = append(result, convertToPostDetailItem(item)) + } + + // 返回結果 + return &tweeting.ListPostsResp{ + Posts: result, + Page: &tweeting.Pager{ + Total: count, + Index: pageIndex, + Size: pageSize, + }, + }, nil +} diff --git a/internal/logic/postservice/list_posts_logic_test.go b/internal/logic/postservice/list_posts_logic_test.go new file mode 100644 index 0000000..9e233df --- /dev/null +++ b/internal/logic/postservice/list_posts_logic_test.go @@ -0,0 +1,164 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + mocklib "app-cloudep-tweeting-service/internal/mock/lib" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" + model "app-cloudep-tweeting-service/internal/model/mongo" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "testing" + "time" + + "google.golang.org/protobuf/proto" + + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.uber.org/mock/gomock" +) + +func TestConvertToPostDetailItem(t *testing.T) { + // 構建測試數據 + postID := primitive.NewObjectID() + post := &model.Post{ + ID: postID, + UID: "12345", + Content: "Test Content", + Tags: []string{"tag1", "tag2"}, + MediaURL: []model.Media{ + {Type: "image", Links: "http://example.com/image.png"}, + {Type: "video", Links: "http://example.com/video.mp4"}, + }, + IsAd: true, + CreateAt: time.Now().Unix(), + UpdateAt: time.Now().Unix(), + Like: 10, + DisLike: 2, + } + + // 執行轉換 + result := convertToPostDetailItem(post) + + // 驗證結果 + assert.Equal(t, postID.Hex(), result.PostId) + assert.Equal(t, "12345", result.Uid) + assert.Equal(t, "Test Content", result.Content) + assert.Equal(t, []string{"tag1", "tag2"}, result.Tags) + assert.Equal(t, true, result.IsAd) + assert.Equal(t, int64(10), result.LikeCount) + assert.Equal(t, int64(2), result.DislikeCount) + + // 驗證 Media 的轉換 + assert.Len(t, result.Media, 2) + assert.Equal(t, "image", result.Media[0].Type) + assert.Equal(t, "http://example.com/image.png", result.Media[0].Url) + assert.Equal(t, "video", result.Media[1].Type) + assert.Equal(t, "http://example.com/video.mp4", result.Media[1].Url) +} + +func TestListPosts(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockPostModel := mockmodel.NewMockPostModel(ctrl) + mockValidate := mocklib.NewMockValidate(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + PostModel: mockPostModel, + Validate: mockValidate, + } + + // 構建測試數據 + queryReq := &tweeting.QueryPostsReq{ + PageSize: 10, + PageIndex: 1, + OnlyAds: proto.Int32(1), + } + + mockPosts := []*model.Post{ + { + ID: primitive.NewObjectID(), + UID: "12345", + Content: "Test Content 1", + Tags: []string{"tag1", "tag2"}, + MediaURL: []model.Media{ + {Type: "image", Links: "http://example.com/image1.png"}, + }, + IsAd: false, + CreateAt: time.Now().Unix(), + UpdateAt: time.Now().Unix(), + Like: 5, + DisLike: 1, + }, + { + ID: primitive.NewObjectID(), + UID: "67890", + Content: "Test Content 2", + Tags: []string{"tag3", "tag4"}, + MediaURL: []model.Media{ + {Type: "video", Links: "http://example.com/video1.mp4"}, + }, + IsAd: true, + CreateAt: time.Now().Unix(), + UpdateAt: time.Now().Unix(), + Like: 3, + DisLike: 0, + }, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.QueryPostsReq + prepare func() + expectErr bool + }{ + { + name: "成功查詢貼文", + input: queryReq, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + mockPostModel.EXPECT().Find(gomock.Any(), gomock.Any()).Return(mockPosts, int64(len(mockPosts)), nil).Times(1) + }, + expectErr: false, + }, + { + name: "查詢貼文失敗", + input: queryReq, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + mockPostModel.EXPECT().Find(gomock.Any(), gomock.Any()).Return(nil, int64(0), errors.New("find failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 ListPostsLogic + logic := ListPostsLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 ListPosts + resp, err := logic.ListPosts(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Len(t, resp.Posts, len(mockPosts)) + } + }) + } +} diff --git a/internal/logic/postservice/update_post_logic.go b/internal/logic/postservice/update_post_logic.go new file mode 100644 index 0000000..acdb501 --- /dev/null +++ b/internal/logic/postservice/update_post_logic.go @@ -0,0 +1,100 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/internal/domain" + model "app-cloudep-tweeting-service/internal/model/mongo" + "context" + "fmt" + "strings" + + ers "code.30cm.net/digimon/library-go/errs" + "code.30cm.net/digimon/library-go/errs/code" + "go.mongodb.org/mongo-driver/bson/primitive" + + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UpdatePostLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUpdatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePostLogic { + return &UpdatePostLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +type checkPostId struct { + PostID string `validate:"required"` + Content string `json:"content,omitempty" validate:"lte=500"` +} + +// UpdatePostError 0502104 資料庫錯誤 +func UpdatePostError(s ...string) *ers.LibError { + return ers.NewError(code.CloudEPTweeting, code.DBError, + domain.UpdatePostError.ToUint32(), + fmt.Sprintf("%s", strings.Join(s, " "))) +} + +// UpdatePostErrorL logs error message and returns Error +func UpdatePostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { + e := UpdatePostError(s...) + l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) + + return e +} + +// UpdatePost 更新貼文 +func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) { + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&checkPostId{ + PostID: in.GetPostId(), + Content: in.GetContent(), + }); err != nil { + // 錯誤代碼 05-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + // 沒有就沒有,有就走全覆蓋 + update := model.Post{} + oid, err := primitive.ObjectIDFromHex(in.GetPostId()) + if err != nil { + // 錯誤代碼 05-011-00 + return nil, ers.InvalidFormat("failed to get correct post id") + } + update.ID = oid + update.Tags = in.GetTags() + // 將 Media 存入 + var media []model.Media + for _, item := range in.GetMedia() { + media = append(media, model.Media{ + Links: item.Url, + Type: item.Type, + }) + } + update.MediaURL = media + update.Content = in.GetContent() + update.Like = uint64(in.GetLikeCount()) + update.DisLike = uint64(in.GetDislikeCount()) + + _, err = l.svcCtx.PostModel.UpdateOptional(l.ctx, &update) + if err != nil { + e := UpdatePostErrorL( + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "req", Value: in}, + {Key: "func", Value: "PostModel.UpdateOptional"}, + {Key: "err", Value: err}, + }, + "failed to update post", in.PostId).Wrap(err) + return nil, e + } + + return &tweeting.OKResp{}, nil +} diff --git a/internal/logic/postservice/update_post_logic_test.go b/internal/logic/postservice/update_post_logic_test.go new file mode 100644 index 0000000..1858572 --- /dev/null +++ b/internal/logic/postservice/update_post_logic_test.go @@ -0,0 +1,118 @@ +package postservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + mocklib "app-cloudep-tweeting-service/internal/mock/lib" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + + "go.mongodb.org/mongo-driver/mongo" + "google.golang.org/protobuf/proto" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" + + "testing" +) + +func TestUpdatePost(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockPostModel := mockmodel.NewMockPostModel(ctrl) + mockValidate := mocklib.NewMockValidate(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + PostModel: mockPostModel, + Validate: mockValidate, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.UpdatePostReq + prepare func() + expectErr bool + }{ + { + name: "成功更新貼文", + input: &tweeting.UpdatePostReq{ + PostId: "66cfdc1d6f8fe7eac1e52523", + Content: proto.String("Updated content"), + Tags: []string{"tag1", "tag2"}, + Media: []*tweeting.Media{ + { + Url: "http://example.com/image.png", + Type: "image", + }, + }, + LikeCount: proto.Int64(10), + DislikeCount: proto.Int64(2), + }, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 UpdateOptional 成功 + mockPostModel.EXPECT().UpdateOptional(gomock.Any(), gomock.Any()).Return(&mongo.UpdateResult{ + ModifiedCount: 1, + }, nil).Times(1) + }, + expectErr: false, + }, + { + name: "驗證失敗", + input: &tweeting.UpdatePostReq{ + PostId: "", + }, + prepare: func() { + // 模擬 Validate 失敗 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1) + }, + expectErr: true, + }, + { + name: "更新貼文失敗", + input: &tweeting.UpdatePostReq{ + PostId: "66cfdc1d6f8fe7eac1e52523", + Content: proto.String("Updated content"), + }, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 UpdateOptional 失敗 + mockPostModel.EXPECT().UpdateOptional(gomock.Any(), gomock.Any()).Return(&mongo.UpdateResult{ + ModifiedCount: 0, + }, errors.New("update failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 UpdatePostLogic + logic := UpdatePostLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 UpdatePost + _, err := logic.UpdatePost(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/internal/mock/lib/validate.go b/internal/mock/lib/validate.go new file mode 100644 index 0000000..dd852f8 --- /dev/null +++ b/internal/mock/lib/validate.go @@ -0,0 +1,73 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./validate.go +// +// Generated by this command: +// +// mockgen -source=./validate.go -destination=../../mock/lib/validate.go -package=lib +// + +// Package lib is a generated GoMock package. +package lib + +import ( + reflect "reflect" + + required "code.30cm.net/digimon/library-go/validator" + + gomock "go.uber.org/mock/gomock" +) + +// MockValidate is a mock of Validate interface. +type MockValidate struct { + ctrl *gomock.Controller + recorder *MockValidateMockRecorder +} + +// MockValidateMockRecorder is the mock recorder for MockValidate. +type MockValidateMockRecorder struct { + mock *MockValidate +} + +// NewMockValidate creates a new mock instance. +func NewMockValidate(ctrl *gomock.Controller) *MockValidate { + mock := &MockValidate{ctrl: ctrl} + mock.recorder = &MockValidateMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockValidate) EXPECT() *MockValidateMockRecorder { + return m.recorder +} + +// BindToValidator mocks base method. +func (m *MockValidate) BindToValidator(opts ...required.Option) error { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BindToValidator", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// BindToValidator indicates an expected call of BindToValidator. +func (mr *MockValidateMockRecorder) BindToValidator(opts ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BindToValidator", reflect.TypeOf((*MockValidate)(nil).BindToValidator), opts...) +} + +// ValidateAll mocks base method. +func (m *MockValidate) ValidateAll(obj any) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateAll", obj) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateAll indicates an expected call of ValidateAll. +func (mr *MockValidateMockRecorder) ValidateAll(obj any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAll", reflect.TypeOf((*MockValidate)(nil).ValidateAll), obj) +} diff --git a/internal/mock/model/post_model.go b/internal/mock/model/post_model.go new file mode 100644 index 0000000..bf3fd1b --- /dev/null +++ b/internal/mock/model/post_model.go @@ -0,0 +1,152 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/model/mongo/post_model.go +// +// Generated by this command: +// +// mockgen -source=./internal/model/mongo/post_model.go -destination=./internal/mock/model/post_model.go -package=mock +// + +// Package mock is a generated GoMock package. +package mock + +import ( + model "app-cloudep-tweeting-service/internal/model/mongo" + context "context" + reflect "reflect" + + mongo "go.mongodb.org/mongo-driver/mongo" + gomock "go.uber.org/mock/gomock" +) + +// MockPostModel is a mock of PostModel interface. +type MockPostModel struct { + ctrl *gomock.Controller + recorder *MockPostModelMockRecorder +} + +// MockPostModelMockRecorder is the mock recorder for MockPostModel. +type MockPostModelMockRecorder struct { + mock *MockPostModel +} + +// NewMockPostModel creates a new mock instance. +func NewMockPostModel(ctrl *gomock.Controller) *MockPostModel { + mock := &MockPostModel{ctrl: ctrl} + mock.recorder = &MockPostModelMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPostModel) EXPECT() *MockPostModelMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockPostModel) Delete(ctx context.Context, id string) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, id) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockPostModelMockRecorder) Delete(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockPostModel)(nil).Delete), ctx, id) +} + +// DeleteMany mocks base method. +func (m *MockPostModel) DeleteMany(ctx context.Context, id ...string) (int64, error) { + m.ctrl.T.Helper() + varargs := []any{ctx} + for _, a := range id { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteMany", varargs...) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteMany indicates an expected call of DeleteMany. +func (mr *MockPostModelMockRecorder) DeleteMany(ctx any, id ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx}, id...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteMany", reflect.TypeOf((*MockPostModel)(nil).DeleteMany), varargs...) +} + +// Find mocks base method. +func (m *MockPostModel) Find(ctx context.Context, param *model.QueryPostModelReq) ([]*model.Post, int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Find", ctx, param) + ret0, _ := ret[0].([]*model.Post) + ret1, _ := ret[1].(int64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// Find indicates an expected call of Find. +func (mr *MockPostModelMockRecorder) Find(ctx, param any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockPostModel)(nil).Find), ctx, param) +} + +// FindOne mocks base method. +func (m *MockPostModel) FindOne(ctx context.Context, id string) (*model.Post, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindOne", ctx, id) + ret0, _ := ret[0].(*model.Post) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindOne indicates an expected call of FindOne. +func (mr *MockPostModelMockRecorder) FindOne(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockPostModel)(nil).FindOne), ctx, id) +} + +// Insert mocks base method. +func (m *MockPostModel) Insert(ctx context.Context, data *model.Post) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, data) + ret0, _ := ret[0].(error) + return ret0 +} + +// Insert indicates an expected call of Insert. +func (mr *MockPostModelMockRecorder) Insert(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockPostModel)(nil).Insert), ctx, data) +} + +// Update mocks base method. +func (m *MockPostModel) Update(ctx context.Context, data *model.Post) (*mongo.UpdateResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, data) + ret0, _ := ret[0].(*mongo.UpdateResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockPostModelMockRecorder) Update(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockPostModel)(nil).Update), ctx, data) +} + +// UpdateOptional mocks base method. +func (m *MockPostModel) UpdateOptional(ctx context.Context, data *model.Post) (*mongo.UpdateResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateOptional", ctx, data) + ret0, _ := ret[0].(*mongo.UpdateResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateOptional indicates an expected call of UpdateOptional. +func (mr *MockPostModelMockRecorder) UpdateOptional(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOptional", reflect.TypeOf((*MockPostModel)(nil).UpdateOptional), ctx, data) +} diff --git a/internal/mock/model/post_model_gen.go b/internal/mock/model/post_model_gen.go new file mode 100644 index 0000000..4b22d6b --- /dev/null +++ b/internal/mock/model/post_model_gen.go @@ -0,0 +1,101 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/model/mongo/post_model_gen.go +// +// Generated by this command: +// +// mockgen -source=./internal/model/mongo/post_model_gen.go -destination=./internal/mock/model/post_model_gen.go -package=mock +// + +// Package mock is a generated GoMock package. +package mock + +import ( + model "app-cloudep-tweeting-service/internal/model/mongo" + context "context" + reflect "reflect" + + mongo "go.mongodb.org/mongo-driver/mongo" + gomock "go.uber.org/mock/gomock" +) + +// MockpostModel is a mock of postModel interface. +type MockpostModel struct { + ctrl *gomock.Controller + recorder *MockpostModelMockRecorder +} + +// MockpostModelMockRecorder is the mock recorder for MockpostModel. +type MockpostModelMockRecorder struct { + mock *MockpostModel +} + +// NewMockpostModel creates a new mock instance. +func NewMockpostModel(ctrl *gomock.Controller) *MockpostModel { + mock := &MockpostModel{ctrl: ctrl} + mock.recorder = &MockpostModelMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockpostModel) EXPECT() *MockpostModelMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockpostModel) Delete(ctx context.Context, id string) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, id) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockpostModelMockRecorder) Delete(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockpostModel)(nil).Delete), ctx, id) +} + +// FindOne mocks base method. +func (m *MockpostModel) FindOne(ctx context.Context, id string) (*model.Post, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindOne", ctx, id) + ret0, _ := ret[0].(*model.Post) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindOne indicates an expected call of FindOne. +func (mr *MockpostModelMockRecorder) FindOne(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockpostModel)(nil).FindOne), ctx, id) +} + +// Insert mocks base method. +func (m *MockpostModel) Insert(ctx context.Context, data *model.Post) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, data) + ret0, _ := ret[0].(error) + return ret0 +} + +// Insert indicates an expected call of Insert. +func (mr *MockpostModelMockRecorder) Insert(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockpostModel)(nil).Insert), ctx, data) +} + +// Update mocks base method. +func (m *MockpostModel) Update(ctx context.Context, data *model.Post) (*mongo.UpdateResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, data) + ret0, _ := ret[0].(*mongo.UpdateResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockpostModelMockRecorder) Update(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockpostModel)(nil).Update), ctx, data) +} diff --git a/internal/model/mongo/comment_model.go b/internal/model/mongo/comment_model.go new file mode 100644 index 0000000..30fe357 --- /dev/null +++ b/internal/model/mongo/comment_model.go @@ -0,0 +1,25 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/mon" + +var _ CommentModel = (*customCommentModel)(nil) + +type ( + // CommentModel is an interface to be customized, add more methods here, + // and implement the added methods in customCommentModel. + CommentModel interface { + commentModel + } + + customCommentModel struct { + *defaultCommentModel + } +) + +// NewCommentModel returns a model for the mongo. +func NewCommentModel(url, db, collection string) CommentModel { + conn := mon.MustNewModel(url, db, collection) + return &customCommentModel{ + defaultCommentModel: newDefaultCommentModel(conn), + } +} diff --git a/internal/model/mongo/comment_model_gen.go b/internal/model/mongo/comment_model_gen.go new file mode 100644 index 0000000..6c5609b --- /dev/null +++ b/internal/model/mongo/comment_model_gen.go @@ -0,0 +1,74 @@ +// Code generated by goctl. DO NOT EDIT. +package model + +import ( + "context" + "time" + + "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" +) + +type commentModel interface { + Insert(ctx context.Context, data *Comment) error + FindOne(ctx context.Context, id string) (*Comment, error) + Update(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) + Delete(ctx context.Context, id string) (int64, error) +} + +type defaultCommentModel struct { + conn *mon.Model +} + +func newDefaultCommentModel(conn *mon.Model) *defaultCommentModel { + return &defaultCommentModel{conn: conn} +} + +func (m *defaultCommentModel) Insert(ctx context.Context, data *Comment) error { + if data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + _, err := m.conn.InsertOne(ctx, data) + return err +} + +func (m *defaultCommentModel) FindOne(ctx context.Context, id string) (*Comment, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, ErrInvalidObjectId + } + + var data Comment + + err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid}) + switch err { + case nil: + return &data, nil + case mon.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultCommentModel) Update(ctx context.Context, data *Comment) (*mongo.UpdateResult, error) { + data.UpdateAt = time.Now() + + res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data}) + return res, err +} + +func (m *defaultCommentModel) Delete(ctx context.Context, id string) (int64, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return 0, ErrInvalidObjectId + } + + res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid}) + return res, err +} diff --git a/internal/model/mongo/comment_types.go b/internal/model/mongo/comment_types.go new file mode 100644 index 0000000..f82cabc --- /dev/null +++ b/internal/model/mongo/comment_types.go @@ -0,0 +1,14 @@ +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type Comment struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + // TODO: Fill your own fields + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` +} diff --git a/internal/model/mongo/error.go b/internal/model/mongo/error.go new file mode 100644 index 0000000..27d9244 --- /dev/null +++ b/internal/model/mongo/error.go @@ -0,0 +1,12 @@ +package model + +import ( + "errors" + + "github.com/zeromicro/go-zero/core/stores/mon" +) + +var ( + ErrNotFound = mon.ErrNotFound + ErrInvalidObjectId = errors.New("invalid objectId") +) diff --git a/internal/model/mongo/post_model.go b/internal/model/mongo/post_model.go new file mode 100644 index 0000000..9829de5 --- /dev/null +++ b/internal/model/mongo/post_model.go @@ -0,0 +1,185 @@ +package model + +import ( + "context" + "errors" + "time" + + "github.com/zeromicro/go-zero/core/stores/monc" + "go.mongodb.org/mongo-driver/mongo/options" + + "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" +) + +var _ PostModel = (*customPostModel)(nil) + +type ( + // PostModel is an interface to be customized, add more methods here, + // and implement the added methods in customPostModel. + PostModel interface { + postModel + DeleteMany(ctx context.Context, id ...string) (int64, error) + UpdateOptional(ctx context.Context, data *Post) (*mongo.UpdateResult, error) + Find(ctx context.Context, param *QueryPostModelReq) ([]*Post, int64, error) + } + + customPostModel struct { + *defaultPostModel + } + + QueryPostModelReq struct { + UID []string + Id []string + OnlyAds *bool + PageSize int64 + PageIndex int64 + } +) + +// NewPostModel returns a model for the mongo. +func NewPostModel(url, db, collection string) PostModel { + conn := mon.MustNewModel(url, db, collection) + return &customPostModel{ + defaultPostModel: newDefaultPostModel(conn), + } +} + +func (m *defaultPostModel) 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 *defaultPostModel) UpdateOptional(ctx context.Context, data *Post) (*mongo.UpdateResult, error) { + update := bson.M{"$set": bson.M{}} + + if data.UID != "" { + update["$set"].(bson.M)["uid"] = data.UID + } + + if data.Content != "" { + update["$set"].(bson.M)["content"] = data.Content + } + + if data.Status != 0 { + update["$set"].(bson.M)["status"] = data.Status + } + + if data.IsAd { + update["$set"].(bson.M)["is_ad"] = data.IsAd + } + + if len(data.Tags) > 0 { + update["$set"].(bson.M)["tags"] = data.Tags + } + + if len(data.MediaURL) > 0 { + update["$set"].(bson.M)["media_url"] = data.MediaURL + } + + if data.Like != 0 { + update["$set"].(bson.M)["like"] = data.Like + } + + if data.DisLike != 0 { + update["$set"].(bson.M)["dislike"] = data.DisLike + } + + // 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 +} + +// Find 貼文列表 +func (m *defaultPostModel) Find(ctx context.Context, param *QueryPostModelReq) ([]*Post, int64, error) { + filter := bson.M{} + + // 添加 UID 過濾條件 + if len(param.UID) > 0 { + filter["uid"] = bson.M{"$in": param.UID} + } + + // 添加 ID 過濾條件 + if len(param.Id) > 0 { + var ids []primitive.ObjectID + for _, item := range param.Id { + oid, err := primitive.ObjectIDFromHex(item) + if err != nil { + // log + continue + } + ids = append(ids, oid) + } + + filter["_id"] = bson.M{"$in": ids} + } + + // 添加 OnlyAds 過濾條件 + if param.OnlyAds != nil { + // true 是廣告 false 不是廣告 , 沒寫就是不過率 + filter["is_ad"] = *param.OnlyAds + } + + // 分頁處理 + opts := options.Find() + opts.SetSort(bson.D{{"create_time", -1}}) + if param.PageSize > 0 { + opts.SetLimit(param.PageSize) + } + if param.PageIndex > 0 { + opts.SetSkip((param.PageIndex - 1) * param.PageSize) + } + + // 計算總數(不考慮分頁) + totalCount, err := m.conn.CountDocuments(ctx, filter) + if err != nil { + return nil, 0, err + } + + result := make([]*Post, 0, param.PageSize) + // 執行查詢 + err = m.conn.Find(ctx, &result, filter, opts) + if err != nil { + return nil, 0, err + } + + switch { + case err == nil: + return result, totalCount, nil + case errors.Is(err, monc.ErrNotFound): + return nil, 0, ErrNotFound + default: + return nil, 0, err + } +} diff --git a/internal/model/mongo/post_model_gen.go b/internal/model/mongo/post_model_gen.go new file mode 100644 index 0000000..8948be5 --- /dev/null +++ b/internal/model/mongo/post_model_gen.go @@ -0,0 +1,74 @@ +// Code generated by goctl. DO NOT EDIT. +package model + +import ( + "context" + "time" + + "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" +) + +type postModel interface { + Insert(ctx context.Context, data *Post) error + FindOne(ctx context.Context, id string) (*Post, error) + Update(ctx context.Context, data *Post) (*mongo.UpdateResult, error) + Delete(ctx context.Context, id string) (int64, error) +} + +type defaultPostModel struct { + conn *mon.Model +} + +func newDefaultPostModel(conn *mon.Model) *defaultPostModel { + return &defaultPostModel{conn: conn} +} + +func (m *defaultPostModel) Insert(ctx context.Context, data *Post) error { + if data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now().UTC().UnixNano() + data.UpdateAt = time.Now().UTC().UnixNano() + } + + _, err := m.conn.InsertOne(ctx, data) + return err +} + +func (m *defaultPostModel) FindOne(ctx context.Context, id string) (*Post, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, ErrInvalidObjectId + } + + var data Post + + err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid}) + switch err { + case nil: + return &data, nil + case mon.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultPostModel) Update(ctx context.Context, data *Post) (*mongo.UpdateResult, error) { + data.UpdateAt = time.Now().UTC().UnixNano() + + res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data}) + return res, err +} + +func (m *defaultPostModel) Delete(ctx context.Context, id string) (int64, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return 0, ErrInvalidObjectId + } + + res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid}) + return res, err +} diff --git a/internal/model/mongo/post_types.go b/internal/model/mongo/post_types.go new file mode 100644 index 0000000..3396ab9 --- /dev/null +++ b/internal/model/mongo/post_types.go @@ -0,0 +1,32 @@ +package model + +import ( + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type Post struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + UID string `bson:"uid" json:"uid"` // 搜尋條件 + Content string `bson:"content" json:"content"` // 內容 + Status int8 `bson:"status" json:"status"` // 1. 等待審核中 , 2 審核通過,預設為 1 ->過濾條件 + IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文 -> 過濾條件 + Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除) + MediaURL []Media `bson:"media_url" json:"media_url"` // 網址 + Like uint64 `bson:"like" json:"like"` // 讚數量 + DisLike uint64 `bson:"dislike" json:"dislike"` // 不讚數量 + UpdateAt int64 `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt int64 `bson:"createAt,omitempty" json:"createAt,omitempty"` // -> 排序條件 +} + +type Media struct { + Type string // media type jpeg, m3u8 之類的 + Links string // 連結的網址 +} + +func (p *Post) CollectionName() string { + return "post" +} + +// 照邏輯,應該需要建立的索引有 +// 單列索引:UID、Status、IsAd、CreateAt +// 複合索引:(UID + Status + IsAd)、(UID + CreateAt) diff --git a/internal/server/postservice/post_service_server.go b/internal/server/postservice/post_service_server.go new file mode 100644 index 0000000..27f442f --- /dev/null +++ b/internal/server/postservice/post_service_server.go @@ -0,0 +1,53 @@ +// Code generated by goctl. DO NOT EDIT. +// Source: tweeting.proto + +package server + +import ( + "context" + + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + postservicelogic "app-cloudep-tweeting-service/internal/logic/postservice" + "app-cloudep-tweeting-service/internal/svc" +) + +type PostServiceServer struct { + svcCtx *svc.ServiceContext + tweeting.UnimplementedPostServiceServer +} + +func NewPostServiceServer(svcCtx *svc.ServiceContext) *PostServiceServer { + return &PostServiceServer{ + svcCtx: svcCtx, + } +} + +// CreatePost 新增貼文 +func (s *PostServiceServer) CreatePost(ctx context.Context, in *tweeting.NewPostReq) (*tweeting.PostResp, error) { + l := postservicelogic.NewCreatePostLogic(ctx, s.svcCtx) + return l.CreatePost(in) +} + +// DeletePost 刪除貼文 +func (s *PostServiceServer) DeletePost(ctx context.Context, in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) { + l := postservicelogic.NewDeletePostLogic(ctx, s.svcCtx) + return l.DeletePost(in) +} + +// UpdatePost 更新貼文 +func (s *PostServiceServer) UpdatePost(ctx context.Context, in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) { + l := postservicelogic.NewUpdatePostLogic(ctx, s.svcCtx) + return l.UpdatePost(in) +} + +// ListPosts 查詢貼文 +func (s *PostServiceServer) ListPosts(ctx context.Context, in *tweeting.QueryPostsReq) (*tweeting.ListPostsResp, error) { + l := postservicelogic.NewListPostsLogic(ctx, s.svcCtx) + 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) +} diff --git a/internal/svc/init_mongo.go b/internal/svc/init_mongo.go new file mode 100644 index 0000000..980c67e --- /dev/null +++ b/internal/svc/init_mongo.go @@ -0,0 +1,20 @@ +package svc + +import ( + "app-cloudep-tweeting-service/internal/config" + model "app-cloudep-tweeting-service/internal/model/mongo" + "fmt" +) + +func mustMongoConnectUrl(c config.Config) string { + return fmt.Sprintf("%s://%s:%s", + c.Mongo.Schema, + c.Mongo.Host, + c.Mongo.Port, + ) +} + +func MustPostModel(c config.Config) model.PostModel { + postCollection := model.Post{} + return model.NewPostModel(mustMongoConnectUrl(c), c.Mongo.Database, postCollection.CollectionName()) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go new file mode 100644 index 0000000..ec86c98 --- /dev/null +++ b/internal/svc/service_context.go @@ -0,0 +1,24 @@ +package svc + +import ( + "app-cloudep-tweeting-service/internal/config" + model "app-cloudep-tweeting-service/internal/model/mongo" + + vi "code.30cm.net/digimon/library-go/validator" +) + +type ServiceContext struct { + Config config.Config + Validate vi.Validate + + PostModel model.PostModel +} + +func NewServiceContext(c config.Config) *ServiceContext { + return &ServiceContext{ + Config: c, + Validate: vi.MustValidator(), + + PostModel: MustPostModel(c), + } +} diff --git a/tweeting.go b/tweeting.go new file mode 100644 index 0000000..c708b77 --- /dev/null +++ b/tweeting.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/config" + postserviceServer "app-cloudep-tweeting-service/internal/server/postservice" + "app-cloudep-tweeting-service/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/tweeting.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + ctx := svc.NewServiceContext(c) + + s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { + tweeting.RegisterPostServiceServer(grpcServer, postserviceServer.NewPostServiceServer(ctx)) + + if c.Mode == service.DevMode || c.Mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) + s.Start() +} -- 2.40.1 From 68b3ab95b9fa4d9091a18314a120eb3fbd219c3d Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Fri, 30 Aug 2024 14:30:39 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=8A=A0=E5=85=A5comment=20servicecrud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generate/protobuf/tweeting.proto | 174 +++++++++++++----- internal/domain/errors.go | 30 +++ .../commentservice/delete_comment_logic.go | 44 +++++ .../commentservice/get_comments_logic.go | 102 ++++++++++ .../logic/commentservice/new_comment_logic.go | 95 ++++++++++ .../commentservice/new_comment_logic_test.go | 1 + .../commentservice/update_comment_logic.go | 81 ++++++++ .../logic/postservice/update_post_logic.go | 15 +- internal/model/mongo/comment_model.go | 77 +++++++- internal/model/mongo/comment_model_gen.go | 6 +- internal/model/mongo/comment_types.go | 21 ++- internal/model/mongo/post_model.go | 4 +- internal/model/mongo/post_types.go | 4 +- .../commentservice/comment_service_server.go | 47 +++++ .../server/postservice/post_service_server.go | 8 +- internal/svc/init_mongo.go | 7 + internal/svc/service_context.go | 11 +- 17 files changed, 652 insertions(+), 75 deletions(-) create mode 100644 internal/logic/commentservice/delete_comment_logic.go create mode 100644 internal/logic/commentservice/get_comments_logic.go create mode 100644 internal/logic/commentservice/new_comment_logic.go create mode 100644 internal/logic/commentservice/new_comment_logic_test.go create mode 100644 internal/logic/commentservice/update_comment_logic.go create mode 100644 internal/server/commentservice/comment_service_server.go diff --git a/generate/protobuf/tweeting.proto b/generate/protobuf/tweeting.proto index 968a1aa..cbc1b2c 100644 --- a/generate/protobuf/tweeting.proto +++ b/generate/protobuf/tweeting.proto @@ -9,90 +9,101 @@ message OKResp {} message NoneReq {} // 分頁信息 -message Pager { - int64 total = 1; // 總數量 - int64 size = 2; // 每頁數量 - int64 index = 3; // 當前頁碼 +message Pager +{ + int64 total = 1; // 總數量 + int64 size = 2; // 每頁數量 + int64 index = 3; // 當前頁碼 } // ========== 貼文區 =========== // ------ NewPost 新增貼文-------- -message NewPostReq { - string uid = 1; // 發佈貼文的用戶ID - string content = 2; // 貼文內容 - repeated string tags = 3; // 貼文相關標籤 - repeated Media media = 4; // 這筆文章的所有 Media URL - bool is_ad = 5; // 是否為廣告 +message NewPostReq +{ + string uid = 1; // 發佈貼文的用戶ID + string content = 2; // 貼文內容 + repeated string tags = 3; // 貼文相關標籤 + repeated Media media = 4; // 這筆文章的所有 Media URL + bool is_ad = 5; // 是否為廣告 } -message Media { +message Media +{ string type = 1; string url = 2; } // 貼文回應 -message PostResp { - string post_id = 1; // 創建成功的貼文ID +message PostResp +{ + string post_id = 1; // 創建成功的貼文ID } // ------ DeletePost 刪除貼文 ------ // 刪除貼文的請求 -message DeletePostsReq { - repeated string post_id = 1; // 貼文ID +message DeletePostsReq +{ + repeated string post_id = 1; // 貼文ID } // ------ UpdatePost 更新貼文 ------ // 更新貼文的請求 -message UpdatePostReq { - string post_id = 1; // 貼文ID - repeated string tags = 2; // 新的標籤列表 - repeated Media media = 3; // 這筆文章的所有 Media URL - optional string content = 4; // 新的貼文內容 - optional int64 like_count = 5; // 喜歡數量 - optional int64 dislike_count = 6; // 不喜歡數量 +message UpdatePostReq +{ + string post_id = 1; // 貼文ID + repeated string tags = 2; // 新的標籤列表 + repeated Media media = 3; // 這筆文章的所有 Media URL + optional string content = 4; // 新的貼文內容 + optional int64 like_count = 5; // 喜歡數量 + optional int64 dislike_count = 6; // 不喜歡數量 } // ------ListPosts 查詢貼文 ------ // 查詢貼文的請求 -message QueryPostsReq { - repeated string uid = 1; // 可選:根據用戶ID篩選貼文 - repeated string post_id = 2; // 可選:根據貼文ID篩選貼文 - optional int32 only_ads = 3; // 可選:是否只顯示廣告 0 不篩選 1 只顯示廣告 2 不顯示廣告 - int32 page_index = 4; // 分頁的頁碼 - int32 page_size = 5; // 每頁顯示的數量 +message QueryPostsReq +{ + repeated string uid = 1; // 可選:根據用戶ID篩選貼文 + repeated string post_id = 2; // 可選:根據貼文ID篩選貼文 + optional int32 only_ads = 3; // 可選:是否只顯示廣告 0 不篩選 1 只顯示廣告 2 不顯示廣告 + int32 page_index = 4; // 分頁的頁碼 + int32 page_size = 5; // 每頁顯示的數量 } // 貼文詳情 -message PostDetailItem { - string post_id = 1; // 貼文ID - string uid = 2; // 發佈用戶ID - string content = 3; // 貼文內容 - repeated string tags = 4; // 標籤 - repeated Media media = 5; // 圖片URL - bool is_ad = 6; // 是否為廣告 - int64 created_at = 7; // 發佈時間 - int64 update_at = 8; // 更新時間 - int64 like_count = 9; // 讚數 - int64 dislike_count = 10; // 不喜歡數量 +message PostDetailItem +{ + string post_id = 1; // 貼文ID + string uid = 2; // 發佈用戶ID + string content = 3; // 貼文內容 + repeated string tags = 4; // 標籤 + repeated Media media = 5; // 圖片URL + bool is_ad = 6; // 是否為廣告 + int64 created_at = 7; // 發佈時間 + int64 update_at = 8; // 更新時間 + int64 like_count = 9; // 讚數 + int64 dislike_count = 10; // 不喜歡數量 } // 貼文列表回應 -message ListPostsResp { - repeated PostDetailItem posts = 1; // 貼文列表 +message ListPostsResp +{ + repeated PostDetailItem posts = 1; // 貼文列表 Pager page = 2; } -message ModifyLikeDislikeCountReq { - string post_id = 1; // 貼文的 ID - int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚 - bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少) - int64 count = 4; // 異動數量 +message ModifyLikeDislikeCountReq +{ + string post_id = 1; // 貼文的 ID + int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚 + bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少) + int64 count = 4; // 異動數量 } // ========== 定義貼文服務(最基本單位,不要把邏輯放進來,也考慮是否要做快取) ========== -service PostService { +service PostService +{ // CreatePost 新增貼文 rpc CreatePost(NewPostReq) returns (PostResp); // DeletePost 刪除貼文 @@ -102,3 +113,72 @@ service PostService { // ListPosts 查詢貼文 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); +} \ No newline at end of file diff --git a/internal/domain/errors.go b/internal/domain/errors.go index 6c63b9d..d1432cb 100644 --- a/internal/domain/errors.go +++ b/internal/domain/errors.go @@ -1,5 +1,13 @@ 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 func (e ErrorCode) ToUint32() uint32 { @@ -15,3 +23,25 @@ const ( UpdatePostError 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 +} diff --git a/internal/logic/commentservice/delete_comment_logic.go b/internal/logic/commentservice/delete_comment_logic.go new file mode 100644 index 0000000..467d027 --- /dev/null +++ b/internal/logic/commentservice/delete_comment_logic.go @@ -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 +} diff --git a/internal/logic/commentservice/get_comments_logic.go b/internal/logic/commentservice/get_comments_logic.go new file mode 100644 index 0000000..ec6b291 --- /dev/null +++ b/internal/logic/commentservice/get_comments_logic.go @@ -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 +} diff --git a/internal/logic/commentservice/new_comment_logic.go b/internal/logic/commentservice/new_comment_logic.go new file mode 100644 index 0000000..07abc0c --- /dev/null +++ b/internal/logic/commentservice/new_comment_logic.go @@ -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 +} diff --git a/internal/logic/commentservice/new_comment_logic_test.go b/internal/logic/commentservice/new_comment_logic_test.go new file mode 100644 index 0000000..40aa145 --- /dev/null +++ b/internal/logic/commentservice/new_comment_logic_test.go @@ -0,0 +1 @@ +package commentservicelogic diff --git a/internal/logic/commentservice/update_comment_logic.go b/internal/logic/commentservice/update_comment_logic.go new file mode 100644 index 0000000..5c64d66 --- /dev/null +++ b/internal/logic/commentservice/update_comment_logic.go @@ -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 +} diff --git a/internal/logic/postservice/update_post_logic.go b/internal/logic/postservice/update_post_logic.go index acdb501..4343e89 100644 --- a/internal/logic/postservice/update_post_logic.go +++ b/internal/logic/postservice/update_post_logic.go @@ -80,8 +80,19 @@ func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKRe } update.MediaURL = media 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) if err != nil { diff --git a/internal/model/mongo/comment_model.go b/internal/model/mongo/comment_model.go index 30fe357..adb0d29 100644 --- a/internal/model/mongo/comment_model.go +++ b/internal/model/mongo/comment_model.go @@ -1,6 +1,14 @@ 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) @@ -9,13 +17,27 @@ type ( // and implement the added methods in customCommentModel. CommentModel interface { 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 { *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. func NewCommentModel(url, db, collection string) CommentModel { conn := mon.MustNewModel(url, db, collection) @@ -23,3 +45,56 @@ func NewCommentModel(url, db, collection string) CommentModel { 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 +} diff --git a/internal/model/mongo/comment_model_gen.go b/internal/model/mongo/comment_model_gen.go index 6c5609b..e575dd8 100644 --- a/internal/model/mongo/comment_model_gen.go +++ b/internal/model/mongo/comment_model_gen.go @@ -29,8 +29,8 @@ func newDefaultCommentModel(conn *mon.Model) *defaultCommentModel { func (m *defaultCommentModel) Insert(ctx context.Context, data *Comment) error { if data.ID.IsZero() { data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() + data.CreateAt = time.Now().UTC().UnixNano() + data.UpdateAt = time.Now().UTC().UnixNano() } _, 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) { - 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}) return res, err diff --git a/internal/model/mongo/comment_types.go b/internal/model/mongo/comment_types.go index f82cabc..ae83fa4 100644 --- a/internal/model/mongo/comment_types.go +++ b/internal/model/mongo/comment_types.go @@ -1,14 +1,23 @@ package model import ( - "time" - "go.mongodb.org/mongo-driver/bson/primitive" ) type Comment struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + PostID string `bson:"post_id" json:"post_id"` + UID string `bson:"uid" json:"uid"` // 留下留言的人 + 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) diff --git a/internal/model/mongo/post_model.go b/internal/model/mongo/post_model.go index 9829de5..d97b772 100644 --- a/internal/model/mongo/post_model.go +++ b/internal/model/mongo/post_model.go @@ -106,11 +106,11 @@ func (m *defaultPostModel) UpdateOptional(ctx context.Context, data *Post) (*mon update["$set"].(bson.M)["media_url"] = data.MediaURL } - if data.Like != 0 { + if data.Like != -1 { update["$set"].(bson.M)["like"] = data.Like } - if data.DisLike != 0 { + if data.DisLike != -1 { update["$set"].(bson.M)["dislike"] = data.DisLike } diff --git a/internal/model/mongo/post_types.go b/internal/model/mongo/post_types.go index 3396ab9..7b50259 100644 --- a/internal/model/mongo/post_types.go +++ b/internal/model/mongo/post_types.go @@ -12,8 +12,8 @@ type Post struct { IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文 -> 過濾條件 Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除) MediaURL []Media `bson:"media_url" json:"media_url"` // 網址 - Like uint64 `bson:"like" json:"like"` // 讚數量 - DisLike uint64 `bson:"dislike" json:"dislike"` // 不讚數量 + Like int64 `bson:"like" json:"like"` // 讚數量 + DisLike int64 `bson:"dislike" json:"dislike"` // 不讚數量 UpdateAt int64 `bson:"updateAt,omitempty" json:"updateAt,omitempty"` CreateAt int64 `bson:"createAt,omitempty" json:"createAt,omitempty"` // -> 排序條件 } diff --git a/internal/server/commentservice/comment_service_server.go b/internal/server/commentservice/comment_service_server.go new file mode 100644 index 0000000..f434bad --- /dev/null +++ b/internal/server/commentservice/comment_service_server.go @@ -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) +} diff --git a/internal/server/postservice/post_service_server.go b/internal/server/postservice/post_service_server.go index 27f442f..07d52d3 100644 --- a/internal/server/postservice/post_service_server.go +++ b/internal/server/postservice/post_service_server.go @@ -7,7 +7,7 @@ import ( "context" "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" ) @@ -45,9 +45,3 @@ func (s *PostServiceServer) ListPosts(ctx context.Context, in *tweeting.QueryPos l := postservicelogic.NewListPostsLogic(ctx, s.svcCtx) 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) -} diff --git a/internal/svc/init_mongo.go b/internal/svc/init_mongo.go index 980c67e..d815d98 100644 --- a/internal/svc/init_mongo.go +++ b/internal/svc/init_mongo.go @@ -14,7 +14,14 @@ func mustMongoConnectUrl(c config.Config) string { ) } +// TODO 思考快取做在那邊 + func MustPostModel(c config.Config) model.PostModel { postCollection := model.Post{} 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()) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index ec86c98..6dff22c 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -11,14 +11,15 @@ type ServiceContext struct { Config config.Config Validate vi.Validate - PostModel model.PostModel + PostModel model.PostModel + CommentModel model.CommentModel } func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ - Config: c, - Validate: vi.MustValidator(), - - PostModel: MustPostModel(c), + Config: c, + Validate: vi.MustValidator(), + PostModel: MustPostModel(c), + CommentModel: MustCommentModel(c), } } -- 2.40.1 From 9f520d1990c8d6016abe44bb91a7204232c60a05 Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Fri, 30 Aug 2024 15:00:23 +0800 Subject: [PATCH 4/5] add comment service ut --- Makefile | 2 + internal/domain/errors.go | 5 +- .../delete_comment_logic_test.go | 85 ++++++++++ .../commentservice/get_comments_logic.go | 3 +- .../commentservice/get_comments_logic_test.go | 119 ++++++++++++++ .../logic/commentservice/new_comment_logic.go | 3 +- .../commentservice/new_comment_logic_test.go | 122 ++++++++++++++ .../commentservice/update_comment_logic.go | 3 +- .../update_comment_logic_test.go | 123 ++++++++++++++ internal/mock/model/comment_model.go | 152 ++++++++++++++++++ internal/mock/model/comment_model_gen.go | 101 ++++++++++++ internal/model/mongo/comment_model.go | 3 +- .../commentservice/comment_service_server.go | 2 +- .../server/postservice/post_service_server.go | 2 +- 14 files changed, 717 insertions(+), 8 deletions(-) create mode 100644 internal/logic/commentservice/delete_comment_logic_test.go create mode 100644 internal/logic/commentservice/get_comments_logic_test.go create mode 100644 internal/logic/commentservice/update_comment_logic_test.go create mode 100644 internal/mock/model/comment_model.go create mode 100644 internal/mock/model/comment_model_gen.go diff --git a/Makefile b/Makefile index 7872af5..20dc350 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,8 @@ gen-mongo-model: # 建立 rpc 資料庫 mock-gen: # 建立 mock 資料 mockgen -source=./internal/model/mongo/post_model_gen.go -destination=./internal/mock/model/post_model_gen.go -package=mock mockgen -source=./internal/model/mongo/post_model.go -destination=./internal/mock/model/post_model.go -package=mock + mockgen -source=./internal/model/mongo/comment_model_gen.go -destination=./internal/mock/model/comment_model_gen.go -package=mock + mockgen -source=./internal/model/mongo/comment_model.go -destination=./internal/mock/model/comment_model.go -package=mock @echo "Generate mock files successfully" .PHONY: migrate-database diff --git a/internal/domain/errors.go b/internal/domain/errors.go index d1432cb..d16b1ab 100644 --- a/internal/domain/errors.go +++ b/internal/domain/errors.go @@ -1,11 +1,12 @@ package domain import ( + "fmt" + "strings" + 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 diff --git a/internal/logic/commentservice/delete_comment_logic_test.go b/internal/logic/commentservice/delete_comment_logic_test.go new file mode 100644 index 0000000..00fa86c --- /dev/null +++ b/internal/logic/commentservice/delete_comment_logic_test.go @@ -0,0 +1,85 @@ +package commentservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" + + mockmodel "app-cloudep-tweeting-service/internal/mock/model" +) + +func TestDeleteComment(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockCommentModel := mockmodel.NewMockCommentModel(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + CommentModel: mockCommentModel, + } + + // 測試數據 + commentReq := &tweeting.DeleteCommentReq{ + CommentId: []string{"12345", "67890"}, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.DeleteCommentReq + prepare func() + expectErr bool + }{ + { + name: "成功刪除評論", + input: commentReq, + prepare: func() { + // 模擬 DeleteMany 成功 + mockCommentModel.EXPECT().DeleteMany(gomock.Any(), "12345", "67890").Return(int64(2), nil).Times(1) + }, + expectErr: false, + }, + { + name: "刪除評論失敗", + input: commentReq, + prepare: func() { + // 模擬 DeleteMany 失敗 + mockCommentModel.EXPECT().DeleteMany(gomock.Any(), "12345", "67890").Return(int64(0), errors.New("delete failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 DeleteCommentLogic + logic := DeleteCommentLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 DeleteComment + resp, err := logic.DeleteComment(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + assert.Nil(t, resp) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + } + }) + } +} diff --git a/internal/logic/commentservice/get_comments_logic.go b/internal/logic/commentservice/get_comments_logic.go index ec6b291..d22a2cf 100644 --- a/internal/logic/commentservice/get_comments_logic.go +++ b/internal/logic/commentservice/get_comments_logic.go @@ -3,9 +3,10 @@ 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" + ers "code.30cm.net/digimon/library-go/errs" + "app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/internal/svc" diff --git a/internal/logic/commentservice/get_comments_logic_test.go b/internal/logic/commentservice/get_comments_logic_test.go new file mode 100644 index 0000000..08ee6e7 --- /dev/null +++ b/internal/logic/commentservice/get_comments_logic_test.go @@ -0,0 +1,119 @@ +package commentservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + model "app-cloudep-tweeting-service/internal/model/mongo" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.uber.org/mock/gomock" + "testing" + + mocklib "app-cloudep-tweeting-service/internal/mock/lib" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" +) + +func TestGetComments(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockCommentModel := mockmodel.NewMockCommentModel(ctrl) + mockValidate := mocklib.NewMockValidate(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + CommentModel: mockCommentModel, + Validate: mockValidate, + } + + // 測試數據 + getCommentsReq := &tweeting.GetCommentsReq{ + PostId: "12345", + PageSize: 10, + PageIndex: 1, + } + + mockComments := []*model.Comment{ + { + ID: primitive.NewObjectID(), + PostID: "12345", + UID: "54321", + Content: "This is a comment", + LikeCount: 10, + DisLikeCount: 2, + }, + { + ID: primitive.NewObjectID(), + PostID: "12345", + UID: "67890", + Content: "This is another comment", + LikeCount: 5, + DisLikeCount: 1, + }, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.GetCommentsReq + prepare func() + expectErr bool + }{ + { + name: "成功查詢評論", + input: getCommentsReq, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + mockCommentModel.EXPECT().Find(gomock.Any(), gomock.Any()).Return(mockComments, int64(len(mockComments)), nil).Times(1) + }, + expectErr: false, + }, + { + name: "查詢評論失敗", + input: getCommentsReq, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + mockCommentModel.EXPECT().Find(gomock.Any(), gomock.Any()).Return(nil, int64(0), errors.New("find failed")).Times(1) + }, + expectErr: true, + }, + { + name: "驗證失敗", + input: getCommentsReq, + prepare: func() { + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 GetCommentsLogic + logic := GetCommentsLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 GetComments + resp, err := logic.GetComments(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + assert.Nil(t, resp) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Len(t, resp.Comments, len(mockComments)) + } + }) + } +} diff --git a/internal/logic/commentservice/new_comment_logic.go b/internal/logic/commentservice/new_comment_logic.go index 07abc0c..df084bb 100644 --- a/internal/logic/commentservice/new_comment_logic.go +++ b/internal/logic/commentservice/new_comment_logic.go @@ -5,10 +5,11 @@ import ( "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" + ers "code.30cm.net/digimon/library-go/errs" + "github.com/zeromicro/go-zero/core/logx" ) diff --git a/internal/logic/commentservice/new_comment_logic_test.go b/internal/logic/commentservice/new_comment_logic_test.go index 40aa145..68edd03 100644 --- a/internal/logic/commentservice/new_comment_logic_test.go +++ b/internal/logic/commentservice/new_comment_logic_test.go @@ -1 +1,123 @@ package commentservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + model "app-cloudep-tweeting-service/internal/model/mongo" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.uber.org/mock/gomock" + "testing" + + mocklib "app-cloudep-tweeting-service/internal/mock/lib" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" +) + +func TestNewComment(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockPostModel := mockmodel.NewMockPostModel(ctrl) + mockCommentModel := mockmodel.NewMockCommentModel(ctrl) + mockValidate := mocklib.NewMockValidate(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + PostModel: mockPostModel, + CommentModel: mockCommentModel, + Validate: mockValidate, + } + + // 測試數據 + postID := primitive.NewObjectID().Hex() + commentReq := &tweeting.CommentPostReq{ + Uid: "12345", + Content: "This is a comment", + PostId: postID, + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.CommentPostReq + prepare func() + expectErr bool + }{ + { + name: "成功發表評論", + input: commentReq, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 FindOne 成功找到文章 + mockPostModel.EXPECT().FindOne(gomock.Any(), postID).Return(&model.Post{}, nil).Times(1) + // 模擬 Insert 成功 + mockCommentModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1) + }, + expectErr: false, + }, + { + name: "驗證失敗", + input: commentReq, + prepare: func() { + // 模擬 Validate 失敗 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1) + }, + expectErr: true, + }, + { + name: "文章不存在", + input: commentReq, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 FindOne 找不到文章 + mockPostModel.EXPECT().FindOne(gomock.Any(), postID).Return(nil, model.ErrNotFound).Times(1) + }, + expectErr: true, + }, + { + name: "插入評論失敗", + input: commentReq, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 FindOne 成功找到文章 + mockPostModel.EXPECT().FindOne(gomock.Any(), postID).Return(&model.Post{}, nil).Times(1) + // 模擬 Insert 失敗 + mockCommentModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(errors.New("insert failed")).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 NewCommentLogic + logic := NewCommentLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 NewComment + resp, err := logic.NewComment(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + assert.Nil(t, resp) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.NotEmpty(t, resp.CommentId) + } + }) + } +} diff --git a/internal/logic/commentservice/update_comment_logic.go b/internal/logic/commentservice/update_comment_logic.go index 5c64d66..bc24ef0 100644 --- a/internal/logic/commentservice/update_comment_logic.go +++ b/internal/logic/commentservice/update_comment_logic.go @@ -5,8 +5,9 @@ import ( "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" + + ers "code.30cm.net/digimon/library-go/errs" "go.mongodb.org/mongo-driver/bson/primitive" "github.com/zeromicro/go-zero/core/logx" diff --git a/internal/logic/commentservice/update_comment_logic_test.go b/internal/logic/commentservice/update_comment_logic_test.go new file mode 100644 index 0000000..88762c9 --- /dev/null +++ b/internal/logic/commentservice/update_comment_logic_test.go @@ -0,0 +1,123 @@ +package commentservicelogic + +import ( + "app-cloudep-tweeting-service/gen_result/pb/tweeting" + mocklib "app-cloudep-tweeting-service/internal/mock/lib" + mockmodel "app-cloudep-tweeting-service/internal/mock/model" + "app-cloudep-tweeting-service/internal/svc" + "context" + "errors" + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.uber.org/mock/gomock" + "google.golang.org/protobuf/proto" + "testing" +) + +func TestUpdateComment(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // 初始化 mock 依賴 + mockCommentModel := mockmodel.NewMockCommentModel(ctrl) + mockValidate := mocklib.NewMockValidate(ctrl) + + // 初始化服務上下文 + svcCtx := &svc.ServiceContext{ + CommentModel: mockCommentModel, + Validate: mockValidate, + } + + // 測試數據 + commentID := primitive.NewObjectID().Hex() + updateCommentReq := &tweeting.UpdateCommentReq{ + CommentId: commentID, + Content: "Updated content", + LikeCount: proto.Int64(5), + DislikeCount: proto.Int64(2), + } + + // 測試數據集 + tests := []struct { + name string + input *tweeting.UpdateCommentReq + prepare func() + expectErr bool + }{ + { + name: "成功更新評論", + input: updateCommentReq, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 UpdateOptional 成功 + mockCommentModel.EXPECT().UpdateOptional(gomock.Any(), gomock.Any()).Return(&mongo.UpdateResult{ + ModifiedCount: 1, + }, nil).Times(1) + }, + expectErr: false, + }, + { + name: "驗證失敗", + input: updateCommentReq, + prepare: func() { + // 模擬 Validate 失敗 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1) + }, + expectErr: true, + }, + { + name: "更新評論失敗", + input: updateCommentReq, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + // 模擬 UpdateOptional 失敗 + mockCommentModel.EXPECT().UpdateOptional(gomock.Any(), gomock.Any()).Return( + &mongo.UpdateResult{ + ModifiedCount: 0, + }, errors.New("update failed")).Times(1) + }, + expectErr: true, + }, + { + name: "無效的評論ID", + input: &tweeting.UpdateCommentReq{ + CommentId: "invalid_id", + Content: "Updated content", + }, + prepare: func() { + // 模擬 Validate 成功 + mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1) + }, + expectErr: true, + }, + } + + // 執行測試 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 設置測試環境 + tt.prepare() + + // 初始化 UpdateCommentLogic + logic := UpdateCommentLogic{ + svcCtx: svcCtx, + ctx: context.TODO(), + } + + // 執行 UpdateComment + resp, err := logic.UpdateComment(tt.input) + + // 驗證結果 + if tt.expectErr { + assert.Error(t, err) + assert.Nil(t, resp) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + } + }) + } +} diff --git a/internal/mock/model/comment_model.go b/internal/mock/model/comment_model.go new file mode 100644 index 0000000..db69a18 --- /dev/null +++ b/internal/mock/model/comment_model.go @@ -0,0 +1,152 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/model/mongo/comment_model.go +// +// Generated by this command: +// +// mockgen -source=./internal/model/mongo/comment_model.go -destination=./internal/mock/model/comment_model.go -package=mock +// + +// Package mock is a generated GoMock package. +package mock + +import ( + model "app-cloudep-tweeting-service/internal/model/mongo" + context "context" + reflect "reflect" + + mongo "go.mongodb.org/mongo-driver/mongo" + gomock "go.uber.org/mock/gomock" +) + +// MockCommentModel is a mock of CommentModel interface. +type MockCommentModel struct { + ctrl *gomock.Controller + recorder *MockCommentModelMockRecorder +} + +// MockCommentModelMockRecorder is the mock recorder for MockCommentModel. +type MockCommentModelMockRecorder struct { + mock *MockCommentModel +} + +// NewMockCommentModel creates a new mock instance. +func NewMockCommentModel(ctrl *gomock.Controller) *MockCommentModel { + mock := &MockCommentModel{ctrl: ctrl} + mock.recorder = &MockCommentModelMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCommentModel) EXPECT() *MockCommentModelMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockCommentModel) Delete(ctx context.Context, id string) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, id) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockCommentModelMockRecorder) Delete(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockCommentModel)(nil).Delete), ctx, id) +} + +// DeleteMany mocks base method. +func (m *MockCommentModel) DeleteMany(ctx context.Context, id ...string) (int64, error) { + m.ctrl.T.Helper() + varargs := []any{ctx} + for _, a := range id { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteMany", varargs...) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteMany indicates an expected call of DeleteMany. +func (mr *MockCommentModelMockRecorder) DeleteMany(ctx any, id ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx}, id...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteMany", reflect.TypeOf((*MockCommentModel)(nil).DeleteMany), varargs...) +} + +// Find mocks base method. +func (m *MockCommentModel) Find(ctx context.Context, param *model.QueryCommentModelReq) ([]*model.Comment, int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Find", ctx, param) + ret0, _ := ret[0].([]*model.Comment) + ret1, _ := ret[1].(int64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// Find indicates an expected call of Find. +func (mr *MockCommentModelMockRecorder) Find(ctx, param any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockCommentModel)(nil).Find), ctx, param) +} + +// FindOne mocks base method. +func (m *MockCommentModel) FindOne(ctx context.Context, id string) (*model.Comment, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindOne", ctx, id) + ret0, _ := ret[0].(*model.Comment) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindOne indicates an expected call of FindOne. +func (mr *MockCommentModelMockRecorder) FindOne(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockCommentModel)(nil).FindOne), ctx, id) +} + +// Insert mocks base method. +func (m *MockCommentModel) Insert(ctx context.Context, data *model.Comment) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, data) + ret0, _ := ret[0].(error) + return ret0 +} + +// Insert indicates an expected call of Insert. +func (mr *MockCommentModelMockRecorder) Insert(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockCommentModel)(nil).Insert), ctx, data) +} + +// Update mocks base method. +func (m *MockCommentModel) Update(ctx context.Context, data *model.Comment) (*mongo.UpdateResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, data) + ret0, _ := ret[0].(*mongo.UpdateResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockCommentModelMockRecorder) Update(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockCommentModel)(nil).Update), ctx, data) +} + +// UpdateOptional mocks base method. +func (m *MockCommentModel) UpdateOptional(ctx context.Context, data *model.Comment) (*mongo.UpdateResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateOptional", ctx, data) + ret0, _ := ret[0].(*mongo.UpdateResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateOptional indicates an expected call of UpdateOptional. +func (mr *MockCommentModelMockRecorder) UpdateOptional(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOptional", reflect.TypeOf((*MockCommentModel)(nil).UpdateOptional), ctx, data) +} diff --git a/internal/mock/model/comment_model_gen.go b/internal/mock/model/comment_model_gen.go new file mode 100644 index 0000000..5de5dd7 --- /dev/null +++ b/internal/mock/model/comment_model_gen.go @@ -0,0 +1,101 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/model/mongo/comment_model_gen.go +// +// Generated by this command: +// +// mockgen -source=./internal/model/mongo/comment_model_gen.go -destination=./internal/mock/model/comment_model_gen.go -package=mock +// + +// Package mock is a generated GoMock package. +package mock + +import ( + model "app-cloudep-tweeting-service/internal/model/mongo" + context "context" + reflect "reflect" + + mongo "go.mongodb.org/mongo-driver/mongo" + gomock "go.uber.org/mock/gomock" +) + +// MockcommentModel is a mock of commentModel interface. +type MockcommentModel struct { + ctrl *gomock.Controller + recorder *MockcommentModelMockRecorder +} + +// MockcommentModelMockRecorder is the mock recorder for MockcommentModel. +type MockcommentModelMockRecorder struct { + mock *MockcommentModel +} + +// NewMockcommentModel creates a new mock instance. +func NewMockcommentModel(ctrl *gomock.Controller) *MockcommentModel { + mock := &MockcommentModel{ctrl: ctrl} + mock.recorder = &MockcommentModelMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockcommentModel) EXPECT() *MockcommentModelMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockcommentModel) Delete(ctx context.Context, id string) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, id) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockcommentModelMockRecorder) Delete(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockcommentModel)(nil).Delete), ctx, id) +} + +// FindOne mocks base method. +func (m *MockcommentModel) FindOne(ctx context.Context, id string) (*model.Comment, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindOne", ctx, id) + ret0, _ := ret[0].(*model.Comment) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindOne indicates an expected call of FindOne. +func (mr *MockcommentModelMockRecorder) FindOne(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockcommentModel)(nil).FindOne), ctx, id) +} + +// Insert mocks base method. +func (m *MockcommentModel) Insert(ctx context.Context, data *model.Comment) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, data) + ret0, _ := ret[0].(error) + return ret0 +} + +// Insert indicates an expected call of Insert. +func (mr *MockcommentModelMockRecorder) Insert(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockcommentModel)(nil).Insert), ctx, data) +} + +// Update mocks base method. +func (m *MockcommentModel) Update(ctx context.Context, data *model.Comment) (*mongo.UpdateResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, data) + ret0, _ := ret[0].(*mongo.UpdateResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockcommentModelMockRecorder) Update(ctx, data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockcommentModel)(nil).Update), ctx, data) +} diff --git a/internal/model/mongo/comment_model.go b/internal/model/mongo/comment_model.go index adb0d29..abd9baa 100644 --- a/internal/model/mongo/comment_model.go +++ b/internal/model/mongo/comment_model.go @@ -2,12 +2,13 @@ package model import ( "context" + "time" + "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) diff --git a/internal/server/commentservice/comment_service_server.go b/internal/server/commentservice/comment_service_server.go index f434bad..9fed63f 100644 --- a/internal/server/commentservice/comment_service_server.go +++ b/internal/server/commentservice/comment_service_server.go @@ -7,7 +7,7 @@ import ( "context" "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/logic/commentservice" + commentservicelogic "app-cloudep-tweeting-service/internal/logic/commentservice" "app-cloudep-tweeting-service/internal/svc" ) diff --git a/internal/server/postservice/post_service_server.go b/internal/server/postservice/post_service_server.go index 07d52d3..639c1f4 100644 --- a/internal/server/postservice/post_service_server.go +++ b/internal/server/postservice/post_service_server.go @@ -7,7 +7,7 @@ import ( "context" "app-cloudep-tweeting-service/gen_result/pb/tweeting" - "app-cloudep-tweeting-service/internal/logic/postservice" + postservicelogic "app-cloudep-tweeting-service/internal/logic/postservice" "app-cloudep-tweeting-service/internal/svc" ) -- 2.40.1 From 3bf7909c6281d857102741ecda711024467ff37c Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Fri, 30 Aug 2024 15:08:13 +0800 Subject: [PATCH 5/5] remove other error --- .../commentservice/get_comments_logic_test.go | 3 +- .../commentservice/new_comment_logic_test.go | 3 +- .../update_comment_logic_test.go | 3 +- .../logic/postservice/create_post_logic.go | 28 +++--------------- .../logic/postservice/delete_post_logic.go | 29 ++++--------------- .../logic/postservice/list_posts_logic.go | 22 ++------------ .../logic/postservice/update_post_logic.go | 22 ++------------ 7 files changed, 21 insertions(+), 89 deletions(-) diff --git a/internal/logic/commentservice/get_comments_logic_test.go b/internal/logic/commentservice/get_comments_logic_test.go index 08ee6e7..be66c91 100644 --- a/internal/logic/commentservice/get_comments_logic_test.go +++ b/internal/logic/commentservice/get_comments_logic_test.go @@ -6,10 +6,11 @@ import ( "app-cloudep-tweeting-service/internal/svc" "context" "errors" + "testing" + "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/mock/gomock" - "testing" mocklib "app-cloudep-tweeting-service/internal/mock/lib" mockmodel "app-cloudep-tweeting-service/internal/mock/model" diff --git a/internal/logic/commentservice/new_comment_logic_test.go b/internal/logic/commentservice/new_comment_logic_test.go index 68edd03..a7873ce 100644 --- a/internal/logic/commentservice/new_comment_logic_test.go +++ b/internal/logic/commentservice/new_comment_logic_test.go @@ -6,10 +6,11 @@ import ( "app-cloudep-tweeting-service/internal/svc" "context" "errors" + "testing" + "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/mock/gomock" - "testing" mocklib "app-cloudep-tweeting-service/internal/mock/lib" mockmodel "app-cloudep-tweeting-service/internal/mock/model" diff --git a/internal/logic/commentservice/update_comment_logic_test.go b/internal/logic/commentservice/update_comment_logic_test.go index 88762c9..ec4973a 100644 --- a/internal/logic/commentservice/update_comment_logic_test.go +++ b/internal/logic/commentservice/update_comment_logic_test.go @@ -7,12 +7,13 @@ import ( "app-cloudep-tweeting-service/internal/svc" "context" "errors" + "testing" + "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/mock/gomock" "google.golang.org/protobuf/proto" - "testing" ) func TestUpdateComment(t *testing.T) { diff --git a/internal/logic/postservice/create_post_logic.go b/internal/logic/postservice/create_post_logic.go index 73023e7..e3fbb0d 100644 --- a/internal/logic/postservice/create_post_logic.go +++ b/internal/logic/postservice/create_post_logic.go @@ -4,14 +4,9 @@ import ( "app-cloudep-tweeting-service/internal/domain" model "app-cloudep-tweeting-service/internal/model/mongo" - "code.30cm.net/digimon/library-go/errs/code" - - "context" - "fmt" - "strings" - "app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/internal/svc" + "context" ers "code.30cm.net/digimon/library-go/errs" "github.com/zeromicro/go-zero/core/logx" @@ -41,23 +36,6 @@ type newTweetingReq struct { IsAd bool `json:"is_ad"` // default false } -// 定義 Error - -// CreatePostError 0502102 資料庫錯誤 -func CreatePostError(s ...string) *ers.LibError { - return ers.NewError(code.CloudEPTweeting, code.DBError, - domain.CreatePostError.ToUint32(), - fmt.Sprintf("%s", strings.Join(s, " "))) -} - -// CreatePostErrorL logs error message and returns Error -func CreatePostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { - e := CreatePostError(s...) - l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) - - return e -} - // CreatePost 新增貼文 func (l *CreatePostLogic) CreatePost(in *tweeting.NewPostReq) (*tweeting.PostResp, error) { // 驗證資料 @@ -97,7 +75,9 @@ func (l *CreatePostLogic) CreatePost(in *tweeting.NewPostReq) (*tweeting.PostRes // ============ insert ============ err := l.svcCtx.PostModel.Insert(l.ctx, tweet) if err != nil { - e := CreatePostErrorL( + // 錯誤代碼 05-021-02 + e := domain.CommentErrorL( + domain.CreatePostError, logx.WithContext(l.ctx), []logx.LogField{ {Key: "req", Value: in}, diff --git a/internal/logic/postservice/delete_post_logic.go b/internal/logic/postservice/delete_post_logic.go index 33a9e81..ffa6bda 100644 --- a/internal/logic/postservice/delete_post_logic.go +++ b/internal/logic/postservice/delete_post_logic.go @@ -1,16 +1,10 @@ package postservicelogic import ( - "app-cloudep-tweeting-service/internal/domain" - "context" - "fmt" - "strings" - - ers "code.30cm.net/digimon/library-go/errs" - "code.30cm.net/digimon/library-go/errs/code" - "app-cloudep-tweeting-service/gen_result/pb/tweeting" + "app-cloudep-tweeting-service/internal/domain" "app-cloudep-tweeting-service/internal/svc" + "context" "github.com/zeromicro/go-zero/core/logx" ) @@ -29,26 +23,13 @@ func NewDeletePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete } } -// DeletePostError 0502103 資料庫錯誤 -func DeletePostError(s ...string) *ers.LibError { - return ers.NewError(code.CloudEPTweeting, code.DBError, - domain.DelPostError.ToUint32(), - fmt.Sprintf("%s", strings.Join(s, " "))) -} - -// DeletePostErrorL logs error message and returns Error -func DeletePostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { - e := DeletePostError(s...) - l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) - - return e -} - // DeletePost 刪除貼文 func (l *DeletePostLogic) DeletePost(in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) { _, err := l.svcCtx.PostModel.DeleteMany(l.ctx, in.GetPostId()...) if err != nil { - e := DeletePostErrorL( + // 錯誤代碼 05-021-03 + e := domain.CommentErrorL( + domain.DelPostError, logx.WithContext(l.ctx), []logx.LogField{ {Key: "req", Value: in}, diff --git a/internal/logic/postservice/list_posts_logic.go b/internal/logic/postservice/list_posts_logic.go index a3e7f08..544327d 100644 --- a/internal/logic/postservice/list_posts_logic.go +++ b/internal/logic/postservice/list_posts_logic.go @@ -4,11 +4,8 @@ import ( "app-cloudep-tweeting-service/internal/domain" model "app-cloudep-tweeting-service/internal/model/mongo" "context" - "fmt" - "strings" ers "code.30cm.net/digimon/library-go/errs" - "code.30cm.net/digimon/library-go/errs/code" "google.golang.org/protobuf/proto" "app-cloudep-tweeting-service/gen_result/pb/tweeting" @@ -38,21 +35,6 @@ type listReq struct { PageIndex int64 `json:"page_index" validate:"required"` } -// ListPostError 0502105 資料庫錯誤 -func ListPostError(s ...string) *ers.LibError { - return ers.NewError(code.CloudEPTweeting, code.DBError, - domain.ListPostError.ToUint32(), - fmt.Sprintf("%s", strings.Join(s, " "))) -} - -// ListPostErrorL logs error message and returns Error -func ListPostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { - e := ListPostError(s...) - l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) - - return e -} - // 將單個 Post 轉換為 PostDetailItem func convertToPostDetailItem(item *model.Post) *tweeting.PostDetailItem { media := make([]*tweeting.Media, 0, len(item.MediaURL)) @@ -110,7 +92,9 @@ func (l *ListPostsLogic) ListPosts(in *tweeting.QueryPostsReq) (*tweeting.ListPo // 執行查詢 find, count, err := l.svcCtx.PostModel.Find(l.ctx, query) if err != nil { - e := ListPostErrorL( + // 錯誤代碼 05-021-05 + e := domain.CommentErrorL( + domain.ListPostError, logx.WithContext(l.ctx), []logx.LogField{ {Key: "query", Value: query}, diff --git a/internal/logic/postservice/update_post_logic.go b/internal/logic/postservice/update_post_logic.go index 4343e89..2275fcc 100644 --- a/internal/logic/postservice/update_post_logic.go +++ b/internal/logic/postservice/update_post_logic.go @@ -4,11 +4,8 @@ import ( "app-cloudep-tweeting-service/internal/domain" model "app-cloudep-tweeting-service/internal/model/mongo" "context" - "fmt" - "strings" ers "code.30cm.net/digimon/library-go/errs" - "code.30cm.net/digimon/library-go/errs/code" "go.mongodb.org/mongo-driver/bson/primitive" "app-cloudep-tweeting-service/gen_result/pb/tweeting" @@ -36,21 +33,6 @@ type checkPostId struct { Content string `json:"content,omitempty" validate:"lte=500"` } -// UpdatePostError 0502104 資料庫錯誤 -func UpdatePostError(s ...string) *ers.LibError { - return ers.NewError(code.CloudEPTweeting, code.DBError, - domain.UpdatePostError.ToUint32(), - fmt.Sprintf("%s", strings.Join(s, " "))) -} - -// UpdatePostErrorL logs error message and returns Error -func UpdatePostErrorL(l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { - e := UpdatePostError(s...) - l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) - - return e -} - // UpdatePost 更新貼文 func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) { // 驗證資料 @@ -96,7 +78,9 @@ func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKRe _, err = l.svcCtx.PostModel.UpdateOptional(l.ctx, &update) if err != nil { - e := UpdatePostErrorL( + // 錯誤代碼 05-021-04 + e := domain.CommentErrorL( + domain.UpdatePostError, logx.WithContext(l.ctx), []logx.LogField{ {Key: "req", Value: in}, -- 2.40.1