mir:add priv api implement for new web service

pull/196/head
Michael Li 2 years ago
parent 64527ec6b2
commit 820d54108d
No known key found for this signature in database

@ -18,22 +18,31 @@ type Priv interface {
CreateCommentReply() mir.Error
DeleteComment() mir.Error
CreateComment() mir.Error
VisiblePost() mir.Error
StickTweet() mir.Error
LockTweet() mir.Error
CollectionTweet() mir.Error
StarTweet() mir.Error
DeleteTweet() mir.Error
VisiblePost(*web.VisiblePostReq) (*web.VisiblePostResp, mir.Error)
StickTweet(*web.StickTweetReq) (*web.StickTweetResp, mir.Error)
LockTweet(*web.LockTweetReq) (*web.LockTweetResp, mir.Error)
CollectionTweet(*web.CollectionTweetReq) (*web.CollectionTweetResp, mir.Error)
StarTweet(*web.StarTweetReq) (*web.StarTweetResp, mir.Error)
DeleteTweet(*web.DeleteTweetReq) mir.Error
CreateTweet(*web.CreateTweetReq) (*web.CreateTweetResp, mir.Error)
DownloadAttachment() mir.Error
DownloadAttachmentPrecheck() mir.Error
UploadAttachment() mir.Error
DownloadAttachment(*web.DownloadAttachmentReq) (*web.DownloadAttachmentResp, mir.Error)
DownloadAttachmentPrecheck(*web.DownloadAttachmentPrecheckReq) (*web.DownloadAttachmentPrecheckResp, mir.Error)
UploadAttachment(*web.UploadAttachmentReq) (*web.UploadAttachmentResp, mir.Error)
mustEmbedUnimplementedPrivServant()
}
type PrivBinding interface {
BindVisiblePost(*gin.Context) (*web.VisiblePostReq, mir.Error)
BindStickTweet(*gin.Context) (*web.StickTweetReq, mir.Error)
BindLockTweet(*gin.Context) (*web.LockTweetReq, mir.Error)
BindCollectionTweet(*gin.Context) (*web.CollectionTweetReq, mir.Error)
BindStarTweet(*gin.Context) (*web.StarTweetReq, mir.Error)
BindDeleteTweet(*gin.Context) (*web.DeleteTweetReq, mir.Error)
BindCreateTweet(*gin.Context) (*web.CreateTweetReq, mir.Error)
BindDownloadAttachment(*gin.Context) (*web.DownloadAttachmentReq, mir.Error)
BindDownloadAttachmentPrecheck(*gin.Context) (*web.DownloadAttachmentPrecheckReq, mir.Error)
BindUploadAttachment(*gin.Context) (*web.UploadAttachmentReq, mir.Error)
mustEmbedUnimplementedPrivBinding()
}
@ -43,16 +52,16 @@ type PrivRender interface {
RenderCreateCommentReply(*gin.Context, mir.Error)
RenderDeleteComment(*gin.Context, mir.Error)
RenderCreateComment(*gin.Context, mir.Error)
RenderVisiblePost(*gin.Context, mir.Error)
RenderStickTweet(*gin.Context, mir.Error)
RenderLockTweet(*gin.Context, mir.Error)
RenderCollectionTweet(*gin.Context, mir.Error)
RenderStarTweet(*gin.Context, mir.Error)
RenderVisiblePost(*gin.Context, *web.VisiblePostResp, mir.Error)
RenderStickTweet(*gin.Context, *web.StickTweetResp, mir.Error)
RenderLockTweet(*gin.Context, *web.LockTweetResp, mir.Error)
RenderCollectionTweet(*gin.Context, *web.CollectionTweetResp, mir.Error)
RenderStarTweet(*gin.Context, *web.StarTweetResp, mir.Error)
RenderDeleteTweet(*gin.Context, mir.Error)
RenderCreateTweet(*gin.Context, *web.CreateTweetResp, mir.Error)
RenderDownloadAttachment(*gin.Context, mir.Error)
RenderDownloadAttachmentPrecheck(*gin.Context, mir.Error)
RenderUploadAttachment(*gin.Context, mir.Error)
RenderDownloadAttachment(*gin.Context, *web.DownloadAttachmentResp, mir.Error)
RenderDownloadAttachmentPrecheck(*gin.Context, *web.DownloadAttachmentPrecheckResp, mir.Error)
RenderUploadAttachment(*gin.Context, *web.UploadAttachmentResp, mir.Error)
mustEmbedUnimplementedPrivRender()
}
@ -112,7 +121,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderVisiblePost(c, s.VisiblePost())
req, err := b.BindVisiblePost(c)
if err != nil {
r.RenderVisiblePost(c, nil, err)
return
}
resp, err := s.VisiblePost(req)
r.RenderVisiblePost(c, resp, err)
})
router.Handle("POST", "/post/stick", func(c *gin.Context) {
@ -122,7 +137,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderStickTweet(c, s.StickTweet())
req, err := b.BindStickTweet(c)
if err != nil {
r.RenderStickTweet(c, nil, err)
return
}
resp, err := s.StickTweet(req)
r.RenderStickTweet(c, resp, err)
})
router.Handle("POST", "/post/lock", func(c *gin.Context) {
@ -132,7 +153,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderLockTweet(c, s.LockTweet())
req, err := b.BindLockTweet(c)
if err != nil {
r.RenderLockTweet(c, nil, err)
return
}
resp, err := s.LockTweet(req)
r.RenderLockTweet(c, resp, err)
})
router.Handle("POST", "/post/collection", func(c *gin.Context) {
@ -142,7 +169,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderCollectionTweet(c, s.CollectionTweet())
req, err := b.BindCollectionTweet(c)
if err != nil {
r.RenderCollectionTweet(c, nil, err)
return
}
resp, err := s.CollectionTweet(req)
r.RenderCollectionTweet(c, resp, err)
})
router.Handle("POST", "/post/start", func(c *gin.Context) {
@ -152,7 +185,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderStarTweet(c, s.StarTweet())
req, err := b.BindStarTweet(c)
if err != nil {
r.RenderStarTweet(c, nil, err)
return
}
resp, err := s.StarTweet(req)
r.RenderStarTweet(c, resp, err)
})
router.Handle("DELETE", "/post", func(c *gin.Context) {
@ -162,7 +201,12 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderDeleteTweet(c, s.DeleteTweet())
req, err := b.BindDeleteTweet(c)
if err != nil {
r.RenderDeleteTweet(c, err)
return
}
r.RenderDeleteTweet(c, s.DeleteTweet(req))
})
router.Handle("POST", "/post", func(c *gin.Context) {
@ -188,7 +232,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderDownloadAttachment(c, s.DownloadAttachment())
req, err := b.BindDownloadAttachment(c)
if err != nil {
r.RenderDownloadAttachment(c, nil, err)
return
}
resp, err := s.DownloadAttachment(req)
r.RenderDownloadAttachment(c, resp, err)
})
router.Handle("GET", "/attachment/precheck", func(c *gin.Context) {
@ -198,7 +248,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderDownloadAttachmentPrecheck(c, s.DownloadAttachmentPrecheck())
req, err := b.BindDownloadAttachmentPrecheck(c)
if err != nil {
r.RenderDownloadAttachmentPrecheck(c, nil, err)
return
}
resp, err := s.DownloadAttachmentPrecheck(req)
r.RenderDownloadAttachmentPrecheck(c, resp, err)
})
router.Handle("POST", "/attachment", func(c *gin.Context) {
@ -208,7 +264,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv, b PrivBinding, r PrivRender) {
default:
}
r.RenderUploadAttachment(c, s.UploadAttachment())
req, err := b.BindUploadAttachment(c)
if err != nil {
r.RenderUploadAttachment(c, nil, err)
return
}
resp, err := s.UploadAttachment(req)
r.RenderUploadAttachment(c, resp, err)
})
}
@ -237,27 +299,27 @@ func (UnimplementedPrivServant) CreateComment() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) VisiblePost() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) VisiblePost(req *web.VisiblePostReq) (*web.VisiblePostResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) StickTweet() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) StickTweet(req *web.StickTweetReq) (*web.StickTweetResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) LockTweet() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) LockTweet(req *web.LockTweetReq) (*web.LockTweetResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) CollectionTweet() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) CollectionTweet(req *web.CollectionTweetReq) (*web.CollectionTweetResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) StarTweet() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) StarTweet(req *web.StarTweetReq) (*web.StarTweetResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) DeleteTweet() mir.Error {
func (UnimplementedPrivServant) DeleteTweet(req *web.DeleteTweetReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
@ -265,16 +327,16 @@ func (UnimplementedPrivServant) CreateTweet(req *web.CreateTweetReq) (*web.Creat
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) DownloadAttachment() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) DownloadAttachment(req *web.DownloadAttachmentReq) (*web.DownloadAttachmentResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) DownloadAttachmentPrecheck() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) DownloadAttachmentPrecheck(req *web.DownloadAttachmentPrecheckReq) (*web.DownloadAttachmentPrecheckResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) UploadAttachment() mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
func (UnimplementedPrivServant) UploadAttachment(req *web.UploadAttachmentReq) (*web.UploadAttachmentResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) mustEmbedUnimplementedPrivServant() {}
@ -300,24 +362,24 @@ func (r *UnimplementedPrivRender) RenderCreateComment(c *gin.Context, err mir.Er
r.RenderAny(c, nil, err)
}
func (r *UnimplementedPrivRender) RenderVisiblePost(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderVisiblePost(c *gin.Context, data *web.VisiblePostResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderStickTweet(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderStickTweet(c *gin.Context, data *web.StickTweetResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderLockTweet(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderLockTweet(c *gin.Context, data *web.LockTweetResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderCollectionTweet(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderCollectionTweet(c *gin.Context, data *web.CollectionTweetResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderStarTweet(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderStarTweet(c *gin.Context, data *web.StarTweetResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderDeleteTweet(c *gin.Context, err mir.Error) {
@ -328,16 +390,16 @@ func (r *UnimplementedPrivRender) RenderCreateTweet(c *gin.Context, data *web.Cr
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderDownloadAttachment(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderDownloadAttachment(c *gin.Context, data *web.DownloadAttachmentResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderDownloadAttachmentPrecheck(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderDownloadAttachmentPrecheck(c *gin.Context, data *web.DownloadAttachmentPrecheckResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) RenderUploadAttachment(c *gin.Context, err mir.Error) {
r.RenderAny(c, nil, err)
func (r *UnimplementedPrivRender) RenderUploadAttachment(c *gin.Context, data *web.UploadAttachmentResp, err mir.Error) {
r.RenderAny(c, data, err)
}
func (r *UnimplementedPrivRender) mustEmbedUnimplementedPrivRender() {}
@ -347,10 +409,64 @@ type UnimplementedPrivBinding struct {
BindAny func(*gin.Context, any) mir.Error
}
func (b *UnimplementedPrivBinding) BindVisiblePost(c *gin.Context) (*web.VisiblePostReq, mir.Error) {
obj := new(web.VisiblePostReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindStickTweet(c *gin.Context) (*web.StickTweetReq, mir.Error) {
obj := new(web.StickTweetReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindLockTweet(c *gin.Context) (*web.LockTweetReq, mir.Error) {
obj := new(web.LockTweetReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindCollectionTweet(c *gin.Context) (*web.CollectionTweetReq, mir.Error) {
obj := new(web.CollectionTweetReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindStarTweet(c *gin.Context) (*web.StarTweetReq, mir.Error) {
obj := new(web.StarTweetReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindDeleteTweet(c *gin.Context) (*web.DeleteTweetReq, mir.Error) {
obj := new(web.DeleteTweetReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindCreateTweet(c *gin.Context) (*web.CreateTweetReq, mir.Error) {
obj := new(web.CreateTweetReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindDownloadAttachment(c *gin.Context) (*web.DownloadAttachmentReq, mir.Error) {
obj := new(web.DownloadAttachmentReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindDownloadAttachmentPrecheck(c *gin.Context) (*web.DownloadAttachmentPrecheckReq, mir.Error) {
obj := new(web.DownloadAttachmentPrecheckReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) BindUploadAttachment(c *gin.Context) (*web.UploadAttachmentReq, mir.Error) {
obj := new(web.UploadAttachmentReq)
err := b.BindAny(c, obj)
return obj, err
}
func (b *UnimplementedPrivBinding) mustEmbedUnimplementedPrivBinding() {}

@ -5,8 +5,6 @@
package web
import (
"context"
"github.com/rocboss/paopao-ce/internal/servants/base"
)
@ -17,7 +15,6 @@ type ChangeAvatarReq struct {
type SyncSearchIndexReq struct {
BaseInfo `json:"-" binding:"-"`
Ctx context.Context `json:"-" binding:"-"`
}
type UserInfoReq struct {

@ -4,10 +4,132 @@
package web
import (
"fmt"
"mime/multipart"
"strings"
"github.com/rocboss/paopao-ce/internal/core"
)
type PostContentItem struct {
Content string `json:"content" binding:"required"`
Type core.PostContentT `json:"type" binding:"required"`
Sort int64 `json:"sort" binding:"required"`
}
type CreateTweetReq struct {
*BaseInfo `json:"-"`
BaseInfo `json:"-" binding:"-"`
Contents []*PostContentItem `json:"contents" binding:"required"`
Tags []string `json:"tags" binding:"required"`
Users []string `json:"users" binding:"required"`
AttachmentPrice int64 `json:"attachment_price"`
Visibility core.PostVisibleT `json:"visibility"`
ClientIP string `json:"-" binding:"-"`
}
type CreateTweetResp core.PostFormated
type DeleteTweetReq struct {
BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
}
type StarTweetReq struct {
SimpleInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
}
type StarTweetResp struct {
Status bool `json:"status"`
}
type CollectionTweetReq struct {
SimpleInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
}
type CollectionTweetResp struct {
Status bool `json:"status"`
}
type LockTweetReq struct {
BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
}
type LockTweetResp struct {
LockStatus int `json:"lock_status"`
}
type StickTweetReq struct {
BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
}
type StickTweetResp struct {
StickStatus int `json:"top_status"`
}
type VisiblePostReq struct {
BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
Visibility core.PostVisibleT `json:"visibility" binding:"required"`
}
type VisiblePostResp struct {
Visibility core.PostVisibleT `json:"visibility"`
}
type UploadAttachmentReq struct {
SimpleInfo `json:"-" binding:"-"`
UploadType string
ContentType string
File multipart.File
FileSize int64
FileExt string
}
type UploadAttachmentResp struct {
UserID int64 `json:"user_id"`
FileSize int64 `json:"file_size"`
ImgWidth int `json:"img_width"`
ImgHeight int `json:"img_height"`
Type core.AttachmentType `json:"type"`
Content string `json:"content"`
}
type DownloadAttachmentPrecheckReq struct {
BaseInfo `json:"-" binding:"-"`
ContentID int64 `form:"id"`
}
type DownloadAttachmentPrecheckResp struct {
Paid bool `json:"paid"`
}
type DownloadAttachmentReq struct {
BaseInfo `json:"-" binding:"-"`
ContentID int64 `form:"id"`
}
type DownloadAttachmentResp struct {
SignedURL string `json:"signed_url"`
}
type CreateTweetResp struct {
// TODO
// Check 检查PostContentItem属性
func (p *PostContentItem) Check(acs core.AttachmentCheckService) error {
// 检查附件是否是本站资源
if p.Type == core.ContentTypeImage || p.Type == core.ContentTypeVideo || p.Type == core.ContentTypeAttachment {
if err := acs.CheckAttachment(p.Content); err != nil {
return err
}
}
// 检查链接是否合法
if p.Type == core.ContentTypeLink {
if strings.Index(p.Content, "http://") != 0 && strings.Index(p.Content, "https://") != 0 {
return fmt.Errorf("链接不合法")
}
}
return nil
}

@ -5,7 +5,11 @@
package base
import (
"context"
"fmt"
"math"
"net/http"
"time"
"github.com/alimy/mir/v3"
"github.com/gin-gonic/gin"
@ -22,6 +26,7 @@ type BaseServant struct {
type DaoServant struct {
Redis *redis.Client
Ds core.DataService
Ts core.TweetSearchService
}
type BaseBinding types.Empty
@ -125,3 +130,72 @@ func (s *DaoServant) GetTweetBy(id int64) (*core.PostFormated, error) {
}
return postFormated, nil
}
func (s *DaoServant) PushPostsToSearch(c context.Context) {
if ok, _ := s.Redis.SetNX(c, "JOB_PUSH_TO_SEARCH", 1, time.Hour).Result(); ok {
defer s.Redis.Del(c, "JOB_PUSH_TO_SEARCH")
splitNum := 1000
totalRows, _ := s.Ds.GetPostCount(&core.ConditionsT{
"visibility IN ?": []core.PostVisibleT{core.PostVisitPublic, core.PostVisitFriend},
})
pages := math.Ceil(float64(totalRows) / float64(splitNum))
nums := int(pages)
for i := 0; i < nums; i++ {
posts, postsFormated, err := s.getTweetList(&core.ConditionsT{}, i*splitNum, splitNum)
if err != nil || len(posts) != len(postsFormated) {
continue
}
for i, pf := range postsFormated {
contentFormated := ""
for _, content := range pf.Contents {
if content.Type == core.ContentTypeText || content.Type == core.ContentTypeTitle {
contentFormated = contentFormated + content.Content + "\n"
}
}
docs := []core.TsDocItem{{
Post: posts[i],
Content: contentFormated,
}}
s.Ts.AddDocuments(docs, fmt.Sprintf("%d", posts[i].ID))
}
}
}
}
func (s *DaoServant) PushPostToSearch(post *core.Post) {
postFormated := post.Format()
postFormated.User = &core.UserFormated{
ID: post.UserID,
}
contents, _ := s.Ds.GetPostContentsByIDs([]int64{post.ID})
for _, content := range contents {
postFormated.Contents = append(postFormated.Contents, content.Format())
}
contentFormated := ""
for _, content := range postFormated.Contents {
if content.Type == core.ContentTypeText || content.Type == core.ContentTypeTitle {
contentFormated = contentFormated + content.Content + "\n"
}
}
docs := []core.TsDocItem{{
Post: post,
Content: contentFormated,
}}
s.Ts.AddDocuments(docs, fmt.Sprintf("%d", post.ID))
}
func (s *DaoServant) DeleteSearchPost(post *core.Post) error {
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) {
posts, err := s.Ds.GetPosts(conditions, offset, limit)
if err != nil {
return nil, nil, err
}
postFormated, err := s.Ds.MergePosts(posts)
return posts, postFormated, err
}

@ -1,15 +0,0 @@
// Copyright 2022 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package localoss
import (
"github.com/rocboss/paopao-ce/pkg/xerror"
)
var (
errFileUploadFailed = xerror.NewError(10200, "文件上传失败")
errFileInvalidExt = xerror.NewError(10201, "文件类型不合法")
errFileInvalidSize = xerror.NewError(10202, "文件大小超限")
)

@ -7,7 +7,7 @@ package web
import (
"context"
"fmt"
"math"
"time"
"unicode/utf8"
@ -42,7 +42,6 @@ type coreSrv struct {
api.UnimplementedCoreServant
*base.DaoServant
ts core.TweetSearchService
oss core.ObjectStorageService
}
@ -55,16 +54,6 @@ type coreRender struct {
*api.UnimplementedCoreRender
}
func (b *coreBinding) BindSyncSearchIndex(c *gin.Context) (*web.SyncSearchIndexReq, mir.Error) {
user, _ := base.UserFrom(c)
return &web.SyncSearchIndexReq{
BaseInfo: web.BaseInfo{
User: user,
},
Ctx: c.Request.Context(),
}, nil
}
func (b *coreBinding) BindGetUserInfo(c *gin.Context) (*web.UserInfoReq, mir.Error) {
username, exist := base.UserNameFrom(c)
if !exist {
@ -134,7 +123,7 @@ func (s *coreSrv) Chain() gin.HandlersChain {
func (s *coreSrv) SyncSearchIndex(req *web.SyncSearchIndexReq) mir.Error {
if req.User != nil && req.User.IsAdmin {
go s.pushPostsToSearch(req.Ctx)
go s.PushPostsToSearch(context.Background())
}
return nil
}
@ -445,38 +434,6 @@ func (s *coreSrv) ChangeAvatar(req *web.ChangeAvatarReq) (xerr mir.Error) {
return nil
}
func (s *coreSrv) pushPostsToSearch(c context.Context) {
if ok, _ := s.Redis.SetNX(c, "JOB_PUSH_TO_SEARCH", 1, time.Hour).Result(); ok {
defer s.Redis.Del(c, "JOB_PUSH_TO_SEARCH")
splitNum := 1000
totalRows, _ := s.Ds.GetPostCount(&core.ConditionsT{
"visibility IN ?": []core.PostVisibleT{core.PostVisitPublic, core.PostVisitFriend},
})
pages := math.Ceil(float64(totalRows) / float64(splitNum))
nums := int(pages)
for i := 0; i < nums; i++ {
posts, postsFormated, err := s.getTweetList(&core.ConditionsT{}, i*splitNum, splitNum)
if err != nil || len(posts) != len(postsFormated) {
continue
}
for i, pf := range postsFormated {
contentFormated := ""
for _, content := range pf.Contents {
if content.Type == core.ContentTypeText || content.Type == core.ContentTypeTitle {
contentFormated = contentFormated + content.Content + "\n"
}
}
docs := []core.TsDocItem{{
Post: posts[i],
Content: contentFormated,
}}
s.ts.AddDocuments(docs, fmt.Sprintf("%d", posts[i].ID))
}
}
}
}
func (s *coreSrv) TweetCollectionStatus(req *web.TweetCollectionStatusReq) (*web.TweetCollectionStatusResp, mir.Error) {
resp := &web.TweetCollectionStatusResp{
Status: true,
@ -499,23 +456,9 @@ func (s *coreSrv) TweetStarStatus(req *web.TweetStarStatusReq) (*web.TweetStarSt
return resp, nil
}
func (s *coreSrv) deleteSearchPost(post *core.Post) error {
return s.ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)})
}
func (s *coreSrv) getTweetList(conditions *core.ConditionsT, offset, limit int) ([]*core.Post, []*core.PostFormated, error) {
posts, err := s.Ds.GetPosts(conditions, offset, limit)
if err != nil {
return nil, nil, err
}
postFormated, err := s.Ds.MergePosts(posts)
return posts, postFormated, err
}
func newCoreSrv(s *base.DaoServant, ts core.TweetSearchService, oss core.ObjectStorageService) api.Core {
func newCoreSrv(s *base.DaoServant, oss core.ObjectStorageService) api.Core {
return &coreSrv{
DaoServant: s,
ts: ts,
oss: oss,
}
}

@ -5,21 +5,42 @@
package web
import (
"image"
"strings"
"github.com/alimy/mir/v3"
"github.com/disintegration/imaging"
"github.com/gin-gonic/gin"
"github.com/gofrs/uuid"
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/chain"
"github.com/rocboss/paopao-ce/pkg/convert"
"github.com/rocboss/paopao-ce/pkg/util"
"github.com/rocboss/paopao-ce/pkg/xerror"
"github.com/sirupsen/logrus"
)
var (
_ api.Priv = (*privSrv)(nil)
_ api.PrivBinding = (*privBinding)(nil)
_ api.PrivRender = (*privRender)(nil)
_uploadAttachmentTypeMap = map[string]core.AttachmentType{
"public/image": core.AttachmentTypeImage,
"public/avatar": core.AttachmentTypeImage,
"public/video": core.AttachmentTypeVideo,
"attachment": core.AttachmentTypeOther,
}
)
type privSrv struct {
base.BaseServant
api.UnimplementedPrivServant
*base.DaoServant
oss core.ObjectStorageService
}
type privBinding struct {
@ -32,12 +53,530 @@ type privRender struct {
*api.UnimplementedPrivRender
}
func (b *privBinding) BindUploadAttachment(c *gin.Context) (*web.UploadAttachmentReq, mir.Error) {
UserId, exist := base.UserIdFrom(c)
if !exist {
return nil, xerror.UnauthorizedAuthNotExist
}
uploadType := c.Request.FormValue("type")
file, fileHeader, err := c.Request.FormFile("file")
if err != nil {
return nil, _errFileUploadFailed
}
if err := fileCheck(uploadType, fileHeader.Size); err != nil {
return nil, err
}
contentType := fileHeader.Header.Get("Content-Type")
fileExt, xerr := getFileExt(contentType)
if xerr != nil {
return nil, xerr
}
return &web.UploadAttachmentReq{
SimpleInfo: web.SimpleInfo{
Uid: UserId,
},
UploadType: uploadType,
ContentType: contentType,
File: file,
FileSize: fileHeader.Size,
FileExt: fileExt,
}, nil
}
func (b *privBinding) BindDownloadAttachmentPrecheck(c *gin.Context) (*web.DownloadAttachmentPrecheckReq, mir.Error) {
user, exist := base.UserFrom(c)
if !exist {
return nil, xerror.UnauthorizedAuthNotExist
}
return &web.DownloadAttachmentPrecheckReq{
BaseInfo: web.BaseInfo{
User: user,
},
ContentID: convert.StrTo(c.Query("id")).MustInt64(),
}, nil
}
func (b *privBinding) BindDownloadAttachment(c *gin.Context) (*web.DownloadAttachmentReq, mir.Error) {
user, exist := base.UserFrom(c)
if !exist {
return nil, xerror.UnauthorizedAuthNotExist
}
return &web.DownloadAttachmentReq{
BaseInfo: web.BaseInfo{
User: user,
},
ContentID: convert.StrTo(c.Query("id")).MustInt64(),
}, nil
}
func (s *privBinding) BindCreateTweet(c *gin.Context) (*web.CreateTweetReq, mir.Error) {
v := &web.CreateTweetReq{}
err := s.BindAny(c, v)
v.ClientIP = c.ClientIP()
return v, err
}
func (s *privSrv) Chain() gin.HandlersChain {
return gin.HandlersChain{chain.JWT(), chain.Priv()}
}
func newPrivSrv() api.Priv {
return &privSrv{}
func (s *privSrv) UploadAttachment(req *web.UploadAttachmentReq) (*web.UploadAttachmentResp, mir.Error) {
defer req.File.Close()
// 生成随机路径
randomPath := uuid.Must(uuid.NewV4()).String()
ossSavePath := req.UploadType + "/" + generatePath(randomPath[:8]) + "/" + randomPath[9:] + req.FileExt
objectUrl, err := s.oss.PutObject(ossSavePath, req.File, req.FileSize, req.ContentType, false)
if err != nil {
logrus.Errorf("oss.putObject err: %s", err)
return nil, _errFileUploadFailed
}
// 构造附件Model
attachment := &core.Attachment{
UserID: req.Uid,
FileSize: req.FileSize,
Content: objectUrl,
Type: _uploadAttachmentTypeMap[req.UploadType],
}
if attachment.Type == core.AttachmentTypeImage {
var src image.Image
src, err = imaging.Decode(req.File)
if err == nil {
attachment.ImgWidth, attachment.ImgHeight = getImageSize(src.Bounds())
}
}
attachment, err = s.Ds.CreateAttachment(attachment)
if err != nil {
logrus.Errorf("Ds.CreateAttachment err: %s", err)
return nil, _errFileUploadFailed
}
return &web.UploadAttachmentResp{
UserID: req.Uid,
FileSize: req.FileSize,
ImgWidth: attachment.ImgWidth,
ImgHeight: attachment.ImgHeight,
Type: attachment.Type,
Content: attachment.Content,
}, nil
}
func (s *privSrv) DownloadAttachmentPrecheck(req *web.DownloadAttachmentPrecheckReq) (*web.DownloadAttachmentPrecheckResp, mir.Error) {
content, err := s.Ds.GetPostContentByID(req.ContentID)
if err != nil {
logrus.Errorf("Ds.GetPostContentByID err: %s", err)
return nil, _errInvalidDownloadReq
}
resp := &web.DownloadAttachmentPrecheckResp{true}
if content.Type == core.ContentTypeChargeAttachment {
tweet, err := s.GetTweetBy(content.PostID)
if err != nil {
logrus.Errorf("get tweet err: %v", err)
return nil, _errInvalidDownloadReq
}
// 发布者或管理员免费下载
if tweet.UserID == req.User.ID || req.User.IsAdmin {
return resp, nil
}
// 检测是否有购买记录
resp.Paid = s.checkPostAttachmentIsPaid(req.ContentID, req.User.ID)
}
return resp, nil
}
func (s *privSrv) DownloadAttachment(req *web.DownloadAttachmentReq) (*web.DownloadAttachmentResp, mir.Error) {
content, err := s.Ds.GetPostContentByID(req.ContentID)
if err != nil {
logrus.Errorf("s.GetPostContentByID err: %v", err)
return nil, _errInvalidDownloadReq
}
// 收费附件
if content.Type == core.ContentTypeChargeAttachment {
post, err := s.GetTweetBy(content.PostID)
if err != nil {
logrus.Errorf("s.GetTweetBy err: %v", err)
return nil, xerror.ServerError
}
paidFlag := false
// 发布者或管理员免费下载 或者 检测是否有购买记录
if post.UserID == req.User.ID || req.User.IsAdmin || s.checkPostAttachmentIsPaid(post.ID, req.User.ID) {
paidFlag = true
}
// 未购买,则尝试购买
if !paidFlag {
err := s.buyPostAttachment(&core.Post{
Model: &core.Model{
ID: post.ID,
},
UserID: post.UserID,
AttachmentPrice: post.AttachmentPrice,
}, req.User)
if err != nil {
return nil, err
}
}
}
// 签发附件下载链接
objectKey := s.oss.ObjectKey(content.Content)
signedURL, err := s.oss.SignURL(objectKey, 60)
if err != nil {
logrus.Errorf("client.SignURL err: %v", err)
return nil, _errDownloadReqError
}
return &web.DownloadAttachmentResp{
SignedURL: signedURL,
}, nil
}
func (s *privSrv) CreateTweet(req *web.CreateTweetReq) (_ *web.CreateTweetResp, xerr mir.Error) {
var mediaContents []string
defer func() {
if xerr != nil {
deleteOssObjects(s.oss, mediaContents)
}
}()
contents, err := persistMediaContents(s.oss, req.Contents)
if err != nil {
return nil, _errCreatePostFailed
}
mediaContents = contents
tags := tagsFrom(req.Tags)
post := &core.Post{
UserID: req.User.ID,
Tags: strings.Join(tags, ","),
IP: req.ClientIP,
IPLoc: util.GetIPLoc(req.ClientIP),
AttachmentPrice: req.AttachmentPrice,
Visibility: req.Visibility,
}
post, err = s.Ds.CreatePost(post)
if err != nil {
logrus.Errorf("Ds.CreatePost err: %s", err)
return nil, _errCreatePostFailed
}
// 创建推文内容
for _, item := range req.Contents {
if err := item.Check(s.Ds); err != nil {
// 属性非法
logrus.Infof("contents check err: %s", err)
continue
}
if item.Type == core.ContentTypeAttachment && req.AttachmentPrice > 0 {
item.Type = core.ContentTypeChargeAttachment
}
postContent := &core.PostContent{
PostID: post.ID,
UserID: req.User.ID,
Content: item.Content,
Type: item.Type,
Sort: item.Sort,
}
if _, err = s.Ds.CreatePostContent(postContent); err != nil {
logrus.Infof("Ds.CreatePostContent err: %s", err)
return nil, _errCreateCommentFailed
}
}
// 私密推文不创建标签与用户提醒
if post.Visibility != core.PostVisitPrivate {
// 创建标签
for _, t := range tags {
tag := &core.Tag{
UserID: req.User.ID,
Tag: t,
}
s.Ds.CreateTag(tag)
}
// 创建用户消息提醒
for _, u := range req.Users {
user, err := s.Ds.GetUserByUsername(u)
if err != nil || user.ID == req.User.ID {
continue
}
// 创建消息提醒
// TODO: 优化消息提醒处理机制
go s.Ds.CreateMessage(&core.Message{
SenderUserID: req.User.ID,
ReceiverUserID: user.ID,
Type: core.MsgTypePost,
Brief: "在新发布的泡泡动态中@了你",
PostID: post.ID,
})
}
}
// 推送Search
go s.PushPostToSearch(post)
formatedPosts, err := s.Ds.RevampPosts([]*core.PostFormated{post.Format()})
if err != nil {
logrus.Infof("Ds.RevampPosts err: %s", err)
return nil, _errCreatePostFailed
}
return (*web.CreateTweetResp)(formatedPosts[0]), nil
}
func (s *privSrv) DeleteTweet(req *web.DeleteTweetReq) mir.Error {
if req.User == nil {
return _errNoPermission
}
post, err := s.Ds.GetPostByID(req.ID)
if err != nil {
logrus.Errorf("Ds.GetPostByID err: %s", err)
return _errGetPostFailed
}
if post.UserID != req.User.ID && !req.User.IsAdmin {
return _errNoPermission
}
mediaContents, err := s.Ds.DeletePost(post)
if err != nil {
logrus.Errorf("Ds.DeletePost delete post failed: %s", err)
return _errDeletePostFailed
}
// 删除推文的媒体内容
deleteOssObjects(s.oss, mediaContents)
// 删除索引
s.DeleteSearchPost(post)
if err != nil {
logrus.Errorf("s.DeleteSearchPost failed: %s", err)
return _errDeletePostFailed
}
return nil
}
func (s *privSrv) CollectionTweet(req *web.CollectionTweetReq) (*web.CollectionTweetResp, mir.Error) {
status := false
collection, err := s.Ds.GetUserPostCollection(req.ID, req.Uid)
if err != nil {
// 创建Star
if _, xerr := s.createPostCollection(req.ID, req.Uid); xerr != nil {
return nil, xerr
}
status = true
} else {
// 取消Star
if xerr := s.deletePostCollection(collection); xerr != nil {
return nil, xerr
}
}
return &web.CollectionTweetResp{
Status: status,
}, nil
}
func (s *privSrv) StarTweet(req *web.StarTweetReq) (*web.StarTweetResp, mir.Error) {
status := false
star, err := s.Ds.GetUserPostStar(req.ID, req.Uid)
if err != nil {
// 创建Star
if _, xerr := s.createPostStar(req.ID, req.Uid); xerr != nil {
return nil, xerr
}
status = true
} else {
// 取消Star
if xerr := s.deletePostStar(star); xerr != nil {
return nil, xerr
}
}
return &web.StarTweetResp{
Status: status,
}, nil
}
func (s *privSrv) VisiblePost(req *web.VisiblePostReq) (*web.VisiblePostResp, mir.Error) {
if req.Visibility >= core.PostVisitInvalid {
return nil, xerror.InvalidParams
}
post, err := s.Ds.GetPostByID(req.User.ID)
if err != nil {
return nil, _errVisblePostFailed
}
if xerr := checkPermision(req.User, post.UserID); xerr != nil {
return nil, xerr
}
if err = s.Ds.VisiblePost(post, req.Visibility); err != nil {
logrus.Warnf("update post failure: %v", err)
return nil, _errVisblePostFailed
}
// 推送Search
post.Visibility = req.Visibility
go s.PushPostToSearch(post)
return &web.VisiblePostResp{
Visibility: req.Visibility,
}, nil
}
func (s *privSrv) StickTweet(req *web.StickTweetReq) (*web.StickTweetResp, mir.Error) {
post, err := s.Ds.GetPostByID(req.ID)
if err != nil {
logrus.Errorf("Ds.GetPostByID err: %v\n", err)
return nil, _errStickPostFailed
}
if !req.User.IsAdmin {
return nil, _errNoPermission
}
if err = s.Ds.StickPost(post); err != nil {
return nil, _errStickPostFailed
}
return &web.StickTweetResp{
StickStatus: 1 - post.IsTop,
}, nil
}
func (s *privSrv) LockTweet(req *web.LockTweetReq) (*web.LockTweetResp, mir.Error) {
post, err := s.Ds.GetPostByID(req.ID)
if err != nil {
return nil, _errLockPostFailed
}
if post.UserID != req.User.ID && !req.User.IsAdmin {
return nil, _errNoPermission
}
if err := s.Ds.LockPost(post); err != nil {
return nil, _errLockPostFailed
}
return &web.LockTweetResp{
LockStatus: 1 - post.IsLock,
}, nil
}
func (s *privSrv) createPostStar(postID, userID int64) (*core.PostStar, mir.Error) {
// 加载Post
post, err := s.Ds.GetPostByID(postID)
if err != nil {
return nil, xerror.ServerError
}
// 私密post不可操作
if post.Visibility == core.PostVisitPrivate {
return nil, _errNoPermission
}
star, err := s.Ds.CreatePostStar(postID, userID)
if err != nil {
return nil, xerror.ServerError
}
// 更新Post点赞数
post.UpvoteCount++
s.Ds.UpdatePost(post)
// 更新索引
s.PushPostToSearch(post)
return star, nil
}
func (s *privSrv) deletePostStar(star *core.PostStar) mir.Error {
err := s.Ds.DeletePostStar(star)
if err != nil {
return xerror.ServerError
}
// 加载Post
post, err := s.Ds.GetPostByID(star.PostID)
if err != nil {
return xerror.ServerError
}
// 私密post不可操作
if post.Visibility == core.PostVisitPrivate {
return _errNoPermission
}
// 更新Post点赞数
post.UpvoteCount--
s.Ds.UpdatePost(post)
// 更新索引
s.PushPostToSearch(post)
return nil
}
func (s *privSrv) createPostCollection(postID, userID int64) (*core.PostCollection, mir.Error) {
// 加载Post
post, err := s.Ds.GetPostByID(postID)
if err != nil {
return nil, xerror.ServerError
}
// 私密post不可操作
if post.Visibility == core.PostVisitPrivate {
return nil, _errNoPermission
}
collection, err := s.Ds.CreatePostCollection(postID, userID)
if err != nil {
return nil, xerror.ServerError
}
// 更新Post点赞数
post.CollectionCount++
s.Ds.UpdatePost(post)
// 更新索引
s.PushPostToSearch(post)
return collection, nil
}
func (s *privSrv) deletePostCollection(collection *core.PostCollection) mir.Error {
err := s.Ds.DeletePostCollection(collection)
if err != nil {
return xerror.ServerError
}
// 加载Post
post, err := s.Ds.GetPostByID(collection.PostID)
if err != nil {
return xerror.ServerError
}
// 私密post不可操作
if post.Visibility == core.PostVisitPrivate {
return _errNoPermission
}
// 更新Post点赞数
post.CollectionCount--
s.Ds.UpdatePost(post)
// 更新索引
s.PushPostToSearch(post)
return nil
}
func (s *privSrv) checkPostAttachmentIsPaid(postID, userID int64) bool {
bill, err := s.Ds.GetPostAttatchmentBill(postID, userID)
return err == nil && bill.Model != nil && bill.ID > 0
}
func (s *privSrv) buyPostAttachment(post *core.Post, user *core.User) mir.Error {
if user.Balance < post.AttachmentPrice {
return _errInsuffientDownloadMoney
}
// 执行购买
if err := s.Ds.HandlePostAttachmentBought(post, user); err != nil {
logrus.Errorf("Ds.HandlePostAttachmentBought err: %s", err)
return xerror.ServerError
}
return nil
}
func newPrivSrv(s *base.DaoServant, oss core.ObjectStorageService) api.Priv {
return &privSrv{
DaoServant: s,
oss: oss,
}
}
func newPrivBinding() api.PrivBinding {

@ -1,13 +1,21 @@
// Copyright 2022 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package web
import (
"image"
"strings"
"unicode/utf8"
"github.com/alimy/mir/v3"
"github.com/gofrs/uuid"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/model/web"
"github.com/rocboss/paopao-ce/pkg/util"
"github.com/rocboss/paopao-ce/pkg/xerror"
"github.com/sirupsen/logrus"
)
// checkPassword 密码检查
@ -45,3 +53,93 @@ func deleteOssObjects(oss core.ObjectStorageService, mediaContents []string) {
oss.DeleteObject(oss.ObjectKey(mediaContents[0]))
}
}
// persistMediaContents 获取媒体内容并持久化
func persistMediaContents(oss core.ObjectStorageService, contents []*web.PostContentItem) (items []string, err error) {
items = make([]string, 0, len(contents))
for _, item := range contents {
switch item.Type {
case core.ContentTypeImage,
core.ContentTypeVideo,
core.ContentTypeAudio,
core.ContentTypeAttachment,
core.ContentTypeChargeAttachment:
items = append(items, item.Content)
if err != nil {
continue
}
if err = oss.PersistObject(oss.ObjectKey(item.Content)); err != nil {
logrus.Errorf("service.persistMediaContents failed: %s", err)
}
}
}
return
}
func fileCheck(uploadType string, size int64) mir.Error {
if uploadType != "public/video" &&
uploadType != "public/image" &&
uploadType != "public/avatar" &&
uploadType != "attachment" {
return xerror.InvalidParams
}
if size > 1024*1024*100 {
return _errFileInvalidSize.WithDetails("最大允许100MB")
}
return nil
}
func getFileExt(s string) (string, mir.Error) {
switch s {
case "image/png":
return ".png", nil
case "image/jpg":
return ".jpg", nil
case "image/jpeg":
return ".jpeg", nil
case "image/gif":
return ".gif", nil
case "video/mp4":
return ".mp4", nil
case "video/quicktime":
return ".mov", nil
case "application/zip":
return ".zip", nil
default:
return "", _errFileInvalidExt.WithDetails("仅允许 png/jpg/gif/mp4/mov/zip 类型")
}
}
func generatePath(s string) string {
n := len(s)
if n <= 2 {
return s
}
return generatePath(s[:n-2]) + "/" + s[n-2:]
}
func getImageSize(img image.Rectangle) (int, int) {
b := img.Bounds()
width := b.Max.X
height := b.Max.Y
return width, height
}
func tagsFrom(originTags []string) []string {
tags := make([]string, 0, len(originTags))
for _, tag := range originTags {
// TODO: 优化tag有效性检测
if tag = strings.TrimSpace(tag); len(tag) > 0 {
tags = append(tags, tag)
}
}
return tags
}
// checkPermision 检查是否拥有者或管理员
func checkPermision(user *core.User, targetUserId int64) mir.Error {
if user == nil || (user.ID != targetUserId && !user.IsAdmin) {
return _errNoPermission
}
return nil
}

@ -17,17 +17,17 @@ import (
// RouteWeb register web route
func RouteWeb(e *gin.Engine) {
ts := dao.TweetSearchService()
oss := dao.ObjectStorageService()
ds := &base.DaoServant{
Redis: conf.Redis,
Ds: dao.DataService(),
Ts: dao.TweetSearchService(),
}
// aways register servants
api.RegisterAdminServant(e, newAdminSrv(ds), newAdminBinding(), newAdminRender())
api.RegisterCoreServant(e, newCoreSrv(ds, ts, oss), newCoreBinding(), newCoreRender())
api.RegisterCoreServant(e, newCoreSrv(ds, oss), newCoreBinding(), newCoreRender())
api.RegisterLooseServant(e, newLooseSrv(), newLooseBinding(), newLooseRender())
api.RegisterPrivServant(e, newPrivSrv(), newPrivBinding(), newPrivRender())
api.RegisterPrivServant(e, newPrivSrv(ds, oss), newPrivBinding(), newPrivRender())
api.RegisterPubServant(e, newPubSrv(), newPubBinding(), newPubRender())
// regster servants if needed by configure
cfg.In(cfg.Actions{

@ -76,4 +76,8 @@ var (
_errDeleteFriendFailed = xerror.NewError(80006, "删除好友失败")
_errGetContactsFailed = xerror.NewError(80007, "获取联系人列表失败")
_errNoActionToSelf = xerror.NewError(80008, "不允许对自己操作")
_errFileUploadFailed = xerror.NewError(10200, "文件上传失败")
_errFileInvalidExt = xerror.NewError(10201, "文件类型不合法")
_errFileInvalidSize = xerror.NewError(10202, "文件大小超限")
)

@ -16,34 +16,34 @@ type Priv struct {
Group Group `mir:"v1"`
// UploadAttachment 上传资源
UploadAttachment func(Post) `mir:"/attachment"`
UploadAttachment func(Post, web.UploadAttachmentReq) web.UploadAttachmentResp `mir:"/attachment"`
// DownloadAttachmentPrecheck 下载资源预检
DownloadAttachmentPrecheck func(Get) `mir:"/attachment/precheck"`
DownloadAttachmentPrecheck func(Get, web.DownloadAttachmentPrecheckReq) web.DownloadAttachmentPrecheckResp `mir:"/attachment/precheck"`
// DownloadAttachment 下载资源
DownloadAttachment func(Get) `mir:"/attachment"`
DownloadAttachment func(Get, web.DownloadAttachmentReq) web.DownloadAttachmentResp `mir:"/attachment"`
// CreateTweet 发布动态
CreateTweet func(Post, web.CreateTweetReq) web.CreateTweetResp `mir:"/post"`
// DeleteTweet 删除动态
DeleteTweet func(Delete) `mir:"/post"`
DeleteTweet func(Delete, web.DeleteTweetReq) `mir:"/post"`
// StarTweet 动态点赞操作
StarTweet func(Post) `mir:"/post/start"`
StarTweet func(Post, web.StarTweetReq) web.StarTweetResp `mir:"/post/start"`
// CollectionTweet 动态收藏操作
CollectionTweet func(Post) `mir:"/post/collection"`
CollectionTweet func(Post, web.CollectionTweetReq) web.CollectionTweetResp `mir:"/post/collection"`
// LockTweet 锁定动态
LockTweet func(Post) `mir:"/post/lock"`
LockTweet func(Post, web.LockTweetReq) web.LockTweetResp `mir:"/post/lock"`
// StickTweet 置顶动态
StickTweet func(Post) `mir:"/post/stick"`
StickTweet func(Post, web.StickTweetReq) web.StickTweetResp `mir:"/post/stick"`
// VisiblePost 修改动态可见度
VisiblePost func(Post) `mir:"/post/visibility"`
VisiblePost func(Post, web.VisiblePostReq) web.VisiblePostResp `mir:"/post/visibility"`
// CreateTweetComment 发布动态评论
CreateComment func(Post) `mir:"/post/comment"`

Loading…
Cancel
Save