feature/post #1
|
@ -4,3 +4,25 @@ Etcd:
|
||||||
Hosts:
|
Hosts:
|
||||||
- 127.0.0.1:2379
|
- 127.0.0.1:2379
|
||||||
Key: tweeting.rpc
|
Key: tweeting.rpc
|
||||||
|
|
||||||
|
Cache:
|
||||||
|
- Host: 127.0.0.1:7001
|
||||||
|
type: cluster
|
||||||
|
- Host: 127.0.0.1:7002
|
||||||
|
type: cluster
|
||||||
|
- Host: 127.0.0.1:7003
|
||||||
|
type: cluster
|
||||||
|
- Host: 127.0.0.1:7004
|
||||||
|
type: cluster
|
||||||
|
- Host: 127.0.0.1:7005
|
||||||
|
type: cluster
|
||||||
|
- Host: 127.0.0.1:7006
|
||||||
|
type: cluster
|
||||||
|
|
||||||
|
Mongo:
|
||||||
|
Schema: mongodb
|
||||||
|
Host: 127.0.0.1
|
||||||
|
User: ""
|
||||||
|
Password: ""
|
||||||
|
Port: "27017"
|
||||||
|
Database: digimon_tweeting
|
|
@ -0,0 +1,5 @@
|
||||||
|
use digimon_tweeting;
|
||||||
|
db.post.createIndex({ "uid": 1, "create_time": 1 });
|
||||||
|
db.post.createIndex({ "is_ad": 1, "create_time": 1 });
|
||||||
|
db.post.createIndex({ "create_time": 1 });
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
db.post_likes.createIndex(
|
||||||
|
{ "target_id": 1, "uid": 1, "type": 1 },
|
||||||
|
{ unique: true }
|
||||||
|
);
|
||||||
|
db.post_likes.createIndex({ "create_time": 1 });
|
|
@ -15,12 +15,17 @@ message Pager {
|
||||||
int64 index=3; // 當前頁碼
|
int64 index=3; // 當前頁碼
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Media{
|
||||||
|
string type =1;
|
||||||
|
string url =2;
|
||||||
|
}
|
||||||
|
|
||||||
// 新增貼文的請求
|
// 新增貼文的請求
|
||||||
message NewPostReq {
|
message NewPostReq {
|
||||||
int64 user_id = 1; // 發佈貼文的用戶ID
|
string uid = 1; // 發佈貼文的用戶ID
|
||||||
string content = 2; // 貼文內容
|
string content = 2; // 貼文內容
|
||||||
repeated string tags = 3; // 貼文相關標籤
|
repeated string tags = 3; // 貼文相關標籤
|
||||||
repeated string media_url = 4; // 這筆文章的所有 Media URL
|
repeated Media media = 4; // 這筆文章的所有 Media URL
|
||||||
bool is_ad = 5; // 是否為廣告
|
bool is_ad = 5; // 是否為廣告
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +43,7 @@ message DeletePostsReq {
|
||||||
message UpdatePostReq {
|
message UpdatePostReq {
|
||||||
string post_id = 1; // 貼文ID
|
string post_id = 1; // 貼文ID
|
||||||
repeated string tags = 2; // 新的標籤列表
|
repeated string tags = 2; // 新的標籤列表
|
||||||
repeated string media_url = 3; // 這筆文章的所有 Media URL
|
repeated Media media = 3; // 這筆文章的所有 Media URL
|
||||||
optional string content = 4; // 新的貼文內容
|
optional string content = 4; // 新的貼文內容
|
||||||
optional int64 like_count = 5; // 喜歡數量
|
optional int64 like_count = 5; // 喜歡數量
|
||||||
optional int64 dislike_count = 6; // 不喜歡數量
|
optional int64 dislike_count = 6; // 不喜歡數量
|
||||||
|
@ -46,10 +51,9 @@ message UpdatePostReq {
|
||||||
|
|
||||||
// 查詢貼文的請求
|
// 查詢貼文的請求
|
||||||
message QueryPostsReq {
|
message QueryPostsReq {
|
||||||
repeated int64 user_id = 1; // 可選:根據用戶ID篩選貼文
|
repeated string uid = 1; // 可選:根據用戶ID篩選貼文
|
||||||
repeated int64 id = 2; // 可選:根據貼文ID篩選貼文
|
repeated string id = 2; // 可選:根據貼文ID篩選貼文
|
||||||
repeated string tags = 3; // 可選:根據標籤篩選貼文
|
optional int32 only_ads = 4; // 可選:是否只顯示廣告 0 不篩選 1 只顯示廣告 2 不顯示廣告
|
||||||
optional bool only_ads = 4; // 可選:是否只顯示廣告
|
|
||||||
int32 page_index = 5; // 分頁的頁碼
|
int32 page_index = 5; // 分頁的頁碼
|
||||||
int32 page_size = 6; // 每頁顯示的數量
|
int32 page_size = 6; // 每頁顯示的數量
|
||||||
}
|
}
|
||||||
|
@ -57,10 +61,10 @@ message QueryPostsReq {
|
||||||
// 貼文詳情
|
// 貼文詳情
|
||||||
message PostDetailItem {
|
message PostDetailItem {
|
||||||
string post_id = 1; // 貼文ID
|
string post_id = 1; // 貼文ID
|
||||||
int64 user_id = 2; // 發佈用戶ID
|
string uid = 2; // 發佈用戶ID
|
||||||
string content = 3; // 貼文內容
|
string content = 3; // 貼文內容
|
||||||
repeated string tags = 4; // 標籤
|
repeated string tags = 4; // 標籤
|
||||||
repeated string media_url = 5; // 圖片URL
|
repeated Media media = 5; // 圖片URL
|
||||||
bool is_ad = 6; // 是否為廣告
|
bool is_ad = 6; // 是否為廣告
|
||||||
int64 created_at = 7; // 發佈時間
|
int64 created_at = 7; // 發佈時間
|
||||||
int64 update_at = 8; // 更新時間
|
int64 update_at = 8; // 更新時間
|
||||||
|
@ -77,14 +81,30 @@ message ListPostsResp {
|
||||||
// 讚/不讚請求
|
// 讚/不讚請求
|
||||||
message LikeReq {
|
message LikeReq {
|
||||||
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
||||||
int64 user_id = 2; // 點讚的用戶ID
|
string uid = 2; // 點讚的用戶ID
|
||||||
int64 like_type = 3; // 讚或爛的類型
|
int64 like_type = 3; // 讚或爛的類型
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetLikeStatusReq{
|
||||||
|
string uid = 1; // 點讚的用戶ID
|
||||||
|
repeated string target_id = 2; // 目標ID(可以是貼文ID或評論ID)
|
||||||
|
int64 like_type = 3; // 讚或爛的類型
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLikeStatusItem{
|
||||||
|
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
||||||
|
bool status = 2; // 是否有按過
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLikeStatusResp{
|
||||||
|
repeated GetLikeStatusItem data = 1; // 目標ID(可以是貼文ID或評論ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 讚/不讚項目
|
// 讚/不讚項目
|
||||||
message LikeItem {
|
message LikeItem {
|
||||||
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
||||||
int64 user_id = 2; // 點讚的用戶ID
|
string uid = 2; // 點讚的用戶ID
|
||||||
int64 like_type = 3; // 讚或爛的類型
|
int64 like_type = 3; // 讚或爛的類型
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +112,8 @@ message LikeItem {
|
||||||
message LikeListReq {
|
message LikeListReq {
|
||||||
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
string target_id = 1; // 目標ID(可以是貼文ID或評論ID)
|
||||||
int64 like_type = 2; // 讚或爛的類型
|
int64 like_type = 2; // 讚或爛的類型
|
||||||
int32 page_index = 3; // 當前頁碼
|
int64 page_index = 3; // 當前頁碼
|
||||||
int32 page_size = 4; // 每頁顯示數量
|
int64 page_size = 4; // 每頁顯示數量
|
||||||
}
|
}
|
||||||
|
|
||||||
// 讚/不讚列表回應
|
// 讚/不讚列表回應
|
||||||
|
@ -110,7 +130,7 @@ message LikeCountReq {
|
||||||
|
|
||||||
// 讚/不讚數量回應
|
// 讚/不讚數量回應
|
||||||
message LikeCountResp {
|
message LikeCountResp {
|
||||||
string count = 1; // 總共按讚數量
|
int64 count = 1; // 總共按讚數量
|
||||||
}
|
}
|
||||||
|
|
||||||
// 評論貼文的請求
|
// 評論貼文的請求
|
||||||
|
@ -154,6 +174,18 @@ message UpdateCommentReq {
|
||||||
string content = 2; // 更新後的評論內容
|
string content = 2; // 更新後的評論內容
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message PostReactionActionResp {
|
||||||
|
string PostID =1; // 貼文的 ID
|
||||||
|
int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚
|
||||||
|
bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少)
|
||||||
|
}
|
||||||
|
|
||||||
|
message IncDecLikeDislikeCountReq {
|
||||||
|
string PostID =1; // 貼文的 ID
|
||||||
|
int64 reaction_type = 2; // 用戶的反應類型,可能是讚或不讚
|
||||||
|
bool is_increment = 3; // 表示是否增加(true 表示增加,false 表示減少)
|
||||||
|
}
|
||||||
|
|
||||||
// 定義貼文服務
|
// 定義貼文服務
|
||||||
service PostService {
|
service PostService {
|
||||||
// NewPost 新增貼文
|
// NewPost 新增貼文
|
||||||
|
@ -164,11 +196,13 @@ service PostService {
|
||||||
rpc UpdatePost(UpdatePostReq) returns (OKResp);
|
rpc UpdatePost(UpdatePostReq) returns (OKResp);
|
||||||
// ListPosts 查詢貼文
|
// ListPosts 查詢貼文
|
||||||
rpc ListPosts(QueryPostsReq) returns (ListPostsResp);
|
rpc ListPosts(QueryPostsReq) returns (ListPostsResp);
|
||||||
|
// IncDecLikeDislikeCount 增減數量
|
||||||
|
rpc IncDecLikeDislikeCount(IncDecLikeDislikeCountReq) returns (OKResp);
|
||||||
|
|
||||||
// Like 點讚/取消讚 貼文
|
// Like 點讚/取消讚 貼文
|
||||||
rpc Like(LikeReq) returns (OKResp);
|
rpc Like(LikeReq) returns (PostReactionActionResp);
|
||||||
// GetLikeStatus 取得讚/不讚狀態
|
// GetLikeStatus 取得讚/不讚狀態
|
||||||
rpc GetLikeStatus(LikeReq) returns (OKResp);
|
rpc GetLikeStatus(GetLikeStatusReq) returns (GetLikeStatusResp);
|
||||||
// LikeList 取得讚/不讚列表
|
// LikeList 取得讚/不讚列表
|
||||||
rpc LikeList(LikeListReq) returns (LikeListResp);
|
rpc LikeList(LikeListReq) returns (LikeListResp);
|
||||||
// CountLike 取得讚/不讚數量
|
// CountLike 取得讚/不讚數量
|
||||||
|
|
17
go.mod
17
go.mod
|
@ -3,7 +3,10 @@ module app-cloudep-tweeting-service
|
||||||
go 1.22.3
|
go 1.22.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
code.30cm.net/digimon/library-go/errs v1.2.4
|
||||||
|
code.30cm.net/digimon/library-go/validator v1.0.0
|
||||||
github.com/zeromicro/go-zero v1.7.0
|
github.com/zeromicro/go-zero v1.7.0
|
||||||
|
go.mongodb.org/mongo-driver v1.16.1
|
||||||
google.golang.org/grpc v1.66.0
|
google.golang.org/grpc v1.66.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
)
|
)
|
||||||
|
@ -18,14 +21,19 @@ require (
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/fatih/color v1.17.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/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // 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/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // 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/gnostic-models v0.6.8 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
|
@ -33,11 +41,14 @@ require (
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // 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/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // 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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
@ -47,6 +58,10 @@ require (
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.6.1 // indirect
|
github.com/redis/go-redis/v9 v9.6.1 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // 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/api/v3 v3.5.15 // indirect
|
||||||
go.etcd.io/etcd/client/pkg/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.etcd.io/etcd/client/v3 v3.5.15 // indirect
|
||||||
|
@ -65,8 +80,10 @@ require (
|
||||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
go.uber.org/zap v1.24.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/net v0.27.0 // indirect
|
||||||
golang.org/x/oauth2 v0.21.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/sys v0.22.0 // indirect
|
||||||
golang.org/x/term v0.22.0 // indirect
|
golang.org/x/term v0.22.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import "github.com/zeromicro/go-zero/zrpc"
|
import (
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
zrpc.RpcServerConf
|
zrpc.RpcServerConf
|
||||||
|
Mongo struct {
|
||||||
|
Schema string
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
Database string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快取
|
||||||
|
Cache cache.CacheConf
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
type AdType int32
|
||||||
|
|
||||||
|
func (a AdType) ToInt32() int32 {
|
||||||
|
return int32(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
AdTypeAll AdType = iota
|
||||||
|
AdTypeOnlyAd
|
||||||
|
AdTypeOnlyNotAd
|
||||||
|
)
|
||||||
|
|
||||||
|
type LikeType int8
|
||||||
|
|
||||||
|
func (l LikeType) ToInt8() int8 {
|
||||||
|
return int8(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
LikeTypeLike LikeType = iota + 1 // 按揍
|
||||||
|
LikeTypeDisLike
|
||||||
|
)
|
|
@ -0,0 +1,39 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.30cm.net/digimon/library-go/errs"
|
||||||
|
"code.30cm.net/digimon/library-go/errs/code"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorCode uint32
|
||||||
|
|
||||||
|
func (e ErrorCode) ToUint32() uint32 {
|
||||||
|
return uint32(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
PostMongoErrorCode ErrorCode = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
// PostMongoError ...
|
||||||
|
func PostMongoError(s ...string) *errs.LibError {
|
||||||
|
return errs.NewError(code.CloudEPTweeting, code.DBError,
|
||||||
|
PostMongoErrorCode.ToUint32(),
|
||||||
|
fmt.Sprintf("%s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostMongoErrorL logs error message and returns Err
|
||||||
|
func PostMongoErrorL(l logx.Logger, filed []logx.LogField, s ...string) *errs.LibError {
|
||||||
|
e := PostMongoError(s...)
|
||||||
|
if filed != nil || len(filed) >= 0 {
|
||||||
|
l.WithCallerSkip(1).WithFields(filed...).Error(e.Error())
|
||||||
|
}
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
type TweetingStatus int8
|
||||||
|
|
||||||
|
func (t TweetingStatus) ToInt8() int8 {
|
||||||
|
return int8(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TweetingStatusNotReviewedYet TweetingStatus = iota + 1
|
||||||
|
TweetingStatusPass
|
||||||
|
)
|
|
@ -1,10 +1,12 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -23,9 +25,35 @@ func NewCountLikeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CountLi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type countLikeReq struct {
|
||||||
|
PostID string `json:"post_id" validate:"required"` // 貼文的 ID
|
||||||
|
ReactionType domain.LikeType `json:"reaction_type" validate:"required,oneof=1 2"` // 用戶的反應類型,可能是讚或不讚
|
||||||
|
}
|
||||||
|
|
||||||
// CountLike 取得讚/不讚數量
|
// CountLike 取得讚/不讚數量
|
||||||
func (l *CountLikeLogic) CountLike(in *tweeting.LikeCountReq) (*tweeting.LikeCountResp, error) {
|
func (l *CountLikeLogic) CountLike(in *tweeting.LikeCountReq) (*tweeting.LikeCountResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&countLikeReq{
|
||||||
|
PostID: in.GetTargetId(),
|
||||||
|
ReactionType: domain.LikeType(in.GetLikeType()),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return &tweeting.LikeCountResp{}, nil
|
count, err := l.svcCtx.PostLikeModel.Count(l.ctx, in.GetTargetId(), domain.LikeType(in.GetLikeType()))
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostLikeModel.Count"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to count like or dislike").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.LikeCountResp{
|
||||||
|
Count: count,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
@ -25,7 +26,18 @@ func NewDeletePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete
|
||||||
|
|
||||||
// DeletePost 刪除貼文
|
// DeletePost 刪除貼文
|
||||||
func (l *DeletePostLogic) DeletePost(in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) {
|
func (l *DeletePostLogic) DeletePost(in *tweeting.DeletePostsReq) (*tweeting.OKResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
_, err := l.svcCtx.PostModel.DeleteMany(l.ctx, in.GetPostId()...)
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.DeletePost"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to add del post").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
return &tweeting.OKResp{}, nil
|
return &tweeting.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
@ -23,9 +27,50 @@ func NewGetLikeStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Get
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLikeStatus 取得讚/不讚狀態
|
// 這個人按讚的文章列表(輸入UID 以及文章id,返回這個人有沒有對這些文章按讚)
|
||||||
func (l *GetLikeStatusLogic) GetLikeStatus(in *tweeting.LikeReq) (*tweeting.OKResp, error) {
|
type getLikeStatusReq struct {
|
||||||
// todo: add your logic here and delete this line
|
Targets []string `json:"targets" validate:"required"`
|
||||||
|
LikeType domain.LikeType `json:"like_type" validate:"required,oneof=1 2"`
|
||||||
return &tweeting.OKResp{}, nil
|
UID string `json:"uid" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLikeStatus 取得讚/不讚狀態
|
||||||
|
func (l *GetLikeStatusLogic) GetLikeStatus(in *tweeting.GetLikeStatusReq) (*tweeting.GetLikeStatusResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getLikeStatusReq{
|
||||||
|
Targets: in.GetTargetId(),
|
||||||
|
LikeType: domain.LikeType(in.GetLikeType()),
|
||||||
|
UID: in.GetUid(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := l.svcCtx.PostLikeModel.FindUIDPostLikeStatus(l.ctx, &model.QueryUIDPostLikeStatusReq{
|
||||||
|
Targets: in.GetTargetId(),
|
||||||
|
LikeType: domain.LikeType(in.GetLikeType()),
|
||||||
|
UID: in.GetUid(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.FindUIDPostLikeStatus"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to find uid post like status list").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
var result = make([]*tweeting.GetLikeStatusItem, 0, len(list))
|
||||||
|
|
||||||
|
for _, item := range list {
|
||||||
|
result = append(result, &tweeting.GetLikeStatusItem{
|
||||||
|
TargetId: item.TargetID,
|
||||||
|
Status: item.LikeStatus,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.GetLikeStatusResp{
|
||||||
|
Data: result,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package postservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IncDecLikeDislikeCountLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIncDecLikeDislikeCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *IncDecLikeDislikeCountLogic {
|
||||||
|
return &IncDecLikeDislikeCountLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type postReactionAction struct {
|
||||||
|
PostID string `json:"post_id" validate:"required"` // 貼文的 ID
|
||||||
|
ReactionType domain.LikeType `json:"reaction_type" validate:"required,oneof=1 2"` // 用戶的反應類型,可能是讚或不讚
|
||||||
|
IsIncrement bool `json:"is_increment" validate:"required"` // 表示是否增加(true 表示增加,false 表示減少)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncDecLikeDislikeCount 增減數量
|
||||||
|
func (l *IncDecLikeDislikeCountLogic) IncDecLikeDislikeCount(in *tweeting.IncDecLikeDislikeCountReq) (*tweeting.OKResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&postReactionAction{
|
||||||
|
PostID: in.GetPostID(),
|
||||||
|
ReactionType: domain.LikeType(in.GetReactionType()),
|
||||||
|
IsIncrement: in.GetIsIncrement(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err := l.svcCtx.PostModel.IncDecLikeDislikeCountLogic(l.ctx, &model.PostReactionAction{
|
||||||
|
PostID: in.GetPostID(),
|
||||||
|
ReactionType: domain.LikeType(in.GetReactionType()),
|
||||||
|
IsIncrement: in.GetIsIncrement(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.IncDecLikeDislikeCountLogic"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to inc like or dislike").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.OKResp{}, nil
|
||||||
|
}
|
|
@ -1,8 +1,12 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
@ -23,9 +27,60 @@ func NewLikeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 換句話說就是對這個文章按讚的人的列表
|
||||||
|
|
||||||
|
type likeListReq struct {
|
||||||
|
Target string `json:"target" validate:"required"`
|
||||||
|
LikeType domain.LikeType `json:"like_type" validate:"required,oneof=1 2"`
|
||||||
|
PageSize int64 `json:"page_size" validate:"required"`
|
||||||
|
PageIndex int64 `json:"page_index" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
// LikeList 取得讚/不讚列表
|
// LikeList 取得讚/不讚列表
|
||||||
func (l *LikeListLogic) LikeList(in *tweeting.LikeListReq) (*tweeting.LikeListResp, error) {
|
func (l *LikeListLogic) LikeList(in *tweeting.LikeListReq) (*tweeting.LikeListResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&likeListReq{
|
||||||
|
Target: in.TargetId,
|
||||||
|
LikeType: domain.LikeType(in.GetLikeType()),
|
||||||
|
PageSize: in.GetPageSize(),
|
||||||
|
PageIndex: in.GetPageIndex(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return &tweeting.LikeListResp{}, nil
|
result, total, err := l.svcCtx.PostLikeModel.FindLikeUsers(l.ctx, &model.QueryPostLikeReq{
|
||||||
|
Target: in.GetTargetId(),
|
||||||
|
LikeType: domain.LikeType(in.GetLikeType()),
|
||||||
|
PageSize: in.GetPageSize(),
|
||||||
|
PageIndex: in.GetPageIndex(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.LikeDislike"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to like or dislike").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = make([]*tweeting.LikeItem, 0, len(result))
|
||||||
|
for _, item := range result {
|
||||||
|
list = append(list, &tweeting.LikeItem{
|
||||||
|
LikeType: int64(item.Type),
|
||||||
|
TargetId: item.TargetID,
|
||||||
|
Uid: item.UID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.LikeListResp{
|
||||||
|
List: list,
|
||||||
|
Page: &tweeting.Pager{
|
||||||
|
Size: in.GetPageSize(),
|
||||||
|
Index: in.GetPageIndex(),
|
||||||
|
Total: total,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
@ -23,9 +27,43 @@ func NewLikeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeLogic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like 點讚/取消讚 貼文
|
type likeReq struct {
|
||||||
func (l *LikeLogic) Like(in *tweeting.LikeReq) (*tweeting.OKResp, error) {
|
Target string `json:"target" validate:"required"`
|
||||||
// todo: add your logic here and delete this line
|
UID string `json:"uid" validate:"required"`
|
||||||
|
}
|
||||||
return &tweeting.OKResp{}, nil
|
|
||||||
|
// Like 點讚/取消讚 貼文
|
||||||
|
func (l *LikeLogic) Like(in *tweeting.LikeReq) (*tweeting.PostReactionActionResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&likeReq{
|
||||||
|
Target: in.TargetId,
|
||||||
|
UID: in.GetUid(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
likeResp, err := l.svcCtx.PostLikeModel.LikeDislike(l.ctx, &model.PostLikes{
|
||||||
|
TargetID: in.GetTargetId(),
|
||||||
|
UID: in.GetUid(),
|
||||||
|
Type: int8(in.GetLikeType()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.LikeDislike"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to like or dislike").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
// 將文章的數量增加或減少的功能,是業務邏輯,從外面再決定要不要丟MQ 後算,或是怎麼算
|
||||||
|
|
||||||
|
return &tweeting.PostReactionActionResp{
|
||||||
|
PostID: likeResp.PostID,
|
||||||
|
ReactionType: int64(likeResp.ReactionType),
|
||||||
|
IsIncrement: likeResp.IsIncrement,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
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"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -23,9 +27,84 @@ func NewListPostsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
// ListPosts 查詢貼文
|
// ListPosts 查詢貼文
|
||||||
func (l *ListPostsLogic) ListPosts(in *tweeting.QueryPostsReq) (*tweeting.ListPostsResp, error) {
|
func (l *ListPostsLogic) ListPosts(in *tweeting.QueryPostsReq) (*tweeting.ListPostsResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&listReq{
|
||||||
|
PageSize: int64(in.GetPageSize()),
|
||||||
|
PageIndex: int64(in.GetPageIndex()),
|
||||||
|
OnlyAdds: in.GetOnlyAds(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return &tweeting.ListPostsResp{}, nil
|
query := &model.QueryPostModelReq{
|
||||||
|
UID: in.GetUid(),
|
||||||
|
Id: in.GetId(),
|
||||||
|
PageSize: int64(in.GetPageSize()),
|
||||||
|
PageIndex: int64(in.GetPageIndex()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.OnlyAds != nil {
|
||||||
|
switch in.GetOnlyAds() {
|
||||||
|
case domain.AdTypeOnlyAd.ToInt32():
|
||||||
|
query.OnlyAds = proto.Bool(true)
|
||||||
|
case domain.AdTypeOnlyNotAd.ToInt32():
|
||||||
|
query.OnlyAds = proto.Bool(false)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
find, count, err := l.svcCtx.PostModel.Find(l.ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "query", Value: query},
|
||||||
|
{Key: "func", Value: "PostModel.Find"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to add new post").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]*tweeting.PostDetailItem, 0, count)
|
||||||
|
|
||||||
|
for _, item := range find {
|
||||||
|
media := make([]*tweeting.Media, 0, len(item.Media))
|
||||||
|
for _, subItem := range item.Media {
|
||||||
|
media = append(media, &tweeting.Media{
|
||||||
|
Type: subItem.Type,
|
||||||
|
Url: subItem.Links,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, &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),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.ListPostsResp{
|
||||||
|
Posts: result,
|
||||||
|
Page: &tweeting.Pager{
|
||||||
|
Total: count,
|
||||||
|
Index: int64(in.GetPageIndex()),
|
||||||
|
Size: int64(in.GetPageSize()),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
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"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -23,9 +26,64 @@ func NewNewPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewPostLo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// NewPost 新增貼文
|
// NewPost 新增貼文
|
||||||
func (l *NewPostLogic) NewPost(in *tweeting.NewPostReq) (*tweeting.PostResp, error) {
|
func (l *NewPostLogic) NewPost(in *tweeting.NewPostReq) (*tweeting.PostResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&newTweetingReq{
|
||||||
|
UID: in.GetUid(),
|
||||||
|
Content: in.GetContent(),
|
||||||
|
}); err != nil {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
return &tweeting.PostResp{}, nil
|
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.Media = media
|
||||||
|
}
|
||||||
|
// ============ insert ============
|
||||||
|
err := l.svcCtx.PostModel.Insert(l.ctx, tweet)
|
||||||
|
if err != nil {
|
||||||
|
e := domain.PostMongoErrorL(
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package postservicelogic
|
package postservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
@ -23,9 +28,53 @@ func NewUpdatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type checkPostId struct {
|
||||||
|
PostID string `validate:"required"`
|
||||||
|
Content string `json:"content,omitempty" validate:"lte=500"`
|
||||||
|
}
|
||||||
|
|
||||||
// UpdatePost 更新貼文
|
// UpdatePost 更新貼文
|
||||||
func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) {
|
func (l *UpdatePostLogic) UpdatePost(in *tweeting.UpdatePostReq) (*tweeting.OKResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&checkPostId{
|
||||||
|
PostID: in.GetPostId(),
|
||||||
|
Content: in.GetContent(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
// 沒有就沒有,有就走全覆蓋
|
||||||
|
update := model.Post{}
|
||||||
|
oid, err := primitive.ObjectIDFromHex(in.GetPostId())
|
||||||
|
if err != nil {
|
||||||
|
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.Media = 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 := domain.PostMongoErrorL(
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "PostModel.UpdateOptional"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to add new post").Wrap(err)
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
return &tweeting.OKResp{}, nil
|
return &tweeting.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type comment_likesModel interface {
|
type comment_likesModel interface {
|
||||||
Insert(ctx context.Context, data *Comment_likes) error
|
Insert(ctx context.Context, data *CommentLikes) error
|
||||||
FindOne(ctx context.Context, id string) (*Comment_likes, error)
|
FindOne(ctx context.Context, id string) (*CommentLikes, error)
|
||||||
Update(ctx context.Context, data *Comment_likes) (*mongo.UpdateResult, error)
|
Update(ctx context.Context, data *CommentLikes) (*mongo.UpdateResult, error)
|
||||||
Delete(ctx context.Context, id string) (int64, error)
|
Delete(ctx context.Context, id string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ func newDefaultComment_likesModel(conn *mon.Model) *defaultComment_likesModel {
|
||||||
return &defaultComment_likesModel{conn: conn}
|
return &defaultComment_likesModel{conn: conn}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultComment_likesModel) Insert(ctx context.Context, data *Comment_likes) error {
|
func (m *defaultComment_likesModel) Insert(ctx context.Context, data *CommentLikes) error {
|
||||||
if data.ID.IsZero() {
|
if data.ID.IsZero() {
|
||||||
data.ID = primitive.NewObjectID()
|
data.ID = primitive.NewObjectID()
|
||||||
data.CreateAt = time.Now()
|
data.CreateAt = time.Now()
|
||||||
|
@ -37,13 +37,13 @@ func (m *defaultComment_likesModel) Insert(ctx context.Context, data *Comment_li
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultComment_likesModel) FindOne(ctx context.Context, id string) (*Comment_likes, error) {
|
func (m *defaultComment_likesModel) FindOne(ctx context.Context, id string) (*CommentLikes, error) {
|
||||||
oid, err := primitive.ObjectIDFromHex(id)
|
oid, err := primitive.ObjectIDFromHex(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrInvalidObjectId
|
return nil, ErrInvalidObjectId
|
||||||
}
|
}
|
||||||
|
|
||||||
var data Comment_likes
|
var data CommentLikes
|
||||||
|
|
||||||
err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid})
|
err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid})
|
||||||
switch err {
|
switch err {
|
||||||
|
@ -56,7 +56,7 @@ func (m *defaultComment_likesModel) FindOne(ctx context.Context, id string) (*Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultComment_likesModel) Update(ctx context.Context, data *Comment_likes) (*mongo.UpdateResult, error) {
|
func (m *defaultComment_likesModel) Update(ctx context.Context, data *CommentLikes) (*mongo.UpdateResult, error) {
|
||||||
data.UpdateAt = time.Now()
|
data.UpdateAt = time.Now()
|
||||||
|
|
||||||
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Comment_likes struct {
|
type CommentLikes struct {
|
||||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||||
// TODO: Fill your own fields
|
// TODO: Fill your own fields
|
||||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "github.com/zeromicro/go-zero/core/stores/mon"
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"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"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
var _ Post_likesModel = (*customPost_likesModel)(nil)
|
var _ Post_likesModel = (*customPost_likesModel)(nil)
|
||||||
|
|
||||||
|
@ -9,6 +20,34 @@ type (
|
||||||
// and implement the added methods in customPost_likesModel.
|
// and implement the added methods in customPost_likesModel.
|
||||||
Post_likesModel interface {
|
Post_likesModel interface {
|
||||||
post_likesModel
|
post_likesModel
|
||||||
|
LikeDislike(ctx context.Context, postLike *PostLikes) (*PostReactionAction, error)
|
||||||
|
FindLikeUsers(ctx context.Context, param *QueryPostLikeReq) ([]*PostLikes, int64, error)
|
||||||
|
FindUIDPostLikeStatus(ctx context.Context, param *QueryUIDPostLikeStatusReq) ([]UIDPostLikeStatusResp, error)
|
||||||
|
Count(ctx context.Context, target string, likeType domain.LikeType) (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
PostReactionAction struct {
|
||||||
|
PostID string // 貼文的 ID
|
||||||
|
ReactionType domain.LikeType // 用戶的反應類型,可能是讚或不讚
|
||||||
|
IsIncrement bool // 表示是否增加(true 表示增加,false 表示減少)
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryPostLikeReq struct {
|
||||||
|
Target string `bson:"target"`
|
||||||
|
LikeType domain.LikeType `bson:"like_type"`
|
||||||
|
PageIndex int64 `bson:"page_index"`
|
||||||
|
PageSize int64 `bson:"page_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryUIDPostLikeStatusReq struct {
|
||||||
|
Targets []string `bson:"target"`
|
||||||
|
LikeType domain.LikeType `bson:"like_type"`
|
||||||
|
UID string
|
||||||
|
}
|
||||||
|
|
||||||
|
UIDPostLikeStatusResp struct {
|
||||||
|
TargetID string `json:"target_id"`
|
||||||
|
LikeStatus bool `json:"like_status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
customPost_likesModel struct {
|
customPost_likesModel struct {
|
||||||
|
@ -23,3 +62,134 @@ func NewPost_likesModel(url, db, collection string) Post_likesModel {
|
||||||
defaultPost_likesModel: newDefaultPost_likesModel(conn),
|
defaultPost_likesModel: newDefaultPost_likesModel(conn),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *defaultPost_likesModel) LikeDislike(ctx context.Context, postLike *PostLikes) (*PostReactionAction, error) {
|
||||||
|
result := &PostReactionAction{
|
||||||
|
PostID: postLike.TargetID,
|
||||||
|
ReactionType: domain.LikeType(postLike.Type),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 target_id、uid、type 來查詢資料是否存在
|
||||||
|
filter := bson.M{
|
||||||
|
"target_id": postLike.TargetID,
|
||||||
|
"uid": postLike.UID,
|
||||||
|
"type": postLike.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查詢資料是否存在
|
||||||
|
var existingPostLike PostLikes
|
||||||
|
err := m.conn.FindOne(ctx, &existingPostLike, filter)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// 資料存在,進行刪除操作
|
||||||
|
result.IsIncrement = false
|
||||||
|
_, err = m.conn.DeleteOne(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err // 刪除失敗
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil // 刪除成功
|
||||||
|
} else if errors.Is(mongo.ErrNoDocuments, err) {
|
||||||
|
// 資料不存在,進行插入操作
|
||||||
|
result.IsIncrement = true
|
||||||
|
postLike.ID = primitive.NewObjectID() // 設置新的 ObjectID
|
||||||
|
postLike.CreateAt = time.Now().UTC().UnixNano()
|
||||||
|
_, err = m.conn.InsertOne(ctx, postLike)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err // 插入失敗
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil // 插入成功
|
||||||
|
} else {
|
||||||
|
// 其他錯誤
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultPost_likesModel) FindLikeUsers(ctx context.Context, param *QueryPostLikeReq) ([]*PostLikes, int64, error) {
|
||||||
|
// 建立篩選條件
|
||||||
|
filter := bson.M{}
|
||||||
|
|
||||||
|
// 如果指定了 Target 條件,將其添加到篩選條件中
|
||||||
|
if param.Target != "" {
|
||||||
|
filter["target_id"] = param.Target
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果指定了 LikeType 條件,將其添加到篩選條件中
|
||||||
|
if param.LikeType != 0 {
|
||||||
|
filter["type"] = param.LikeType
|
||||||
|
}
|
||||||
|
|
||||||
|
// 計算符合條件的文檔總數
|
||||||
|
totalCount, err := m.conn.CountDocuments(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 設置分頁和排序選項
|
||||||
|
opts := options.Find()
|
||||||
|
opts.SetSort(bson.D{{"createAt", -1}}) // 按照創建時間倒序排序
|
||||||
|
if param.PageSize > 0 {
|
||||||
|
opts.SetLimit(param.PageSize)
|
||||||
|
}
|
||||||
|
if param.PageIndex > 0 && param.PageSize > 0 {
|
||||||
|
opts.SetSkip((param.PageIndex - 1) * param.PageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查詢符合條件的文檔
|
||||||
|
var results []*PostLikes
|
||||||
|
err = m.conn.Find(ctx, &results, filter, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回結果集、總數和錯誤信息
|
||||||
|
return results, totalCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultPost_likesModel) FindUIDPostLikeStatus(ctx context.Context, param *QueryUIDPostLikeStatusReq) ([]UIDPostLikeStatusResp, error) {
|
||||||
|
// 初始化返回結果的切片
|
||||||
|
var results []UIDPostLikeStatusResp
|
||||||
|
|
||||||
|
// 建立篩選條件
|
||||||
|
filter := bson.M{
|
||||||
|
"uid": param.UID, // 篩選指定的 UID
|
||||||
|
"target_id": bson.M{"$in": param.Targets}, // 篩選多個目標 ID
|
||||||
|
"type": param.LikeType, // 篩選指定的 LikeType
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查詢符合條件的點讚記錄
|
||||||
|
var postLikes []PostLikes
|
||||||
|
err := m.conn.Find(ctx, &postLikes, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 構建一個 map 來保存查詢到的點讚記錄
|
||||||
|
targetLikeMap := make(map[string]bool)
|
||||||
|
for _, like := range postLikes {
|
||||||
|
targetLikeMap[like.TargetID] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 構建每個目標的點讚狀態
|
||||||
|
for _, targetID := range param.Targets {
|
||||||
|
likeStatus := UIDPostLikeStatusResp{
|
||||||
|
TargetID: targetID,
|
||||||
|
LikeStatus: targetLikeMap[targetID], // 如果 map 中有該 targetID,返回 true,否則返回 false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果該 targetID 沒有點讚記錄,默認 LikeStatus 為 false
|
||||||
|
if _, found := targetLikeMap[targetID]; !found {
|
||||||
|
likeStatus.LikeStatus = false
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, likeStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c customPost_likesModel) Count(ctx context.Context, target string, likeType domain.LikeType) (int64, error) {
|
||||||
|
// TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type post_likesModel interface {
|
type post_likesModel interface {
|
||||||
Insert(ctx context.Context, data *Post_likes) error
|
Insert(ctx context.Context, data *PostLikes) error
|
||||||
FindOne(ctx context.Context, id string) (*Post_likes, error)
|
FindOne(ctx context.Context, id string) (*PostLikes, error)
|
||||||
Update(ctx context.Context, data *Post_likes) (*mongo.UpdateResult, error)
|
Update(ctx context.Context, data *PostLikes) (*mongo.UpdateResult, error)
|
||||||
Delete(ctx context.Context, id string) (int64, error)
|
Delete(ctx context.Context, id string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,24 +26,23 @@ func newDefaultPost_likesModel(conn *mon.Model) *defaultPost_likesModel {
|
||||||
return &defaultPost_likesModel{conn: conn}
|
return &defaultPost_likesModel{conn: conn}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultPost_likesModel) Insert(ctx context.Context, data *Post_likes) error {
|
func (m *defaultPost_likesModel) Insert(ctx context.Context, data *PostLikes) error {
|
||||||
if data.ID.IsZero() {
|
if data.ID.IsZero() {
|
||||||
data.ID = primitive.NewObjectID()
|
data.ID = primitive.NewObjectID()
|
||||||
data.CreateAt = time.Now()
|
data.CreateAt = time.Now().UTC().UnixNano()
|
||||||
data.UpdateAt = time.Now()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := m.conn.InsertOne(ctx, data)
|
_, err := m.conn.InsertOne(ctx, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultPost_likesModel) FindOne(ctx context.Context, id string) (*Post_likes, error) {
|
func (m *defaultPost_likesModel) FindOne(ctx context.Context, id string) (*PostLikes, error) {
|
||||||
oid, err := primitive.ObjectIDFromHex(id)
|
oid, err := primitive.ObjectIDFromHex(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrInvalidObjectId
|
return nil, ErrInvalidObjectId
|
||||||
}
|
}
|
||||||
|
|
||||||
var data Post_likes
|
var data PostLikes
|
||||||
|
|
||||||
err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid})
|
err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid})
|
||||||
switch err {
|
switch err {
|
||||||
|
@ -56,9 +55,7 @@ func (m *defaultPost_likesModel) FindOne(ctx context.Context, id string) (*Post_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultPost_likesModel) Update(ctx context.Context, data *Post_likes) (*mongo.UpdateResult, error) {
|
func (m *defaultPost_likesModel) Update(ctx context.Context, data *PostLikes) (*mongo.UpdateResult, error) {
|
||||||
data.UpdateAt = time.Now()
|
|
||||||
|
|
||||||
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Post_likes struct {
|
type PostLikes struct {
|
||||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||||
// TODO: Fill your own fields
|
TargetID string `bson:"target_id" json:"target_id"`
|
||||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
UID string `bson:"uid" json:"uid"`
|
||||||
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
Type int8 `bson:"type" json:"type"`
|
||||||
|
CreateAt int64 `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PostLikes) CollectionName() string {
|
||||||
|
return "post_like"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||||
"github.com/zeromicro/go-zero/core/stores/monc"
|
"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"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ PostModel = (*customPostModel)(nil)
|
var _ PostModel = (*customPostModel)(nil)
|
||||||
|
@ -12,11 +23,23 @@ type (
|
||||||
// and implement the added methods in customPostModel.
|
// and implement the added methods in customPostModel.
|
||||||
PostModel interface {
|
PostModel interface {
|
||||||
postModel
|
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)
|
||||||
|
IncDecLikeDislikeCountLogic(ctx context.Context, param *PostReactionAction) error
|
||||||
}
|
}
|
||||||
|
|
||||||
customPostModel struct {
|
customPostModel struct {
|
||||||
*defaultPostModel
|
*defaultPostModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryPostModelReq struct {
|
||||||
|
UID []string
|
||||||
|
Id []string
|
||||||
|
OnlyAds *bool
|
||||||
|
PageSize int64
|
||||||
|
PageIndex int64
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPostModel returns a model for the mongo.
|
// NewPostModel returns a model for the mongo.
|
||||||
|
@ -26,3 +49,185 @@ func NewPostModel(url, db, collection string, c cache.CacheConf) PostModel {
|
||||||
defaultPostModel: newDefaultPostModel(conn),
|
defaultPostModel: newDefaultPostModel(conn),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *defaultPostModel) DeleteMany(ctx context.Context, id ...string) (int64, error) {
|
||||||
|
objectIDs := make([]primitive.ObjectID, 0, len(id))
|
||||||
|
key := make([]string, 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)
|
||||||
|
key = append(key, prefixPostCacheKey+item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查是否有有效的 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
|
||||||
|
}
|
||||||
|
|
||||||
|
err = m.conn.DelCache(ctx, key...)
|
||||||
|
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.Media) > 0 {
|
||||||
|
update["$set"].(bson.M)["media_url"] = data.Media
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
fmt.Println("update map", update)
|
||||||
|
|
||||||
|
key := prefixPostCacheKey + data.ID.Hex()
|
||||||
|
res, err := m.conn.UpdateOne(ctx, key, 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *customPostModel) IncDecLikeDislikeCountLogic(ctx context.Context, param *PostReactionAction) error {
|
||||||
|
// 建立篩選條件,找到要更新的貼文
|
||||||
|
filter := bson.M{"_id": param.PostID}
|
||||||
|
|
||||||
|
// 初始化更新操作
|
||||||
|
update := bson.M{}
|
||||||
|
|
||||||
|
// 根據 ReactionType 和 IsIncrement 決定更新邏輯
|
||||||
|
if param.ReactionType == domain.LikeTypeLike {
|
||||||
|
if param.IsIncrement {
|
||||||
|
// 增加 like 計數
|
||||||
|
update = bson.M{"$inc": bson.M{"like": 1}}
|
||||||
|
} else {
|
||||||
|
// 減少 like 計數
|
||||||
|
update = bson.M{"$inc": bson.M{"like": -1}}
|
||||||
|
}
|
||||||
|
} else if param.ReactionType == domain.LikeTypeDisLike {
|
||||||
|
if param.IsIncrement {
|
||||||
|
// 增加 dislike 計數
|
||||||
|
update = bson.M{"$inc": bson.M{"dislike": 1}}
|
||||||
|
} else {
|
||||||
|
// 減少 dislike 計數
|
||||||
|
update = bson.M{"$inc": bson.M{"dislike": -1}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 執行更新操作
|
||||||
|
key := prefixPostCacheKey + param.PostID
|
||||||
|
_, err := c.conn.UpdateOne(ctx, key, filter, update)
|
||||||
|
if err != nil {
|
||||||
|
return err // 返回錯誤信息
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil // 成功返回 nil
|
||||||
|
}
|
||||||
|
|
|
@ -31,8 +31,8 @@ func newDefaultPostModel(conn *monc.Model) *defaultPostModel {
|
||||||
func (m *defaultPostModel) Insert(ctx context.Context, data *Post) error {
|
func (m *defaultPostModel) Insert(ctx context.Context, data *Post) error {
|
||||||
if data.ID.IsZero() {
|
if data.ID.IsZero() {
|
||||||
data.ID = primitive.NewObjectID()
|
data.ID = primitive.NewObjectID()
|
||||||
data.CreateAt = time.Now()
|
data.CreateAt = time.Now().UTC().UnixNano()
|
||||||
data.UpdateAt = time.Now()
|
data.UpdateAt = time.Now().UTC().UnixNano()
|
||||||
}
|
}
|
||||||
|
|
||||||
key := prefixPostCacheKey + data.ID.Hex()
|
key := prefixPostCacheKey + data.ID.Hex()
|
||||||
|
@ -60,7 +60,7 @@ func (m *defaultPostModel) FindOne(ctx context.Context, id string) (*Post, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultPostModel) Update(ctx context.Context, data *Post) (*mongo.UpdateResult, error) {
|
func (m *defaultPostModel) Update(ctx context.Context, data *Post) (*mongo.UpdateResult, error) {
|
||||||
data.UpdateAt = time.Now()
|
data.UpdateAt = time.Now().UTC().UnixNano()
|
||||||
key := prefixPostCacheKey + data.ID.Hex()
|
key := prefixPostCacheKey + data.ID.Hex()
|
||||||
res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO Tag 這裡在效能與正確性之間做取捨
|
||||||
|
// 存在貼文內的不提供搜尋,純顯示用,只不過在原始的tag 發生變動的時候,並不會一起改變
|
||||||
|
// 搜尋會貼文與Tag 的表會再另外一邊做關聯
|
||||||
|
// 暫時業務邏輯上tag 只提供新增,不提供修改以及刪除,故目前版本可行
|
||||||
|
|
||||||
type Post struct {
|
type Post struct {
|
||||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||||
// TODO: Fill your own fields
|
UID string `bson:"uid" json:"uid"`
|
||||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
Content string `bson:"content" json:"content"`
|
||||||
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
Status int8 `bson:"status" json:"status"` // 1. 等待審核中 , 2 審核通過,預設為 1
|
||||||
|
IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文
|
||||||
|
Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除)
|
||||||
|
Media []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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"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"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
"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"
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,14 +46,20 @@ func (s *PostServiceServer) ListPosts(ctx context.Context, in *tweeting.QueryPos
|
||||||
return l.ListPosts(in)
|
return l.ListPosts(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IncDecLikeDislikeCount 增減數量
|
||||||
|
func (s *PostServiceServer) IncDecLikeDislikeCount(ctx context.Context, in *tweeting.IncDecLikeDislikeCountReq) (*tweeting.OKResp, error) {
|
||||||
|
l := postservicelogic.NewIncDecLikeDislikeCountLogic(ctx, s.svcCtx)
|
||||||
|
return l.IncDecLikeDislikeCount(in)
|
||||||
|
}
|
||||||
|
|
||||||
// Like 點讚/取消讚 貼文
|
// Like 點讚/取消讚 貼文
|
||||||
func (s *PostServiceServer) Like(ctx context.Context, in *tweeting.LikeReq) (*tweeting.OKResp, error) {
|
func (s *PostServiceServer) Like(ctx context.Context, in *tweeting.LikeReq) (*tweeting.PostReactionActionResp, error) {
|
||||||
l := postservicelogic.NewLikeLogic(ctx, s.svcCtx)
|
l := postservicelogic.NewLikeLogic(ctx, s.svcCtx)
|
||||||
return l.Like(in)
|
return l.Like(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLikeStatus 取得讚/不讚狀態
|
// GetLikeStatus 取得讚/不讚狀態
|
||||||
func (s *PostServiceServer) GetLikeStatus(ctx context.Context, in *tweeting.LikeReq) (*tweeting.OKResp, error) {
|
func (s *PostServiceServer) GetLikeStatus(ctx context.Context, in *tweeting.GetLikeStatusReq) (*tweeting.GetLikeStatusResp, error) {
|
||||||
l := postservicelogic.NewGetLikeStatusLogic(ctx, s.svcCtx)
|
l := postservicelogic.NewGetLikeStatusLogic(ctx, s.svcCtx)
|
||||||
return l.GetLikeStatus(in)
|
return l.GetLikeStatus(in)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,36 @@
|
||||||
package svc
|
package svc
|
||||||
|
|
||||||
import "app-cloudep-tweeting-service/internal/config"
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/config"
|
||||||
|
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
vi "code.30cm.net/digimon/library-go/validator"
|
||||||
|
)
|
||||||
|
|
||||||
type ServiceContext struct {
|
type ServiceContext struct {
|
||||||
Config config.Config
|
Config config.Config
|
||||||
|
Validate vi.Validate
|
||||||
|
|
||||||
|
PostModel model.PostModel
|
||||||
|
PostLikeModel model.Post_likesModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config) *ServiceContext {
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
|
baseMongo := MustMongoConnectUrl(c)
|
||||||
|
postCollection := model.Post{}
|
||||||
|
postLikeCollection := model.PostLikes{}
|
||||||
|
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
|
Validate: vi.MustValidator(),
|
||||||
|
PostModel: model.NewPostModel(baseMongo, c.Mongo.Database, postCollection.CollectionName(), c.Cache),
|
||||||
|
PostLikeModel: model.NewPost_likesModel(baseMongo, c.Mongo.Database, postLikeCollection.CollectionName()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustMongoConnectUrl(c config.Config) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s://%s:%s", c.Mongo.Schema,
|
||||||
|
c.Mongo.Host, c.Mongo.Port)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue