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
|
|
@ -8,13 +8,12 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
zrpc.RpcServerConf
|
zrpc.RpcServerConf
|
||||||
Mongo struct {
|
Mongo struct {
|
||||||
Schema string
|
Schema string
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
Database string
|
Database string
|
||||||
Collection string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 快取
|
// 快取
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func NewNewPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewPostLo
|
||||||
|
|
||||||
type newTweetingReq struct {
|
type newTweetingReq struct {
|
||||||
UID string `json:"uid" validate:"required"`
|
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"`
|
Tags []string `json:"tags"`
|
||||||
MediaUrl []string `json:"media_url"`
|
MediaUrl []string `json:"media_url"`
|
||||||
IsAd bool `json:"is_ad"` // default false
|
IsAd bool `json:"is_ad"` // default false
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
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"
|
||||||
|
"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 +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 更新貼文
|
// 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
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/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"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ PostModel = (*customPostModel)(nil)
|
var _ PostModel = (*customPostModel)(nil)
|
||||||
|
@ -12,6 +19,8 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
customPostModel struct {
|
customPostModel struct {
|
||||||
|
@ -26,3 +35,86 @@ 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
|
||||||
|
}
|
||||||
|
|
|
@ -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,8 +1,6 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,8 +17,10 @@ type Post struct {
|
||||||
IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文
|
IsAd bool `bson:"is_ad" json:"is_ad"` // 此則貼文是否為廣告貼文
|
||||||
Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除)
|
Tags []string `bson:"tags" json:"tags"` // 本則貼文的標籤,不提供搜尋,僅提供顯示(存名字,ID 建立之後就不提供修改與刪除)
|
||||||
Media []Media `bson:"media_url" json:"media_url"` // 網址
|
Media []Media `bson:"media_url" json:"media_url"` // 網址
|
||||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
Like uint64 `bson:"like" json:"like"` // 讚
|
||||||
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
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 Media struct {
|
||||||
|
|
Loading…
Reference in New Issue