feature/post #1
|
@ -15,12 +15,17 @@ message Pager {
|
|||
int64 index=3; // 當前頁碼
|
||||
}
|
||||
|
||||
message Media{
|
||||
string type =1;
|
||||
string url =2;
|
||||
}
|
||||
|
||||
// 新增貼文的請求
|
||||
message NewPostReq {
|
||||
int64 user_id = 1; // 發佈貼文的用戶ID
|
||||
string uid = 1; // 發佈貼文的用戶ID
|
||||
string content = 2; // 貼文內容
|
||||
repeated string tags = 3; // 貼文相關標籤
|
||||
repeated string media_url = 4; // 這筆文章的所有 Media URL
|
||||
repeated Media media = 4; // 這筆文章的所有 Media URL
|
||||
bool is_ad = 5; // 是否為廣告
|
||||
}
|
||||
|
||||
|
@ -38,7 +43,7 @@ message DeletePostsReq {
|
|||
message UpdatePostReq {
|
||||
string post_id = 1; // 貼文ID
|
||||
repeated string tags = 2; // 新的標籤列表
|
||||
repeated string media_url = 3; // 這筆文章的所有 Media URL
|
||||
repeated Media media = 3; // 這筆文章的所有 Media URL
|
||||
optional string content = 4; // 新的貼文內容
|
||||
optional int64 like_count = 5; // 喜歡數量
|
||||
optional int64 dislike_count = 6; // 不喜歡數量
|
||||
|
@ -60,7 +65,7 @@ message PostDetailItem {
|
|||
int64 user_id = 2; // 發佈用戶ID
|
||||
string content = 3; // 貼文內容
|
||||
repeated string tags = 4; // 標籤
|
||||
repeated string media_url = 5; // 圖片URL
|
||||
repeated Media media = 5; // 圖片URL
|
||||
bool is_ad = 6; // 是否為廣告
|
||||
int64 created_at = 7; // 發佈時間
|
||||
int64 update_at = 8; // 更新時間
|
||||
|
|
17
go.mod
17
go.mod
|
@ -3,7 +3,10 @@ module app-cloudep-tweeting-service
|
|||
go 1.22.3
|
||||
|
||||
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
|
||||
go.mongodb.org/mongo-driver v1.16.1
|
||||
google.golang.org/grpc v1.66.0
|
||||
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/emicklei/go-restful/v3 v3.11.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/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // 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/golang/mock v1.6.0 // 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/go-cmp v0.6.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/josharian/intern v1.0.0 // 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/mattn/go-colorable v0.1.13 // 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/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/openzipkin/zipkin-go v0.4.3 // 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/redis/go-redis/v9 v9.6.1 // 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/client/pkg/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/multierr v1.9.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/oauth2 v0.21.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/term v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
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 {
|
||||
zrpc.RpcServerConf
|
||||
Mongo struct {
|
||||
Schema string
|
||||
User string
|
||||
Password string
|
||||
Host string
|
||||
Port string
|
||||
Database string
|
||||
Collection string
|
||||
}
|
||||
|
||||
// 快取
|
||||
Cache cache.CacheConf
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"code.30cm.net/digimon/library-go/errs"
|
||||
"code.30cm.net/digimon/library-go/errs/code"
|
||||
"fmt"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
@ -23,9 +25,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,gte=500"` // 貼文限制 500 字內
|
||||
Tags []string `json:"tags"`
|
||||
MediaUrl []string `json:"media_url"`
|
||||
IsAd bool `json:"is_ad"` // default false
|
||||
}
|
||||
|
||||
// NewPost 新增貼文
|
||||
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
|
||||
}
|
||||
|
|
|
@ -6,9 +6,24 @@ import (
|
|||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
// TODO Tag 這裡在效能與正確性之間做取捨
|
||||
// 存在貼文內的不提供搜尋,純顯示用,只不過在原始的tag 發生變動的時候,並不會一起改變
|
||||
// 搜尋會貼文與Tag 的表會再另外一邊做關聯
|
||||
// 暫時業務邏輯上tag 只提供新增,不提供修改以及刪除,故目前版本可行
|
||||
|
||||
type Post struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||
// TODO: Fill your own fields
|
||||
UID string `bson:"uid" json:"uid"`
|
||||
Content string `bson:"content" json:"content"`
|
||||
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"` // 網址
|
||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
||||
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
||||
}
|
||||
|
||||
type Media struct {
|
||||
Type string // media type jpeg, m3u8 之類的
|
||||
Links string // 連結的網址
|
||||
}
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
package svc
|
||||
|
||||
import "app-cloudep-tweeting-service/internal/config"
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/config"
|
||||
model "app-cloudep-tweeting-service/internal/model/mongo"
|
||||
vi "code.30cm.net/digimon/library-go/validator"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ServiceContext struct {
|
||||
Config config.Config
|
||||
Validate vi.Validate
|
||||
|
||||
PostModel model.PostModel
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
baseMongo := MustMongoConnectUrl(c)
|
||||
|
||||
return &ServiceContext{
|
||||
Config: c,
|
||||
Validate: vi.MustValidator(),
|
||||
PostModel: model.NewPostModel(baseMongo, c.Mongo.Database, "post", c.Cache),
|
||||
}
|
||||
}
|
||||
|
||||
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