feature/post #1

Open
daniel.w wants to merge 7 commits from feature/post into main
8 changed files with 190 additions and 17 deletions
Showing only changes of commit b4e7082576 - Show all commits

View File

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

View File

@ -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
}
// 快取

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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