From b4e70825768c099da6ccb68e40186a581ae810a7 Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Thu, 29 Aug 2024 10:41:34 +0800 Subject: [PATCH] add update and delete post --- etc/tweeting.yaml | 22 +++++ internal/config/config.go | 13 ++- .../logic/postservice/delete_post_logic.go | 14 ++- internal/logic/postservice/new_post_logic.go | 2 +- .../logic/postservice/update_post_logic.go | 50 +++++++++- internal/model/mongo/post_model.go | 92 +++++++++++++++++++ internal/model/mongo/post_model_gen.go | 6 +- internal/model/mongo/post_types.go | 8 +- 8 files changed, 190 insertions(+), 17 deletions(-) diff --git a/etc/tweeting.yaml b/etc/tweeting.yaml index c611c48..9d1d04c 100644 --- a/etc/tweeting.yaml +++ b/etc/tweeting.yaml @@ -4,3 +4,25 @@ Etcd: Hosts: - 127.0.0.1:2379 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 \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index 7055491..eecde82 100755 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,13 +8,12 @@ import ( type Config struct { zrpc.RpcServerConf Mongo struct { - Schema string - User string - Password string - Host string - Port string - Database string - Collection string + Schema string + User string + Password string + Host string + Port string + Database string } // 快取 diff --git a/internal/logic/postservice/delete_post_logic.go b/internal/logic/postservice/delete_post_logic.go index 714e1f5..41f7ddc 100644 --- a/internal/logic/postservice/delete_post_logic.go +++ b/internal/logic/postservice/delete_post_logic.go @@ -1,6 +1,7 @@ package postservicelogic import ( + "app-cloudep-tweeting-service/internal/domain" "context" "app-cloudep-tweeting-service/gen_result/pb/tweeting" @@ -25,7 +26,18 @@ func NewDeletePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete // DeletePost 刪除貼文 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 } diff --git a/internal/logic/postservice/new_post_logic.go b/internal/logic/postservice/new_post_logic.go index ef95a4e..f555b84 100644 --- a/internal/logic/postservice/new_post_logic.go +++ b/internal/logic/postservice/new_post_logic.go @@ -27,7 +27,7 @@ func NewNewPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewPostLo type newTweetingReq struct { UID string `json:"uid" validate:"required"` - Content string `json:"content" validate:"required,gte=500"` // 貼文限制 500 字內 + 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 diff --git a/internal/logic/postservice/update_post_logic.go b/internal/logic/postservice/update_post_logic.go index 454844b..23b5ee3 100644 --- a/internal/logic/postservice/update_post_logic.go +++ b/internal/logic/postservice/update_post_logic.go @@ -1,7 +1,11 @@ package postservicelogic import ( + "app-cloudep-tweeting-service/internal/domain" + model "app-cloudep-tweeting-service/internal/model/mongo" + ers "code.30cm.net/digimon/library-go/errs" "context" + "go.mongodb.org/mongo-driver/bson/primitive" "app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/internal/svc" @@ -23,9 +27,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 更新貼文 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 } diff --git a/internal/model/mongo/post_model.go b/internal/model/mongo/post_model.go index 096dda8..d57daab 100644 --- a/internal/model/mongo/post_model.go +++ b/internal/model/mongo/post_model.go @@ -1,8 +1,15 @@ package model import ( + "context" + "fmt" + "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/cache" "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" + "time" ) var _ PostModel = (*customPostModel)(nil) @@ -12,6 +19,8 @@ type ( // 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) } customPostModel struct { @@ -26,3 +35,86 @@ func NewPostModel(url, db, collection string, c cache.CacheConf) PostModel { 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 +} diff --git a/internal/model/mongo/post_model_gen.go b/internal/model/mongo/post_model_gen.go index c7aa965..386d9c7 100644 --- a/internal/model/mongo/post_model_gen.go +++ b/internal/model/mongo/post_model_gen.go @@ -31,8 +31,8 @@ func newDefaultPostModel(conn *monc.Model) *defaultPostModel { 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() + data.CreateAt = time.Now().UTC().UnixNano() + data.UpdateAt = time.Now().UTC().UnixNano() } 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) { - data.UpdateAt = time.Now() + data.UpdateAt = time.Now().UTC().UnixNano() key := prefixPostCacheKey + data.ID.Hex() res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data}) return res, err diff --git a/internal/model/mongo/post_types.go b/internal/model/mongo/post_types.go index fa07b17..7677d60 100644 --- a/internal/model/mongo/post_types.go +++ b/internal/model/mongo/post_types.go @@ -1,8 +1,6 @@ package model import ( - "time" - "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -19,8 +17,10 @@ type Post struct { IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文 Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除) Media []Media `bson:"media_url" json:"media_url"` // 網址 - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` + 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 {