diff --git a/README.md b/README.md index f1ebb53b..e8f98f80 100644 --- a/README.md +++ b/README.md @@ -383,6 +383,8 @@ release/paopao serve --no-default-features --features sqlite3,localoss,loggerfil |[`Pyroscope`](docs/proposal/23021510-关于使用pyroscope用于性能调试的设计.md)| 性能优化 | 内测 | 开启Pyroscope功能用于性能调试 | |[`Pprof`](docs/proposal/23062905-添加Pprof功能特性用于获取Profile.md)| 性能优化 | 内测 | 开启Pprof功能收集Profile信息 | |`PhoneBind` | 其他 | 稳定 | 手机绑定功能 | +|`UseAuditHook` | 其他 | 内测 | 使用审核hook功能 | +|`UseJobManager` | 其他 | 内测 | 使用JobManager功能 | |`Web:DisallowUserRegister` | 功能特性 | 稳定 | 不允许用户注册 | > 功能项状态详情参考 [features-status](features-status.md). diff --git a/auto/api/v1/priv.go b/auto/api/v1/priv.go index f4adccfc..c6142180 100644 --- a/auto/api/v1/priv.go +++ b/auto/api/v1/priv.go @@ -44,8 +44,20 @@ type Priv interface { mustEmbedUnimplementedPrivServant() } +type PrivChain interface { + ChainCreateTweet() gin.HandlersChain + + mustEmbedUnimplementedPrivChain() +} + // RegisterPrivServant register Priv servant to gin -func RegisterPrivServant(e *gin.Engine, s Priv) { +func RegisterPrivServant(e *gin.Engine, s Priv, m ...PrivChain) { + var cc PrivChain + if len(m) > 0 { + cc = m[0] + } else { + cc = &UnimplementedPrivChain{} + } router := e.Group("v1") // use chain for router middlewares := s.Chain() @@ -297,7 +309,7 @@ func RegisterPrivServant(e *gin.Engine, s Priv) { } s.Render(c, nil, s.DeleteTweet(req)) }) - router.Handle("POST", "/post", func(c *gin.Context) { + router.Handle("POST", "/post", append(cc.ChainCreateTweet(), func(c *gin.Context) { select { case <-c.Request.Context().Done(): return @@ -310,8 +322,13 @@ func RegisterPrivServant(e *gin.Engine, s Priv) { return } resp, err := s.CreateTweet(req) - s.Render(c, resp, err) - }) + if err != nil { + s.Render(c, nil, err) + return + } + var rv _render_ = resp + rv.Render(c) + })...) router.Handle("GET", "/attachment", func(c *gin.Context) { select { case <-c.Request.Context().Done(): @@ -455,3 +472,12 @@ func (UnimplementedPrivServant) UploadAttachment(req *web.UploadAttachmentReq) ( } func (UnimplementedPrivServant) mustEmbedUnimplementedPrivServant() {} + +// UnimplementedPrivChain can be embedded to have forward compatible implementations. +type UnimplementedPrivChain struct{} + +func (b *UnimplementedPrivChain) ChainCreateTweet() gin.HandlersChain { + return nil +} + +func (b *UnimplementedPrivChain) mustEmbedUnimplementedPrivChain() {} diff --git a/features-status.md b/features-status.md index b8b0dafc..4949fdc8 100644 --- a/features-status.md +++ b/features-status.md @@ -196,7 +196,17 @@ * `PhoneBind` 手机绑定功能; * [ ] 提按文档 * [x] 接口定义 - * [x] 业务逻辑实现 + * [x] 业务逻辑实现 + +* `UseAuditHook` 使用审核hook功能 (目前状态: 内测 待完善后将转为Builtin) + * [ ] 提按文档 + * [x] 接口定义 + * [x] 业务逻辑实现 + +* `UseJobManager` 使用JobManager功能 (目前状态: 内测 待完善后将转为Builtin) + * [ ] 提按文档 + * [x] 接口定义 + * [x] 业务逻辑实现 ### 功能特性: * `Web:DisallowUserRegister` 不允许用户注册; diff --git a/internal/events/events.go b/internal/events/events.go index 01b9c15c..cccc145d 100644 --- a/internal/events/events.go +++ b/internal/events/events.go @@ -18,7 +18,7 @@ var ( func Initial() { _onceInitial.Do(func() { initEventManager() - if cfg.If("JobManager") { + if cfg.If("UseJobManager") { initJobManager() logrus.Debugln("initial JobManager") } diff --git a/internal/model/web/audit.go b/internal/model/web/audit.go new file mode 100644 index 00000000..5b891177 --- /dev/null +++ b/internal/model/web/audit.go @@ -0,0 +1,39 @@ +// Copyright 2023 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 + +const ( + AuditStyleUnknown AuditStyle = iota + AuditStyleUserTweet + AuditStyleUserTweetComment + AuditStyleUserTweetReply +) + +const ( + AuditHookCtxKey = "audit_ctx_key" +) + +type AuditStyle uint8 + +type AuditMetaInfo struct { + Style AuditStyle + Id int64 +} + +func (s AuditStyle) String() (res string) { + switch s { + case AuditStyleUserTweet: + res = "UserTweet" + case AuditStyleUserTweetComment: + res = "UserTweetComment" + case AuditStyleUserTweetReply: + res = "UserTweetReply" + case AuditStyleUnknown: + fallthrough + default: + res = "Unknown" + } + return +} diff --git a/internal/model/web/priv.go b/internal/model/web/priv.go index 7ce1aba0..604311b1 100644 --- a/internal/model/web/priv.go +++ b/internal/model/web/priv.go @@ -7,12 +7,14 @@ package web import ( "fmt" "mime/multipart" + "net/http" "strings" "github.com/alimy/mir/v4" "github.com/gin-gonic/gin" "github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core/ms" + "github.com/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/pkg/convert" "github.com/rocboss/paopao-ce/pkg/xerror" @@ -281,3 +283,16 @@ func (r *CreateCommentReq) Bind(c *gin.Context) mir.Error { r.ClientIP = c.ClientIP() return bindAny(c, r) } + +func (r *CreateTweetResp) Render(c *gin.Context) { + c.JSON(http.StatusOK, &joint.JsonResp{ + Code: 0, + Msg: "success", + Data: r, + }) + // 设置审核元信息,用于接下来的审核逻辑 + c.Set(AuditHookCtxKey, &AuditMetaInfo{ + Style: AuditStyleUserTweet, + Id: r.ID, + }) +} diff --git a/internal/servants/chain/audit.go b/internal/servants/chain/audit.go new file mode 100644 index 00000000..01976777 --- /dev/null +++ b/internal/servants/chain/audit.go @@ -0,0 +1,25 @@ +// Copyright 2023 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 chain + +import ( + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/internal/model/web" +) + +func AuditHook() gin.HandlerFunc { + return func(c *gin.Context) { + // 此midleware后面是真正的http handlder,让handler先执行 + c.Next() + // 审核hook 后处理逻辑 + var ami *web.AuditMetaInfo + if val, ok := c.Get(web.AuditHookCtxKey); ok { + if ami, ok = val.(*web.AuditMetaInfo); !ok { + return + } + } + OnAudiotHookEvent(ami) + } +} diff --git a/internal/servants/chain/events.go b/internal/servants/chain/events.go new file mode 100644 index 00000000..d1d73777 --- /dev/null +++ b/internal/servants/chain/events.go @@ -0,0 +1,35 @@ +// Copyright 2023 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 chain + +import ( + "github.com/alimy/tryst/event" + "github.com/rocboss/paopao-ce/internal/events" + "github.com/rocboss/paopao-ce/internal/model/web" + "github.com/sirupsen/logrus" +) + +type AuditHookEvent struct { + event.UnimplementedEvent + ami *web.AuditMetaInfo +} + +func (e *AuditHookEvent) Name() string { + return "AuditHookEvent" +} + +func (e *AuditHookEvent) Action() error { + // TODO: just log event now, will add real logic in future. + logrus.Debugf("auditHook event action style[%s] id[%d]", e.ami.Style, e.ami.Id) + return nil +} + +func OnAudiotHookEvent(ami *web.AuditMetaInfo) { + if ami != nil { + events.OnEvent(&AuditHookEvent{ + ami: ami, + }) + } +} diff --git a/internal/servants/web/priv.go b/internal/servants/web/priv.go index 99d20f8b..329bbe64 100644 --- a/internal/servants/web/priv.go +++ b/internal/servants/web/priv.go @@ -10,6 +10,7 @@ import ( "time" "github.com/alimy/mir/v4" + "github.com/alimy/tryst/cfg" "github.com/disintegration/imaging" "github.com/gin-gonic/gin" "github.com/gofrs/uuid/v5" @@ -27,7 +28,8 @@ import ( ) var ( - _ api.Priv = (*privSrv)(nil) + _ api.Priv = (*privSrv)(nil) + _ api.PrivChain = (*privChain)(nil) _uploadAttachmentTypeMap = map[string]ms.AttachmentType{ "public/image": ms.AttachmentTypeImage, @@ -35,12 +37,6 @@ var ( "public/video": ms.AttachmentTypeVideo, "attachment": ms.AttachmentTypeOther, } - _uploadAttachmentTypes = map[string]cs.AttachmentType{ - "public/image": cs.AttachmentTypeImage, - "public/avatar": cs.AttachmentTypeImage, - "public/video": cs.AttachmentTypeVideo, - "attachment": cs.AttachmentTypeOther, - } ) type privSrv struct { @@ -50,6 +46,17 @@ type privSrv struct { oss core.ObjectStorageService } +type privChain struct { + api.UnimplementedPrivChain +} + +func (s *privChain) ChainCreateTweet() (res gin.HandlersChain) { + if cfg.If("UseAuditHook") { + res = gin.HandlersChain{chain.AuditHook()} + } + return +} + func (s *privSrv) Chain() gin.HandlersChain { return gin.HandlersChain{chain.JWT(), chain.Priv()} } @@ -846,3 +853,7 @@ func newPrivSrv(s *base.DaoServant, oss core.ObjectStorageService) api.Priv { oss: oss, } } + +func newPrivChain() api.PrivChain { + return &privChain{} +} diff --git a/internal/servants/web/web.go b/internal/servants/web/web.go index 14ae8bb1..e281310a 100644 --- a/internal/servants/web/web.go +++ b/internal/servants/web/web.go @@ -36,7 +36,7 @@ func RouteWeb(e *gin.Engine) { api.RegisterCoreServant(e, newCoreSrv(ds, _oss, _wc)) api.RegisterRelaxServant(e, newRelaxSrv(ds, _wc)) api.RegisterLooseServant(e, newLooseSrv(ds, _ac)) - api.RegisterPrivServant(e, newPrivSrv(ds, _oss)) + api.RegisterPrivServant(e, newPrivSrv(ds, _oss), newPrivChain()) api.RegisterPubServant(e, newPubSrv(ds)) api.RegisterFollowshipServant(e, newFollowshipSrv(ds)) api.RegisterFriendshipServant(e, newFriendshipSrv(ds)) diff --git a/mirc/web/v1/priv.go b/mirc/web/v1/priv.go index 567de00d..758afd31 100644 --- a/mirc/web/v1/priv.go +++ b/mirc/web/v1/priv.go @@ -25,7 +25,7 @@ type Priv struct { DownloadAttachment func(Get, web.DownloadAttachmentReq) web.DownloadAttachmentResp `mir:"/attachment"` // CreateTweet 发布动态 - CreateTweet func(Post, web.CreateTweetReq) web.CreateTweetResp `mir:"/post"` + CreateTweet func(Post, Chain, web.CreateTweetReq) web.CreateTweetResp `mir:"/post"` // DeleteTweet 删除动态 DeleteTweet func(Delete, web.DeleteTweetReq) `mir:"/post"`