mir: add loose api implement for new web service

pull/196/head
Michael Li 2 years ago
parent 058a30794d
commit 6b2f320cd8
No known key found for this signature in database

@ -14,22 +14,24 @@ type Loose interface {
// Chain provide handlers chain for gin // Chain provide handlers chain for gin
Chain() gin.HandlersChain Chain() gin.HandlersChain
GetUserProfile() mir.Error GetUserProfile(*web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error)
GetUserTweets() mir.Error GetUserTweets(*web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error)
Timeline(*web.TimelineReq) (*web.TimelineResp, mir.Error) Timeline(*web.TimelineReq) (*web.TimelineResp, mir.Error)
mustEmbedUnimplementedLooseServant() mustEmbedUnimplementedLooseServant()
} }
type LooseBinding interface { type LooseBinding interface {
BindGetUserProfile(*gin.Context) (*web.GetUserProfileReq, mir.Error)
BindGetUserTweets(*gin.Context) (*web.GetUserTweetsReq, mir.Error)
BindTimeline(*gin.Context) (*web.TimelineReq, mir.Error) BindTimeline(*gin.Context) (*web.TimelineReq, mir.Error)
mustEmbedUnimplementedLooseBinding() mustEmbedUnimplementedLooseBinding()
} }
type LooseRender interface { type LooseRender interface {
RenderGetUserProfile(*gin.Context, mir.Error) RenderGetUserProfile(*gin.Context, *web.GetUserProfileResp, mir.Error)
RenderGetUserTweets(*gin.Context, mir.Error) RenderGetUserTweets(*gin.Context, *web.GetUserTweetsResp, mir.Error)
RenderTimeline(*gin.Context, *web.TimelineResp, mir.Error) RenderTimeline(*gin.Context, *web.TimelineResp, mir.Error)
mustEmbedUnimplementedLooseRender() mustEmbedUnimplementedLooseRender()
@ -50,7 +52,13 @@ func RegisterLooseServant(e *gin.Engine, s Loose, b LooseBinding, r LooseRender)
default: default:
} }
r.RenderGetUserProfile(c, s.GetUserProfile()) req, err := b.BindGetUserProfile(c)
if err != nil {
r.RenderGetUserProfile(c, nil, err)
return
}
resp, err := s.GetUserProfile(req)
r.RenderGetUserProfile(c, resp, err)
}) })
router.Handle("GET", "/user/posts", func(c *gin.Context) { router.Handle("GET", "/user/posts", func(c *gin.Context) {
@ -60,7 +68,13 @@ func RegisterLooseServant(e *gin.Engine, s Loose, b LooseBinding, r LooseRender)
default: default:
} }
r.RenderGetUserTweets(c, s.GetUserTweets()) req, err := b.BindGetUserTweets(c)
if err != nil {
r.RenderGetUserTweets(c, nil, err)
return
}
resp, err := s.GetUserTweets(req)
r.RenderGetUserTweets(c, resp, err)
}) })
router.Handle("GET", "/posts", func(c *gin.Context) { router.Handle("GET", "/posts", func(c *gin.Context) {
@ -89,12 +103,12 @@ func (UnimplementedLooseServant) Chain() gin.HandlersChain {
return nil return nil
} }
func (UnimplementedLooseServant) GetUserProfile() mir.Error { func (UnimplementedLooseServant) GetUserProfile(req *web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error) {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedLooseServant) GetUserTweets() mir.Error { func (UnimplementedLooseServant) GetUserTweets(req *web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error) {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedLooseServant) Timeline(req *web.TimelineReq) (*web.TimelineResp, mir.Error) { func (UnimplementedLooseServant) Timeline(req *web.TimelineReq) (*web.TimelineResp, mir.Error) {
@ -108,12 +122,12 @@ type UnimplementedLooseRender struct {
RenderAny func(*gin.Context, any, mir.Error) RenderAny func(*gin.Context, any, mir.Error)
} }
func (r *UnimplementedLooseRender) RenderGetUserProfile(c *gin.Context, err mir.Error) { func (r *UnimplementedLooseRender) RenderGetUserProfile(c *gin.Context, data *web.GetUserProfileResp, err mir.Error) {
r.RenderAny(c, nil, err) r.RenderAny(c, data, err)
} }
func (r *UnimplementedLooseRender) RenderGetUserTweets(c *gin.Context, err mir.Error) { func (r *UnimplementedLooseRender) RenderGetUserTweets(c *gin.Context, data *web.GetUserTweetsResp, err mir.Error) {
r.RenderAny(c, nil, err) r.RenderAny(c, data, err)
} }
func (r *UnimplementedLooseRender) RenderTimeline(c *gin.Context, data *web.TimelineResp, err mir.Error) { func (r *UnimplementedLooseRender) RenderTimeline(c *gin.Context, data *web.TimelineResp, err mir.Error) {
@ -127,6 +141,18 @@ type UnimplementedLooseBinding struct {
BindAny func(*gin.Context, any) mir.Error BindAny func(*gin.Context, any) mir.Error
} }
func (b *UnimplementedLooseBinding) BindGetUserProfile(c *gin.Context) (*web.GetUserProfileReq, mir.Error) {
obj := new(web.GetUserProfileReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedLooseBinding) BindGetUserTweets(c *gin.Context) (*web.GetUserTweetsReq, mir.Error) {
obj := new(web.GetUserTweetsReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedLooseBinding) BindTimeline(c *gin.Context) (*web.TimelineReq, mir.Error) { func (b *UnimplementedLooseBinding) BindTimeline(c *gin.Context) (*web.TimelineReq, mir.Error) {
obj := new(web.TimelineReq) obj := new(web.TimelineReq)
err := b.BindAny(c, obj) err := b.BindAny(c, obj)

@ -4,10 +4,46 @@
package web package web
import (
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/servants/base"
)
type TimelineReq struct { type TimelineReq struct {
*BaseInfo `json:"-"` BaseInfo `form:"-" binding:"-"`
Query string `form:"query"`
Visibility []core.PostVisibleT `form:"query"`
Type string `form:"type"`
Page int `form:"-" binding:"-"`
PageSize int `form:"-" binding:"-"`
}
type TimelineResp base.PageResp
type GetUserTweetsReq struct {
BaseInfo `form:"-" binding:"-"`
Username string `form:"username" binding:"required"`
Page int `form:"-" binding:"-"`
PageSize int `form:"-" binding:"-"`
}
type GetUserTweetsResp base.PageResp
type GetUserProfileReq struct {
BaseInfo `form:"-" binding:"-"`
Username string `form:"username" binding:"required"`
}
type GetUserProfileResp struct {
ID int64 `json:"id"`
Nickname string `json:"nickname"`
Username string `json:"username"`
Status int `json:"status"`
Avatar string `json:"avatar"`
IsAdmin bool `json:"is_admin"`
IsFriend bool `json:"is_friend"`
} }
type TimelineResp struct { func (r *GetUserTweetsReq) SetPageInfo(page int, pageSize int) {
// TODO r.Page, r.PageSize = page, pageSize
} }

@ -25,8 +25,8 @@ type TweetDetailResp core.PostFormated
type TweetCommentsReq struct { type TweetCommentsReq struct {
TweetId int64 `form:"id"` TweetId int64 `form:"id"`
Page int `form:"page"` Page int `form:"-"`
PageSize int `form:"page_size"` PageSize int `form:"-"`
} }
type TweetCommentsResp base.PageResp type TweetCommentsResp base.PageResp

@ -40,7 +40,7 @@ func BasePageReqFrom(c *gin.Context) (*BasePageReq, mir.Error) {
if !ok { if !ok {
return nil, xerror.UnauthorizedTokenError return nil, xerror.UnauthorizedTokenError
} }
page, pageSize := app.GetPageOffset(c) page, pageSize := app.GetPageInfo(c)
return &BasePageReq{ return &BasePageReq{
UserId: uid, UserId: uid,
Page: page, Page: page,

@ -15,6 +15,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/pkg/app"
"github.com/rocboss/paopao-ce/pkg/types" "github.com/rocboss/paopao-ce/pkg/types"
"github.com/rocboss/paopao-ce/pkg/xerror" "github.com/rocboss/paopao-ce/pkg/xerror"
) )
@ -47,6 +48,10 @@ type UserIdSetter interface {
SetUserId(int64) SetUserId(int64)
} }
type PageInfoSetter interface {
SetPageInfo(page, pageSize int)
}
func UserFrom(c *gin.Context) (*core.User, bool) { func UserFrom(c *gin.Context) (*core.User, bool) {
if u, exists := c.Get("USER"); exists { if u, exists := c.Get("USER"); exists {
user, ok := u.(*core.User) user, ok := u.(*core.User)
@ -87,6 +92,11 @@ func BindAny(c *gin.Context, obj any) mir.Error {
uid, _ := UserIdFrom(c) uid, _ := UserIdFrom(c)
setter.SetUserId(uid) setter.SetUserId(uid)
} }
// setup PageInfo if needed
if setter, ok := obj.(PageInfoSetter); ok {
page, pageSize := app.GetPageInfo(c)
setter.SetPageInfo(page, pageSize)
}
return nil return nil
} }
@ -142,7 +152,7 @@ func (s *DaoServant) PushPostsToSearch(c context.Context) {
pages := math.Ceil(float64(totalRows) / float64(splitNum)) pages := math.Ceil(float64(totalRows) / float64(splitNum))
nums := int(pages) nums := int(pages)
for i := 0; i < nums; i++ { for i := 0; i < nums; i++ {
posts, postsFormated, err := s.getTweetList(&core.ConditionsT{}, i*splitNum, splitNum) posts, postsFormated, err := s.GetTweetList(&core.ConditionsT{}, i*splitNum, splitNum)
if err != nil || len(posts) != len(postsFormated) { if err != nil || len(posts) != len(postsFormated) {
continue continue
} }
@ -191,7 +201,7 @@ func (s *DaoServant) DeleteSearchPost(post *core.Post) error {
return s.Ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)}) return s.Ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)})
} }
func (s *DaoServant) getTweetList(conditions *core.ConditionsT, offset, limit int) ([]*core.Post, []*core.PostFormated, error) { func (s *DaoServant) GetTweetList(conditions *core.ConditionsT, offset, limit int) ([]*core.Post, []*core.PostFormated, error) {
posts, err := s.Ds.GetPosts(conditions, offset, limit) posts, err := s.Ds.GetPosts(conditions, offset, limit)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

@ -105,7 +105,7 @@ func (b *alipayPrivBinding) BindUserWalletBills(c *gin.Context) (*web.UserWallet
if !ok { if !ok {
return nil, xerror.UnauthorizedTokenError return nil, xerror.UnauthorizedTokenError
} }
page, pageSize := app.GetPageOffset(c) page, pageSize := app.GetPageInfo(c)
return &web.UserWalletBillsReq{ return &web.UserWalletBillsReq{
UserId: uid, UserId: uid,
Page: page, Page: page,

@ -47,7 +47,6 @@ type coreSrv struct {
type coreBinding struct { type coreBinding struct {
*api.UnimplementedCoreBinding *api.UnimplementedCoreBinding
base.BaseBinding
} }
type coreRender struct { type coreRender struct {

@ -5,10 +5,15 @@
package web package web
import ( import (
"github.com/alimy/mir/v3"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
api "github.com/rocboss/paopao-ce/auto/api/v1" api "github.com/rocboss/paopao-ce/auto/api/v1"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/model/web"
"github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/internal/servants/chain" "github.com/rocboss/paopao-ce/internal/servants/chain"
"github.com/rocboss/paopao-ce/pkg/app"
"github.com/sirupsen/logrus"
) )
var ( var (
@ -18,26 +23,136 @@ var (
) )
type looseSrv struct { type looseSrv struct {
base.BaseServant
api.UnimplementedLooseServant api.UnimplementedLooseServant
*base.DaoServant
} }
type looseBinding struct { type looseBinding struct {
base.BaseBinding
*api.UnimplementedLooseBinding *api.UnimplementedLooseBinding
} }
type looseRender struct { type looseRender struct {
base.BaseRender
*api.UnimplementedLooseRender *api.UnimplementedLooseRender
} }
func (s *looseSrv) BindTimeline(c *gin.Context) (*web.TimelineReq, mir.Error) {
user, _ := base.UserFrom(c)
page, pageSize := app.GetPageInfo(c)
v := &web.TimelineReq{
BaseInfo: web.BaseInfo{
User: user,
},
Query: c.Query("query"),
Type: "search",
Page: page,
PageSize: pageSize,
}
if c.Query("type") == "tag" {
v.Type = "tag"
}
return v, nil
}
func (s *looseSrv) Chain() gin.HandlersChain { func (s *looseSrv) Chain() gin.HandlersChain {
return gin.HandlersChain{chain.JwtLoose()} return gin.HandlersChain{chain.JwtLoose()}
} }
func newLooseSrv() api.Loose { func (s *looseSrv) Timeline(req *web.TimelineReq) (*web.TimelineResp, mir.Error) {
return &looseSrv{} var resp *base.PageResp
offset, limit := (req.Page-1)*req.PageSize, req.PageSize
if req.Query == "" && req.Type == "search" {
res, err := s.Ds.IndexPosts(req.User, offset, limit)
if err != nil {
logrus.Errorf("Ds.IndexPosts err: %s", err)
return nil, _errGetPostsFailed
}
resp = base.PageRespFrom(res.Tweets, req.Page, req.PageSize, res.Total)
} else {
q := &core.QueryReq{
Query: req.Query,
Type: core.SearchType(req.Type),
}
res, err := s.Ts.Search(req.User, q, offset, limit)
if err != nil {
logrus.Errorf("Ts.Search err: %s", err)
return nil, _errGetPostsFailed
}
posts, err := s.Ds.RevampPosts(res.Items)
if err != nil {
logrus.Errorf("Ds.RevampPosts err: %s", err)
return nil, _errGetPostsFailed
}
resp = base.PageRespFrom(posts, req.Page, req.PageSize, res.Total)
}
return (*web.TimelineResp)(resp), nil
}
func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error) {
other, xerr := s.GetUserProfile(&web.GetUserProfileReq{
BaseInfo: req.BaseInfo,
Username: req.Username,
})
if xerr != nil {
return nil, xerr
}
visibilities := []core.PostVisibleT{core.PostVisitPublic}
if req.User != nil {
if req.User.ID == other.ID || req.User.IsAdmin {
visibilities = append(visibilities, core.PostVisitPrivate, core.PostVisitFriend)
} else if other.IsFriend {
visibilities = append(visibilities, core.PostVisitFriend)
}
}
conditions := &core.ConditionsT{
"user_id": other.ID,
"visibility IN ?": visibilities,
"ORDER": "latest_replied_on DESC",
}
_, posts, err := s.GetTweetList(conditions, (req.Page-1)*req.PageSize, req.PageSize)
if err != nil {
logrus.Errorf("s.GetTweetList err: %s", err)
return nil, _errGetPostsFailed
}
totalRows, err := s.Ds.GetPostCount(conditions)
if err != nil {
logrus.Errorf("s.GetPostCount err: %s", err)
return nil, _errGetPostsFailed
}
resp := base.PageRespFrom(posts, req.Page, req.PageSize, totalRows)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) GetUserProfile(req *web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error) {
he, err := s.Ds.GetUserByUsername(req.Username)
if err != nil {
logrus.Errorf("Ds.GetUserByUsername err: %s", err)
return nil, _errNoExistUsername
}
if he.Model == nil && he.ID <= 0 {
return nil, _errNoExistUsername
}
// 设定自己不是自己的朋友
isFriend := !(req.User == nil || req.User.ID == he.ID)
if req.User != nil && req.User.ID != he.ID {
isFriend = s.Ds.IsFriend(req.User.ID, he.ID)
}
return &web.GetUserProfileResp{
ID: he.ID,
Nickname: he.Nickname,
Username: he.Username,
Status: he.Status,
Avatar: he.Avatar,
IsAdmin: he.IsAdmin,
IsFriend: isFriend,
}, nil
}
func newLooseSrv(s *base.DaoServant) api.Loose {
return &looseSrv{
DaoServant: s,
}
} }
func newLooseBinding() api.LooseBinding { func newLooseBinding() api.LooseBinding {

@ -48,12 +48,10 @@ type privSrv struct {
} }
type privBinding struct { type privBinding struct {
base.BaseBinding
*api.UnimplementedPrivBinding *api.UnimplementedPrivBinding
} }
type privRender struct { type privRender struct {
base.BaseRender
*api.UnimplementedPrivRender *api.UnimplementedPrivRender
} }

@ -53,18 +53,16 @@ type pubSrv struct {
} }
type pubBinding struct { type pubBinding struct {
base.BaseBinding
*api.UnimplementedPubBinding *api.UnimplementedPubBinding
} }
type pubRender struct { type pubRender struct {
base.BaseRender
*api.UnimplementedPubRender *api.UnimplementedPubRender
} }
func (b *pubBinding) BindTweetComments(c *gin.Context) (*web.TweetCommentsReq, mir.Error) { func (b *pubBinding) BindTweetComments(c *gin.Context) (*web.TweetCommentsReq, mir.Error) {
tweetId := convert.StrTo(c.Query("id")).MustInt64() tweetId := convert.StrTo(c.Query("id")).MustInt64()
page, pageSize := app.GetPageOffset(c) page, pageSize := app.GetPageInfo(c)
return &web.TweetCommentsReq{ return &web.TweetCommentsReq{
TweetId: tweetId, TweetId: tweetId,
Page: page, Page: page,

@ -26,7 +26,7 @@ func RouteWeb(e *gin.Engine) {
// aways register servants // aways register servants
api.RegisterAdminServant(e, newAdminSrv(ds), newAdminBinding(), newAdminRender()) api.RegisterAdminServant(e, newAdminSrv(ds), newAdminBinding(), newAdminRender())
api.RegisterCoreServant(e, newCoreSrv(ds, oss), newCoreBinding(), newCoreRender()) api.RegisterCoreServant(e, newCoreSrv(ds, oss), newCoreBinding(), newCoreRender())
api.RegisterLooseServant(e, newLooseSrv(), newLooseBinding(), newLooseRender()) api.RegisterLooseServant(e, newLooseSrv(ds), newLooseBinding(), newLooseRender())
api.RegisterPrivServant(e, newPrivSrv(ds, oss), newPrivBinding(), newPrivRender()) api.RegisterPrivServant(e, newPrivSrv(ds, oss), newPrivBinding(), newPrivRender())
api.RegisterPubServant(e, newPubSrv(ds), newPubBinding(), newPubRender()) api.RegisterPubServant(e, newPubSrv(ds), newPubBinding(), newPubRender())
// regster servants if needed by configure // regster servants if needed by configure

@ -19,8 +19,8 @@ type Loose struct {
Timeline func(Get, web.TimelineReq) web.TimelineResp `mir:"/posts"` Timeline func(Get, web.TimelineReq) web.TimelineResp `mir:"/posts"`
// GetUserTweets 获取用户动态列表 // GetUserTweets 获取用户动态列表
GetUserTweets func(Get) `mir:"/user/posts"` GetUserTweets func(Get, web.GetUserTweetsReq) web.GetUserTweetsResp `mir:"/user/posts"`
// GetUserProfile 获取用户基本信息 // GetUserProfile 获取用户基本信息
GetUserProfile func(Get) `mir:"/user/profile"` GetUserProfile func(Get, web.GetUserProfileReq) web.GetUserProfileResp `mir:"/user/profile"`
} }

@ -46,3 +46,17 @@ func GetPageOffset(c *gin.Context) (offset, limit int) {
offset = (page - 1) * limit offset = (page - 1) * limit
return return
} }
func GetPageInfo(c *gin.Context) (page, pageSize int) {
page = convert.StrTo(c.Query("page")).MustInt()
if page <= 0 {
page = 1
}
pageSize = convert.StrTo(c.Query("page_size")).MustInt()
if pageSize <= 0 {
pageSize = conf.AppSetting.DefaultPageSize
} else if pageSize > conf.AppSetting.MaxPageSize {
pageSize = conf.AppSetting.MaxPageSize
}
return
}

Loading…
Cancel
Save