add list posts

This commit is contained in:
daniel.w 2024-08-29 21:26:01 +08:00
parent 518e1673fe
commit 98605573f3
15 changed files with 272 additions and 43 deletions

View File

@ -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 });

View File

@ -0,0 +1,5 @@
db.post_likes.createIndex(
{ "target_id": 1, "uid": 1, "type": 1 },
{ unique: true }
);
db.post_likes.createIndex({ "create_time": 1 });

View File

@ -81,14 +81,30 @@ message ListPostsResp {
// / // /
message LikeReq { message LikeReq {
string target_id = 1; // IDID或評論ID string target_id = 1; // IDID或評論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; // IDID或評論ID
int64 like_type = 3; //
}
message GetLikeStatusItem{
string target_id = 1; // IDID或評論ID
bool status = 2; //
}
message GetLikeStatusResp{
repeated GetLikeStatusItem data = 1; // IDID或評論ID
}
// / // /
message LikeItem { message LikeItem {
string target_id = 1; // IDID或評論ID string target_id = 1; // IDID或評論ID
int64 user_id = 2; // ID string uid = 2; // ID
int64 like_type = 3; // int64 like_type = 3; //
} }
@ -96,8 +112,8 @@ message LikeItem {
message LikeListReq { message LikeListReq {
string target_id = 1; // IDID或評論ID string target_id = 1; // IDID或評論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; //
} }
// / // /
@ -172,7 +188,7 @@ service PostService {
// Like / // Like /
rpc Like(LikeReq) returns (OKResp); rpc Like(LikeReq) returns (OKResp);
// 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 /

View File

@ -11,3 +11,14 @@ const (
AdTypeOnlyAd AdTypeOnlyAd
AdTypeOnlyNotAd AdTypeOnlyNotAd
) )
type LikeType int8
func (l LikeType) ToInt32() int8 {
return int8(l)
}
const (
LikeTypeLike LikeType = iota + 1 // 按揍
LikeTypeDisLike
)

View File

@ -23,6 +23,8 @@ func NewGetLikeStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Get
} }
} }
// 這個人按讚的文章列表輸入UID 以及文章id返回這個人有沒有對這些文章按讚
// GetLikeStatus 取得讚/不讚狀態 // GetLikeStatus 取得讚/不讚狀態
func (l *GetLikeStatusLogic) GetLikeStatus(in *tweeting.LikeReq) (*tweeting.OKResp, error) { func (l *GetLikeStatusLogic) GetLikeStatus(in *tweeting.LikeReq) (*tweeting.OKResp, error) {
// todo: add your logic here and delete this line // todo: add your logic here and delete this line

View File

@ -1,6 +1,9 @@
package postservicelogic package postservicelogic
import ( import (
"app-cloudep-tweeting-service/internal/domain"
model "app-cloudep-tweeting-service/internal/model/mongo"
ers "code.30cm.net/digimon/library-go/errs"
"context" "context"
"app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/gen_result/pb/tweeting"
@ -23,9 +26,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
} }

View File

@ -1,6 +1,9 @@
package postservicelogic package postservicelogic
import ( import (
"app-cloudep-tweeting-service/internal/domain"
model "app-cloudep-tweeting-service/internal/model/mongo"
ers "code.30cm.net/digimon/library-go/errs"
"context" "context"
"app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/gen_result/pb/tweeting"
@ -23,9 +26,39 @@ func NewLikeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LikeLogic {
} }
} }
type likeReq struct {
Target string `json:"target" validate:"required"`
UID string `json:"uid" validate:"required"`
LikeType domain.LikeType `json:"like_type" validate:"required,oneof=1 2"`
}
// Like 點讚/取消讚 貼文 // Like 點讚/取消讚 貼文
func (l *LikeLogic) Like(in *tweeting.LikeReq) (*tweeting.OKResp, error) { func (l *LikeLogic) Like(in *tweeting.LikeReq) (*tweeting.OKResp, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&likeReq{
Target: in.TargetId,
UID: in.GetUid(),
LikeType: domain.LikeType(in.GetLikeType()),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
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
}
return &tweeting.OKResp{}, nil return &tweeting.OKResp{}, nil
} }

View File

@ -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})

View File

@ -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"`

View File

@ -1,6 +1,16 @@
package model package model
import "github.com/zeromicro/go-zero/core/stores/mon" import (
"app-cloudep-tweeting-service/internal/domain"
"context"
"errors"
"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"
"time"
)
var _ Post_likesModel = (*customPost_likesModel)(nil) var _ Post_likesModel = (*customPost_likesModel)(nil)
@ -9,6 +19,15 @@ 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) error
FindLikeUsers(ctx context.Context, param *QueryPostLikeReq) ([]*PostLikes, int64, error)
}
QueryPostLikeReq struct {
Target string `bson:"target"`
LikeType domain.LikeType `bson:"like_type"`
PageIndex int64 `bson:"page_index"`
PageSize int64 `bson:"page_size"`
} }
customPost_likesModel struct { customPost_likesModel struct {
@ -23,3 +42,78 @@ 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) error {
// 使用 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 {
// 資料存在,進行刪除操作
_, err = m.conn.DeleteOne(ctx, filter)
if err != nil {
return err // 刪除失敗
}
return nil // 刪除成功
} else if errors.Is(mongo.ErrNoDocuments, err) {
// 資料不存在,進行插入操作
postLike.ID = primitive.NewObjectID() // 設置新的 ObjectID
postLike.CreateAt = time.Now().UTC().UnixNano()
_, err = m.conn.InsertOne(ctx, postLike)
if err != nil {
return err // 插入失敗
}
return nil // 插入成功
} else {
// 其他錯誤
return 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
}

View File

@ -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
} }

View File

@ -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"
} }

View File

@ -161,12 +161,13 @@ func (m *defaultPostModel) Find(ctx context.Context, param *QueryPostModelReq) (
} }
// 分頁處理 // 分頁處理
options := options.Find() opts := options.Find()
opts.SetSort(bson.D{{"create_time", -1}})
if param.PageSize > 0 { if param.PageSize > 0 {
options.SetLimit(param.PageSize) opts.SetLimit(param.PageSize)
} }
if param.PageIndex > 0 { if param.PageIndex > 0 {
options.SetSkip((param.PageIndex - 1) * param.PageSize) opts.SetSkip((param.PageIndex - 1) * param.PageSize)
} }
// 計算總數(不考慮分頁) // 計算總數(不考慮分頁)
@ -177,7 +178,7 @@ func (m *defaultPostModel) Find(ctx context.Context, param *QueryPostModelReq) (
result := make([]*Post, 0, param.PageSize) result := make([]*Post, 0, param.PageSize)
// 執行查詢 // 執行查詢
err = m.conn.Find(ctx, &result, filter, options) err = m.conn.Find(ctx, &result, filter, opts)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }

View File

@ -27,3 +27,7 @@ type Media struct {
Type string // media type jpeg, m3u8 之類的 Type string // media type jpeg, m3u8 之類的
Links string // 連結的網址 Links string // 連結的網址
} }
func (p *Post) CollectionName() string {
return "post"
}

View File

@ -12,15 +12,19 @@ type ServiceContext struct {
Validate vi.Validate Validate vi.Validate
PostModel model.PostModel PostModel model.PostModel
PostLikeModel model.Post_likesModel
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
baseMongo := MustMongoConnectUrl(c) baseMongo := MustMongoConnectUrl(c)
postCollection := model.Post{}
postLikeCollection := model.PostLikes{}
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
Validate: vi.MustValidator(), Validate: vi.MustValidator(),
PostModel: model.NewPostModel(baseMongo, c.Mongo.Database, "post", c.Cache), PostModel: model.NewPostModel(baseMongo, c.Mongo.Database, postCollection.CollectionName(), c.Cache),
PostLikeModel: model.NewPost_likesModel(baseMongo, c.Mongo.Database, postLikeCollection.CollectionName()),
} }
} }