作者 yangfu

Merge branch 'dev' into test

正在显示 31 个修改的文件 包含 1997 行增加43 行删除
... ... @@ -11,3 +11,4 @@ import "core/article.api"
import "core/role.api"
import "core/department.api"
import "core/article_category.api"
import "core/article_security.api"
\ No newline at end of file
... ...
... ... @@ -1013,6 +1013,64 @@
]
}
},
"v1/mini/message/subscribe/add": {
"post": {
"summary": "增加订阅消息次数",
"operationId": "miniMessageSubscribeAdd",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/MessageSubscribeAddResponse"
}
}
},
"parameters": [
{
"name": "body",
"description": " 增加消息订阅次数",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/MessageSubscribeAddRequest"
}
}
],
"requestBody": {},
"tags": [
"message"
]
}
},
"v1/mini/message/subscribe/list": {
"post": {
"summary": "获取订阅消息次数",
"operationId": "miniMessageSubscribeList",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/MessageSubscribeListResponse"
}
}
},
"parameters": [
{
"name": "body",
"description": "订阅消息次数详情",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/MessageSubscribeListRequest"
}
}
],
"requestBody": {},
"tags": [
"message"
]
}
},
"v1/mini/message/system": {
"post": {
"summary": "系统消息",
... ... @@ -1661,6 +1719,52 @@
]
}
},
"v1/mini/wechat/bind": {
"post": {
"summary": "绑定微信",
"operationId": "miniWechatBind",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/MiniWechatBindResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/MiniWechatBindRequest"
}
}
],
"requestBody": {},
"tags": [
"user"
]
}
},
"v1/mini/wechat/info": {
"get": {
"summary": "检测是否绑定微信",
"operationId": "miniWechatInfo",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/MiniWechatInfoResponse"
}
}
},
"requestBody": {},
"tags": [
"user"
]
}
},
"v1/system/account": {
"post": {
"summary": "系统新增账号",
... ... @@ -2623,6 +2727,89 @@
]
}
},
"v1/system/article_security/audit": {
"post": {
"summary": "内容安全-审核",
"operationId": "articleSecurityAudit",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ArticleSecurityAuditResponse"
}
}
},
"parameters": [
{
"name": "body",
"description": " ArticleSecuritySaveRequest struct{, ArticleSecurity ArticleSecurityItem `json:\"article_security\"`, }, ArticleSecuritySaveResponse struct{},, ArticleSecurityDeleteRequest struct{, Id int64 `path:\"id\"`, }, ArticleSecurityDeleteResponse struct{},, ArticleSecurityUpdateRequest struct{, Id int64 `path:\"id\"`, ArticleSecurity ArticleSecurityItem `json:\"article_security\"`, }, ArticleSecurityUpdateResponse struct{}",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/ArticleSecurityAuditRequest"
}
}
],
"requestBody": {},
"tags": [
"secuirty"
]
}
},
"v1/system/article_security/search": {
"post": {
"summary": "内容安全-搜索",
"operationId": "articleSecuritySearch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ArticleSecuritySearchResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/ArticleSecuritySearchRequest"
}
}
],
"requestBody": {},
"tags": [
"secuirty"
]
}
},
"v1/system/article_security/{id}": {
"get": {
"summary": "详情",
"operationId": "articleSecurityGet",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ArticleSecurityGetResponse"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"requestBody": {},
"tags": [
"secuirty"
]
}
},
"v1/system/article_tag": {
"post": {
"summary": "后台创建文章标签",
... ... @@ -3765,6 +3952,16 @@
"format": "int64"
},
"description": "谁可查看"
},
"isDel": {
"type": "integer",
"format": "int32",
"description": "是否删除 1-删除 0-否"
},
"deletedType": {
"type": "integer",
"format": "int32",
"description": "类型 1-运营删除 2-用户删除"
}
},
"title": "ArticleSearchMe",
... ... @@ -3778,7 +3975,9 @@
"countRead",
"show",
"targetUser",
"whoRead"
"whoRead",
"isDel",
"deletedType"
]
},
"ArticleSection": {
... ... @@ -3812,6 +4011,199 @@
"totalComment"
]
},
"ArticleSecurityAuditRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": "id"
},
"status": {
"type": "integer",
"format": "int32",
"description": " 1:成功 0:失败"
}
},
"title": "ArticleSecurityAuditRequest",
"required": [
"id",
"status"
]
},
"ArticleSecurityAuditResponse": {
"type": "object",
"title": "ArticleSecurityAuditResponse"
},
"ArticleSecurityGetRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
},
"title": "ArticleSecurityGetRequest",
"required": [
"id"
]
},
"ArticleSecurityGetResponse": {
"type": "object",
"properties": {
"item": {
"$ref": "#/definitions/ArticleSecurityItem"
}
},
"title": "ArticleSecurityGetResponse",
"required": [
"item"
]
},
"ArticleSecurityItem": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": " 唯一标识"
},
"contentKeyWords": {
"type": "string",
"description": " 内容关键字"
},
"content": {
"$ref": "#/definitions/ContentDetailItem",
"description": " 内容详情"
},
"label": {
"type": "string",
"description": " 风控标签"
},
"prob": {
"type": "integer",
"format": "int32",
"description": " 分值"
},
"suggest": {
"type": "string",
"description": " 建议 通过、风险、人工审核"
},
"author": {
"type": "string",
"description": " 发布人"
},
"releaseAt": {
"type": "string",
"description": " 发布时间"
},
"reviewStatus": {
"type": "integer",
"format": "int32",
"description": " 审核结果 1:待审核 2:通过 3:拒绝"
},
"reviewer": {
"type": "string",
"description": " 审核人"
},
"reviewAt": {
"type": "integer",
"format": "int64",
"description": " 审核时间(人工处置时间)"
},
"checkList": {
"type": "array",
"items": {
"$ref": "#/definitions/CheckDetailItem"
},
"description": " 检查列表"
}
},
"title": "ArticleSecurityItem",
"required": [
"id",
"contentKeyWords",
"content",
"label",
"prob",
"suggest",
"author",
"releaseAt",
"reviewStatus",
"reviewer",
"reviewAt",
"checkList"
]
},
"ArticleSecuritySearchRequest": {
"type": "object",
"properties": {
"page": {
"type": "integer",
"format": "int32"
},
"size": {
"type": "integer",
"format": "int32"
},
"reviewStatus": {
"type": "integer",
"format": "int32",
"description": " 审核结果 1:待审核 2:通过 3:拒绝"
},
"suggest": {
"type": "string",
"description": " 建议 通过、风险、人工审核"
},
"contentType": {
"type": "integer",
"format": "int32",
"description": " 内容类型 (1:文章 2:评论)"
},
"authorName": {
"type": "string",
"description": " 作者名称"
},
"beginTime": {
"type": "integer",
"format": "int64",
"description": " 开始时间"
},
"endTime": {
"type": "integer",
"format": "int64",
"description": " 结束时间"
}
},
"title": "ArticleSecuritySearchRequest",
"required": [
"suggest",
"contentType",
"authorName",
"beginTime",
"endTime"
]
},
"ArticleSecuritySearchResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/ArticleSecurityItem"
}
},
"total": {
"type": "integer",
"format": "int64"
}
},
"title": "ArticleSecuritySearchResponse",
"required": [
"list",
"total"
]
},
"ArticleTagCount": {
"type": "object",
"properties": {
... ... @@ -3967,12 +4359,18 @@
"label": {
"type": "string",
"description": " 分组名称"
},
"enable": {
"type": "integer",
"format": "int32",
"description": " 启用状态 1:启用"
}
},
"title": "CategoryOptions",
"required": [
"value",
"label"
"label",
"enable"
]
},
"CategoryOptionsRequest": {
... ... @@ -4001,6 +4399,29 @@
"options"
]
},
"CheckDetailItem": {
"type": "object",
"properties": {
"label": {
"type": "string",
"description": " 命中标签"
},
"prob": {
"$ref": "#/definitions/uint",
"description": " 置信度。0-100,越高代表越有可能属于当前返回的标签(label)"
},
"suggest": {
"type": "string",
"description": " 建议"
}
},
"title": "CheckDetailItem",
"required": [
"label",
"prob",
"suggest"
]
},
"CommentAtWho": {
"type": "object",
"properties": {
... ... @@ -4200,6 +4621,31 @@
"type": "object",
"title": "CompanyVisibleSwitchResponse"
},
"ContentDetailItem": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": " 内容ID"
},
"type": {
"type": "integer",
"format": "int32",
"description": " 内容类型 (1:文章 2:评论)"
},
"text": {
"type": "string",
"description": " 内容文本"
}
},
"title": "ContentDetailItem",
"required": [
"id",
"type",
"text"
]
},
"Department": {
"type": "object",
"properties": {
... ... @@ -4229,6 +4675,11 @@
"format": "int64"
},
"description": " 部门下的用户"
},
"totalUser": {
"type": "integer",
"format": "int32",
"description": " 累计用户"
}
},
"title": "Department",
... ... @@ -4237,7 +4688,8 @@
"companyId",
"parentId",
"name",
"userIds"
"userIds",
"totalUser"
]
},
"DepartmentAddRequest": {
... ... @@ -4297,6 +4749,16 @@
"size": {
"type": "integer",
"format": "int32"
},
"includeRootCompany": {
"type": "boolean",
"format": "boolean",
"description": " 包含公司(把公司当作部门作为顶级节点 部门ID:0)"
},
"includeDefaultDepartment": {
"type": "boolean",
"format": "boolean",
"description": " 包含默认分组"
}
},
"title": "DepartmentListRequest",
... ... @@ -4497,6 +4959,89 @@
"size"
]
},
"MessageSubscribeAddRequest": {
"type": "object",
"properties": {
"types": {
"type": "array",
"items": {
"type": "integer",
"format": "int32"
},
"description": " 订阅消息类型"
}
},
"title": "MessageSubscribeAddRequest",
"required": [
"types"
]
},
"MessageSubscribeAddResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/MessageSubscribeItem"
}
}
},
"title": "MessageSubscribeAddResponse",
"required": [
"items"
]
},
"MessageSubscribeItem": {
"type": "object",
"properties": {
"type": {
"type": "integer",
"format": "int32",
"description": " 订阅消息类型"
},
"count": {
"type": "integer",
"format": "int32",
"description": " 订阅次数"
},
"userId": {
"type": "integer",
"format": "int64",
"description": " 用户ID"
},
"companyId": {
"type": "integer",
"format": "int64",
"description": " 公司ID"
}
},
"title": "MessageSubscribeItem",
"required": [
"type",
"count",
"userId",
"companyId"
]
},
"MessageSubscribeListRequest": {
"type": "object",
"title": "MessageSubscribeListRequest"
},
"MessageSubscribeListResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/MessageSubscribeItem"
}
}
},
"title": "MessageSubscribeListResponse",
"required": [
"items"
]
},
"MessageSystemItem": {
"type": "object",
"properties": {
... ... @@ -6975,10 +7520,89 @@
"keywords": {
"type": "string",
"description": " 按关键字搜索(名称)"
},
"departmentId": {
"$ref": "#/definitions/int64",
"description": " 按部门过滤"
}
},
"title": "MiniUsersListRequest"
},
"MiniWechatBindRequest": {
"type": "object",
"properties": {
"wechatAuthcode": {
"type": "string",
"description": " 微信登录 授权码"
},
"wechatEncryptedData": {
"type": "string",
"description": " 微信登录 加密数据"
},
"wechatIV": {
"type": "string",
"description": " 微信登录 加密算法初始向量"
}
},
"title": "MiniWechatBindRequest",
"required": [
"wechatAuthcode",
"wechatEncryptedData",
"wechatIV"
]
},
"MiniWechatBindResponse": {
"type": "object",
"properties": {
"bind": {
"type": "boolean",
"format": "boolean",
"description": " 绑定结果 true-已绑定 false-未绑定"
},
"openId": {
"type": "string",
"description": " 绑定的微信openId"
},
"phone": {
"type": "string",
"description": " 绑定手机号"
}
},
"title": "MiniWechatBindResponse",
"required": [
"bind",
"openId",
"phone"
]
},
"MiniWechatInfoRequest": {
"type": "object",
"title": "MiniWechatInfoRequest"
},
"MiniWechatInfoResponse": {
"type": "object",
"properties": {
"bind": {
"type": "boolean",
"format": "boolean",
"description": " 绑定结果 true-已绑定 false-未绑定"
},
"openId": {
"type": "string",
"description": " 绑定的微信openId"
},
"phone": {
"type": "string",
"description": " 绑定手机号"
}
},
"title": "MiniWechatInfoResponse",
"required": [
"bind",
"openId",
"phone"
]
},
"MyBeLikedItem": {
"type": "object",
"properties": {
... ... @@ -7828,11 +8452,16 @@
"type": "integer",
"format": "int64",
"description": "id"
},
"AccessToken": {
"type": "string",
"description": " 授权token"
}
},
"title": "SystemArticleDeleteRequest",
"required": [
"id"
"id",
"x-mmm-accesstoken"
]
},
"SystemArticleDeleteResponse": {
... ... @@ -7866,11 +8495,16 @@
"type": "integer",
"format": "int64",
"description": "ID"
},
"AccessToken": {
"type": "string",
"description": " 授权token"
}
},
"title": "SystemArticleDeletedRestoreRequest",
"required": [
"id"
"id",
"x-mmm-accesstoken"
]
},
"SystemArticleDeletedRestoreResponse": {
... ... @@ -10180,6 +10814,10 @@
},
"code": {
"type": "string"
},
"companyVisible": {
"type": "boolean",
"format": "boolean"
}
},
"title": "SystemUserInfoResponse",
... ... @@ -10189,7 +10827,8 @@
"avatar",
"companyId",
"companyName",
"code"
"code",
"companyVisible"
]
},
"SystemUserSearchRequest": {
... ... @@ -10221,8 +10860,7 @@
"description": " 启用状态 1:启用 2:禁用"
},
"departmentId": {
"type": "integer",
"format": "int64",
"$ref": "#/definitions/int64",
"description": " 所属部门"
}
},
... ...
@server(
prefix: v1/system
group: secuirty
middleware: LoginStatusCheck,LogRequest
jwt: SystemAuth
)
service Core {
@doc "内容安全-搜索"
@handler articleSecuritySearch
post /article_security/search (ArticleSecuritySearchRequest) returns (ArticleSecuritySearchResponse)
@doc "详情"
@handler articleSecurityGet
get /article_security/:id (ArticleSecurityGetRequest) returns (ArticleSecurityGetResponse)
@doc "内容安全-审核"
@handler articleSecurityAudit
post /article_security/audit (ArticleSecurityAuditRequest) returns (ArticleSecurityAuditResponse)
}
type (
ArticleSecurityGetRequest {
Id int64 `path:"id"`
}
ArticleSecurityGetResponse struct{
ArticleSecurity ArticleSecurityItem `json:"item"`
}
// ArticleSecuritySaveRequest struct{
// ArticleSecurity ArticleSecurityItem `json:"article_security"`
// }
// ArticleSecuritySaveResponse struct{}
//
// ArticleSecurityDeleteRequest struct{
// Id int64 `path:"id"`
// }
// ArticleSecurityDeleteResponse struct{}
//
// ArticleSecurityUpdateRequest struct{
// Id int64 `path:"id"`
// ArticleSecurity ArticleSecurityItem `json:"article_security"`
// }
// ArticleSecurityUpdateResponse struct{}
ArticleSecurityAuditRequest struct{
Id int64 `json:"id"` //id
Status int `json:"status"` // 1:成功 0:失败
}
ArticleSecurityAuditResponse struct{
}
ArticleSecuritySearchRequest struct{
Page int `json:"page,optional"`
Size int `json:"size,optional"`
ReviewStatus int `json:"reviewStatus,optional"` // 审核结果 1:待审核 2:通过 3:拒绝
Suggest string `json:"suggest"` // 建议 通过、风险、人工审核
ContentType int `json:"contentType"` // 内容类型 (1:文章 2:评论)
AuthorName string `json:"authorName"` // 作者名称
BeginTime int64 `json:"beginTime"` // 开始时间
EndTime int64 `json:"endTime"` // 结束时间
}
ArticleSecuritySearchResponse{
List []ArticleSecurityItem `json:"list"`
Total int64 `json:"total"`
}
ArticleSecurityItem struct{
Id int64 `json:"id"` // 唯一标识
ContentKeyWords string `json:"contentKeyWords"` // 内容关键字
Content ContentDetailItem `json:"content"` // 内容详情
Label string `json:"label"` // 风控标签
Prob int `json:"prob"` // 分值
Suggest string `json:"suggest"` // 建议 通过、风险、人工审核
Author string `json:"author"` // 发布人
ReleaseAt int64 `json:"releaseAt"` // 发布时间
ReviewStatus int `json:"reviewStatus"` // 审核结果 1:待审核 2:通过 3:拒绝
Reviewer string `json:"reviewer"` // 审核人
ReviewAt int64 `json:"reviewAt"` // 审核时间(人工处置时间)
CheckList []CheckDetailItem `json:"checkList"` // 检查列表
}
CheckDetailItem struct{
Label string `json:"label"` // 命中标签
Prob uint `json:"prob"` // 置信度。0-100,越高代表越有可能属于当前返回的标签(label)
Suggest string `json:"suggest"` // 建议
}
ContentDetailItem struct{
Id int64 `json:"id"` // 内容ID
Type int `json:"type"` // 内容类型 (1:文章 2:评论)
Text string `json:"text"` // 内容文本
}
)
\ No newline at end of file
... ...
... ... @@ -7,6 +7,7 @@ Timeout: 30000
# CertFile: ./key/fjmaimaimai.com_bundle.crt
# KeyFile: ./key/fjmaimaimai.com.key
LogRequest: true # 记录详细请求日志
ContentSecurityCheck: true # 内容安全检查(调用微信接口)
Log:
Mode: file
... ...
... ... @@ -17,6 +17,7 @@ type Config struct {
ApiAuth ApiService
DebugSmsCode string `json:",optional,default=999512"`
LogRequest bool `json:",optional,default=true"`
ContentSecurityCheck bool `json:",optional,default=false"`
}
type ApiService struct {
... ...
... ... @@ -11,6 +11,7 @@ import (
department "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/handler/department"
message "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/handler/message"
role "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/handler/role"
secuirty "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/handler/secuirty"
tags "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/handler/tags"
user "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/handler/user"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
... ... @@ -809,4 +810,29 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
},
rest.WithPrefix("/v1/system"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.LoginStatusCheck, serverCtx.LogRequest},
[]rest.Route{
{
Method: http.MethodPost,
Path: "/article_security/search",
Handler: secuirty.ArticleSecuritySearchHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/article_security/:id",
Handler: secuirty.ArticleSecurityGetHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/article_security/audit",
Handler: secuirty.ArticleSecurityAuditHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.SystemAuth.AccessSecret),
rest.WithPrefix("/v1/system"),
)
}
... ...
package secuirty
import (
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/secuirty"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
)
func ArticleSecurityAuditHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ArticleSecurityAuditRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := secuirty.NewArticleSecurityAuditLogic(r.Context(), svcCtx)
resp, err := l.ArticleSecurityAudit(&req)
result.HttpResult(r, w, resp, err)
}
}
... ...
package secuirty
import (
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/secuirty"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
)
func ArticleSecurityGetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ArticleSecurityGetRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := secuirty.NewArticleSecurityGetLogic(r.Context(), svcCtx)
resp, err := l.ArticleSecurityGet(&req)
result.HttpResult(r, w, resp, err)
}
}
... ...
package secuirty
import (
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/secuirty"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
)
func ArticleSecuritySearchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ArticleSecuritySearchRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := secuirty.NewArticleSecuritySearchLogic(r.Context(), svcCtx)
resp, err := l.ArticleSecuritySearch(&req)
result.HttpResult(r, w, resp, err)
}
}
... ...
... ... @@ -2,6 +2,7 @@ package article
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/core"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/message"
"strconv"
"strings"
... ... @@ -205,6 +206,11 @@ func (l *MiniCreateArticleLogic) MiniCreateArticle(req *types.MiniArticleCreateR
if err != nil {
return xerr.NewErrMsgErr("创建文章失败", err)
}
// 内容安全检查
if err = core.ContentSecurityCheck(l.ctx, l.svcCtx, c, author, core.NewContentFromArticle(newArticle, sectionList)); err != nil {
return err
}
return nil
}, true)
if err != nil {
... ...
... ... @@ -2,6 +2,7 @@ package comment
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/core"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/message"
... ... @@ -211,6 +212,11 @@ func (l *MiniCreateArticleCommentLogic) MiniCreateArticleComment(req *types.Mini
if err != nil {
return err
}
// 内容安全检查
if err = core.ContentSecurityCheck(l.ctx, l.svcCtx, conn, fromUser, core.NewContentFromComment(&newComment)); err != nil {
return err
}
return nil
}, true)
... ...
package core
import (
"bytes"
"context"
"fmt"
"github.com/silenceper/wechat/v2/miniprogram/security"
"github.com/zeromicro/go-zero/core/executors"
"github.com/zeromicro/go-zero/core/logx"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
"time"
)
func ContentSecurityCheck(ctx context.Context, svcCtx *svc.ServiceContext, conn transaction.Conn, toUser *domain.User, content ContentBody) error {
if !svcCtx.Config.ContentSecurityCheck {
return nil
}
var (
scene security.MsgScene
)
if content.Type == 1 {
scene = security.MsgSceneSocialLog
} else {
scene = security.MsgSceneComment
}
var (
resp domain.MsgCheckDetail
userWechat *domain.UserWechat
)
if userWechat, _ = svcCtx.UserWechatRepository.FindOneByPhone(ctx, conn, toUser.Phone); userWechat == nil {
logx.Debug(fmt.Sprintf("用户%s(%s)未绑定微信,无法进行内容检查", toUser.Name, toUser.Phone))
return nil
}
respTmp, err := svcCtx.MiniProgram.GetSecurity().MsgCheck(&security.MsgCheckRequest{
OpenID: userWechat.OpenId,
Scene: scene,
Content: content.Content,
})
if err != nil {
logx.Error(err)
return nil
}
resp = domain.MsgCheckDetail(respTmp)
var (
keyWords = make([]string, 0)
prob int
)
for i := range resp.Detail {
item := resp.Detail[i]
if prob == 0 {
prob = int(item.Prob)
}
if item.Keyword == "" {
continue
}
keyWords = append(keyWords, item.Keyword)
}
dm := &domain.ArticleSecurity{
CompanyId: toUser.CompanyId,
ContentKeyWords: keyWords,
ContentType: content.Type,
ContentId: content.Id,
AuthorId: content.AuthorId,
AuthorName: toUser.Name,
Reviewer: 0,
ReviewStatus: domain.ReviewStatusWait,
Label: resp.Result.Label.String(),
Prob: prob,
Suggest: string(resp.Result.Suggest),
Detail: resp,
AutoReviewAt: time.Now().Unix(),
AutoReviewErrorCode: fmt.Sprintf("%d", resp.ErrCode),
}
if resp.Result.Suggest == security.CheckSuggestPass {
dm.ReviewStatus = domain.ReviewStatusPass
}
// 延迟任务(认定为风险的、人工审核),帖子或评论先隐藏,状态改为非法
if resp.Result.Suggest == security.CheckSuggestRisky || resp.Result.Suggest == security.CheckSuggestReview {
executors.NewDelayExecutor(func() {
HandlerSecurityContent(ctx, svcCtx, svcCtx.DefaultDBConn(), content, dm.ReviewStatus)
}, time.Second*5).Trigger()
}
if dm, err = svcCtx.ArticleSecurityRepository.Insert(ctx, conn, dm); err != nil {
logx.Error(err)
return nil
}
return nil
}
func HandlerSecurityContent(ctx context.Context, svcCtx *svc.ServiceContext, conn transaction.Conn, c ContentBody, status int) error {
if !svcCtx.Config.ContentSecurityCheck {
return nil
}
var (
article *domain.Article
comment *domain.ArticleComment
err error
show = int(domain.ArticleShowIllegal)
)
if status == domain.ReviewStatusPass {
show = int(domain.ArticleShowEnable)
}
mnl := NewMessageNoticeLogic(ctx, svcCtx)
if c.Type == domain.TypeArticle {
if article, err = svcCtx.ArticleRepository.FindOne(ctx, conn, c.Id); err != nil {
return fmt.Errorf("文章不存在")
}
article.Show = domain.ArticleShow(show)
if _, err = svcCtx.ArticleRepository.UpdateWithVersion(ctx, conn, article); err != nil {
return err
}
if show == int(domain.ArticleShowIllegal) {
mnl.ArticleIllegal(conn, article.CompanyId, article.AuthorId, time.Unix(article.CreatedAt, 0).Format("2006-01-02 15:04"), article.Title)
}
} else if c.Type == domain.TypeComment {
if comment, err = svcCtx.ArticleCommentRepository.FindOne(ctx, conn, c.Id); err != nil {
return fmt.Errorf("评论不存在")
}
comment.Show = domain.CommentShow(show)
if _, err = svcCtx.ArticleCommentRepository.UpdateWithVersion(ctx, conn, comment); err != nil {
return err
}
if show == int(domain.CommentShowIllegal) {
mnl.ArticleIllegal(conn, comment.CompanyId, comment.FromUserId, time.Unix(comment.CreatedAt, 0).Format("2006-01-02 15:04"), comment.Content)
}
}
return nil
}
type ContentBody struct {
Id int64
Type int
Content string
AuthorId int64
Summary string
}
func NewContentFromComment(c *domain.ArticleComment) ContentBody {
return ContentBody{
Id: c.Id,
Type: domain.TypeComment,
Content: c.Content,
AuthorId: c.FromUserId,
Summary: c.Content,
}
}
func NewContentFromArticle(c *domain.Article, sections []*domain.ArticleSection) ContentBody {
content := bytes.NewBuffer(nil)
for _, sec := range sections {
content.WriteString(sec.Content)
}
return ContentBody{
Id: c.Id,
Type: domain.TypeArticle,
Content: content.String(),
AuthorId: c.AuthorId,
Summary: c.Summary,
}
}
... ...
package core
import (
"context"
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
)
type MessageNotice struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewMessageNoticeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MessageNotice {
return &MessageNotice{
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *MessageNotice) ArticleIllegal(conn transaction.Conn, companyId, at int64, createdTime, title string) (err error) {
return l.createMessage(conn, companyId, at, domain.MsgTypeIllegal, "文本内容违规", fmt.Sprintf("你于%v发布的帖子[%v]含有违规信息,未通过审核,已被禁止发布。请自觉遵守相关规定,若有疑问,请咨询运营管理员了解详情。", createdTime, title))
}
// CommentIllegal 评论违规
func (l *MessageNotice) CommentIllegal(conn transaction.Conn, at int64, companyId int64, createdTime, title string) (err error) {
return l.createMessage(conn, companyId, at, domain.MsgTypeIllegal, "文本内容违规", fmt.Sprintf("你于%v发布的评论[%v]含有违规信息,未通过审核,已被禁止发布。请自觉遵守相关规定,若有疑问,请咨询运营管理员了解详情。", createdTime, title))
}
func (l *MessageNotice) createMessage(conn transaction.Conn, companyId, at int64, msgType domain.MsgSystemType, title string, content string) (err error) {
var msg = &domain.MessageSystem{
Type: msgType,
CompanyId: companyId,
RecipientId: at,
Title: title,
Content: content,
}
msg, err = l.svcCtx.MessageSystemRepository.Insert(l.ctx, conn, msg)
return err
}
... ...
... ... @@ -54,8 +54,8 @@ func (l *MiniSubscribeLogic) getOpenId(conn transaction.Conn, userId int64) (str
return userWechat.OpenId, nil
}
// saveMessage 保存订阅消息
func (l *MiniSubscribeLogic) saveMessage(conn transaction.Conn, companyId, userId int64, mType int, msg *subscribe.Message, sendErr error) error {
// sendAndDecrease 保存并扣减订阅消息
func (l *MiniSubscribeLogic) sendAndDecrease(conn transaction.Conn, companyId, userId int64, mType int, msg *subscribe.Message) error {
templateData := make(map[string]interface{})
_ = copier.Copy(&templateData, msg.Data)
subscribeMessage := &domain.MessageSubscribe{
... ... @@ -66,14 +66,34 @@ func (l *MiniSubscribeLogic) saveMessage(conn transaction.Conn, companyId, userI
TemplateId: msg.TemplateID,
TemplateData: templateData,
}
//获取订阅次数
userSubscribe, err := l.svcCtx.UserSubscribeRepository.FindOneByType(l.ctx, conn, companyId, userId, mType)
if err != nil || userSubscribe.Count <= 0 {
subscribeMessage.Result = "fail"
subscribeMessage.Error = "订阅次数已用完"
} else {
//扣减订阅次数
userSubscribe.Count = userSubscribe.Count - 1
_, err = l.svcCtx.UserSubscribeRepository.Update(l.ctx, conn, userSubscribe)
if err != nil {
return err
}
//发送订阅消息
subCtx := l.getSubScribe()
sendErr := subCtx.Send(msg)
if sendErr != nil {
subscribeMessage.Result = "fail"
subscribeMessage.Error = sendErr.Error()
} else {
subscribeMessage.Result = "ok"
}
_, err := l.svcCtx.MessageSubscribeRepository.Insert(l.ctx, conn, subscribeMessage)
}
//保存订阅结果
_, err = l.svcCtx.MessageSubscribeRepository.Insert(l.ctx, conn, subscribeMessage)
if err != nil {
return err
}
return nil
}
func (l *MiniSubscribeLogic) messageSubscribe(companyId, userId int64, mType int) *domain.MessageSubscribe {
... ... @@ -109,7 +129,6 @@ func (l *MiniSubscribeLogic) getReplyCommentUserInfo(conn transaction.Conn, comp
// @param article 文章
// @param comment 评论
func (l *MiniSubscribeLogic) ReplyComment(conn transaction.Conn, article *domain.Article, comment *domain.ArticleComment) error {
subCtx := l.getSubScribe()
//评论用户+职位 例: 张三-董事办
fromUserName, err := l.getReplyCommentUserInfo(conn, comment.CompanyId, comment.FromUserId)
if err != nil {
... ... @@ -124,7 +143,7 @@ func (l *MiniSubscribeLogic) ReplyComment(conn transaction.Conn, article *domain
//评论内容
"thing2": &subscribe.DataItem{Value: comment.GetSubscribeMessageContent()},
//评论时间
"thing3": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
"time3": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
//评论用户
"thing5": &subscribe.DataItem{Value: fromUserName},
//备注
... ... @@ -139,10 +158,10 @@ func (l *MiniSubscribeLogic) ReplyComment(conn transaction.Conn, article *domain
msg.ToUser = openId
msg.Page = fmt.Sprintf("/pages/detail/more-comment?id=%v", article.Id) //跳转页面 帖子评论聚合页
//备注
msg.Data["thing9"] = &subscribe.DataItem{Value: fmt.Sprintf("您的帖子最近已有%v人评论,点击查看详情", article.CountComment)}
userCount, err := l.svcCtx.ArticleCommentRepository.CommentUserCount(l.ctx, conn, comment.CompanyId, comment.ArticleId)
msg.Data["thing9"] = &subscribe.DataItem{Value: fmt.Sprintf("您的帖子最近已有%v人评论,点击查看详情", userCount)}
//发送微信订阅消息
err = subCtx.Send(msg)
err = l.saveMessage(conn, comment.CompanyId, article.AuthorId, domain.SubscribeTypeReplyComment, msg, err)
err = l.sendAndDecrease(conn, comment.CompanyId, article.AuthorId, domain.SubscribeTypeReplyComment, msg)
if err != nil {
return xerr.NewErrMsgErr("评论失败", err)
}
... ... @@ -154,12 +173,11 @@ func (l *MiniSubscribeLogic) ReplyComment(conn transaction.Conn, article *domain
msg.ToUser = toOpenId
msg.Page = fmt.Sprintf("/pages/detail/reply-comment?id=%v&commentId=%v", article.Id, comment.Pid) //跳转页面评论聚合页
//备注
parent, err := l.svcCtx.ArticleCommentRepository.FindOne(l.ctx, conn, comment.Pid)
if err == nil && parent.Id > 0 {
msg.Data["thing9"] = &subscribe.DataItem{Value: fmt.Sprintf("您的评论最近已有%v人回复,点击查看详情", parent.CountReply)}
replyCount, err := l.svcCtx.ArticleCommentRepository.ReplyUserCount(l.ctx, conn, comment.CompanyId, comment.Pid)
if err == nil {
msg.Data["thing9"] = &subscribe.DataItem{Value: fmt.Sprintf("您的评论最近已有%v人回复,点击查看详情", replyCount)}
//发送微信订阅消息
err = subCtx.Send(msg)
err = l.saveMessage(conn, comment.CompanyId, comment.ToUserId, domain.SubscribeTypeReplyComment, msg, err)
err = l.sendAndDecrease(conn, comment.CompanyId, comment.ToUserId, domain.SubscribeTypeReplyComment, msg)
if err != nil {
return xerr.NewErrMsgErr("评论失败", err)
}
... ... @@ -179,8 +197,7 @@ func (l *MiniSubscribeLogic) ReplyComment(conn transaction.Conn, article *domain
//备注
msg.Data["thing9"] = &subscribe.DataItem{Value: fmt.Sprintf("%v在评论中提到了你", comment.FromUser.Name)}
//发送微信订阅消息
err = subCtx.Send(msg)
err = l.saveMessage(conn, comment.CompanyId, at.Id, domain.SubscribeTypeReplyComment, msg, err)
err = l.sendAndDecrease(conn, comment.CompanyId, at.Id, domain.SubscribeTypeReplyComment, msg)
if err != nil {
return xerr.NewErrMsgErr("评论失败", err)
}
... ... @@ -191,11 +208,14 @@ func (l *MiniSubscribeLogic) ReplyComment(conn transaction.Conn, article *domain
// LikeArticle 帖子点赞订阅消息
func (l *MiniSubscribeLogic) LikeArticle(conn transaction.Conn, article *domain.Article, userInfo *domain.User) error {
subCtx := l.getSubScribe()
openId, err := l.getOpenId(conn, article.AuthorId)
if err != nil || openId == "" {
return nil
}
newArticle, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, article.Id)
if err != nil {
return xerr.NewErrMsgErr("未获取到帖子信息", err)
}
msg := &subscribe.Message{
ToUser: openId,
TemplateID: domain.SubscribeTemplateLike,
... ... @@ -204,18 +224,17 @@ func (l *MiniSubscribeLogic) LikeArticle(conn transaction.Conn, article *domain.
//点赞用户
"name1": &subscribe.DataItem{Value: userInfo.Name},
//点赞时间
"data2": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
"date2": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
//动态内容
"thing8": &subscribe.DataItem{Value: article.GetSubscribeMessageTitle()},
//被赞次数
"number4": &subscribe.DataItem{Value: article.CountLove},
"number4": &subscribe.DataItem{Value: newArticle.CountLove},
//温馨提示
"thing5": &subscribe.DataItem{Value: "这条内容很受欢迎哦,快来看看吧"},
},
MiniprogramState: l.svcCtx.Config.Wechat.QrcodeEnv,
}
err = subCtx.Send(msg)
err = l.saveMessage(conn, article.CompanyId, article.AuthorId, domain.SubscribeTypeLike, msg, err)
err = l.sendAndDecrease(conn, article.CompanyId, article.AuthorId, domain.SubscribeTypeLike, msg)
if err != nil {
return xerr.NewErrMsgErr("点赞失败", err)
}
... ... @@ -224,11 +243,15 @@ func (l *MiniSubscribeLogic) LikeArticle(conn transaction.Conn, article *domain.
// LikeComment 点赞评论订阅消息
func (l *MiniSubscribeLogic) LikeComment(conn transaction.Conn, comment *domain.ArticleComment, userInfo *domain.User) error {
subCtx := l.getSubScribe()
openId, err := l.getOpenId(conn, comment.FromUserId)
if err != nil || openId == "" {
return nil
}
//获取被赞次数
newComment, err := l.svcCtx.ArticleCommentRepository.FindOne(l.ctx, conn, comment.Id)
if err != nil {
return xerr.NewErrMsgErr("未获取到评论信息", err)
}
msg := &subscribe.Message{
ToUser: openId,
TemplateID: domain.SubscribeTemplateLike,
... ... @@ -237,18 +260,17 @@ func (l *MiniSubscribeLogic) LikeComment(conn transaction.Conn, comment *domain.
//点赞用户
"name1": &subscribe.DataItem{Value: userInfo.Name},
//点赞时间
"data2": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
"date2": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
//动态内容
"thing8": &subscribe.DataItem{Value: comment.GetSubscribeMessageContent()},
//被赞次数
"number4": &subscribe.DataItem{Value: comment.CountUserLove},
"number4": &subscribe.DataItem{Value: newComment.CountUserLove},
//温馨提示
"thing5": &subscribe.DataItem{Value: "这条内容很受欢迎哦,快来看看吧"},
},
MiniprogramState: l.svcCtx.Config.Wechat.QrcodeEnv,
}
err = subCtx.Send(msg)
err = l.saveMessage(conn, comment.CompanyId, comment.FromUserId, domain.SubscribeTypeLike, msg, err)
err = l.sendAndDecrease(conn, comment.CompanyId, comment.FromUserId, domain.SubscribeTypeLike, msg)
if err != nil {
return xerr.NewErrMsgErr("点赞失败", err)
}
... ... @@ -257,7 +279,6 @@ func (l *MiniSubscribeLogic) LikeComment(conn transaction.Conn, comment *domain.
// FollowArticle 发帖关注更新提醒
func (l *MiniSubscribeLogic) FollowArticle(conn transaction.Conn, article *domain.Article) error {
subCtx := l.getSubScribe()
//获取关注帖子作者的人员
_, userInfo, err := l.svcCtx.UserFollowRepository.Find(l.ctx, conn, domain.NewQueryOptions().WithKV("toUserIds", []int64{article.AuthorId}))
if err == nil && len(userInfo) > 0 {
... ... @@ -278,14 +299,13 @@ func (l *MiniSubscribeLogic) FollowArticle(conn transaction.Conn, article *domai
//内容摘要
"thing5": &subscribe.DataItem{Value: ""},
//发布时间
"thing6": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
"time6": &subscribe.DataItem{Value: time.Now().Format("2006-01-02 15:04:05")},
//温馨提示
"thing3": &subscribe.DataItem{Value: "你关注的人发布了新的帖子"},
},
MiniprogramState: l.svcCtx.Config.Wechat.QrcodeEnv,
}
err = subCtx.Send(msg)
err = l.saveMessage(conn, article.CompanyId, item.FromUserId, domain.SubscribeTypeFollow, msg, err)
err = l.sendAndDecrease(conn, article.CompanyId, item.FromUserId, domain.SubscribeTypeFollow, msg)
if err != nil {
return xerr.NewErrMsgErr("保存订阅消息失败", err)
}
... ...
... ... @@ -62,6 +62,11 @@ func (l *MiniSystemLogic) ArticleDeleted(conn transaction.Conn, companyId, at in
return l.createMessage(conn, companyId, at, domain.MsgTypeDeleted, "帖子已删除", fmt.Sprintf("你于%v发布的帖子[%v]已被删除,如有疑问,请联系运营管理员了解详情。", createdTime, title))
}
// ArticleIllegal 帖子违规
func (l *MiniSystemLogic) ArticleIllegal(conn transaction.Conn, companyId, at int64, createdTime, title string) (err error) {
return l.createMessage(conn, companyId, at, domain.MsgTypeDeleted, "文本内容违规", fmt.Sprintf("你于%v发布的帖子[%v]含有违规信息,未通过审核,已被禁止发布。请自觉遵守相关规定,若有疑问,请咨询运营管理员了解详情。", createdTime, title))
}
//// ArticleAuth 文章权限变更
//func (l *MiniSystemLogic) ArticleAuth(conn transaction.Conn, companyId, at int64, item string) (err error) {
// return l.createMessage(conn, companyId, at, domain.MsgTypeAbnormal, "权限变更", fmt.Sprintf("您的帖子[%s]可见权限已添加,如有疑问,请联系运营管理员了解详情。", item))
... ... @@ -92,6 +97,11 @@ func (l *MiniSystemLogic) AbnormalCommentHidden(conn transaction.Conn, companyId
return l.createMessage(conn, companyId, at, domain.MsgTypeAbnormal, "评论被隐藏", fmt.Sprintf("您的评论[%s]已被隐藏,如有疑问,请联系运营管理员了解详情。", item))
}
// CommentIllegal 评论违规
func (l *MiniSystemLogic) CommentIllegal(conn transaction.Conn, at int64, companyId int64, createdTime, title string) (err error) {
return l.createMessage(conn, companyId, at, domain.MsgTypeIllegal, "文本内容违规", fmt.Sprintf("你于%v发布的评论[%v]含有违规信息,未通过审核,已被禁止发布。请自觉遵守相关规定,若有疑问,请咨询运营管理员了解详情。", createdTime, title))
}
func (l *MiniSystemLogic) createMessage(conn transaction.Conn, companyId, at int64, msgType domain.MsgSystemType, title string, content string) (err error) {
var msg = &domain.MessageSystem{
Type: msgType,
... ...
package secuirty
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/core"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
"time"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ArticleSecurityAuditLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewArticleSecurityAuditLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ArticleSecurityAuditLogic {
return &ArticleSecurityAuditLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ArticleSecurityAuditLogic) ArticleSecurityAudit(req *types.ArticleSecurityAuditRequest) (resp *types.ArticleSecurityAuditResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ArticleSecurity
)
if dm, err = l.svcCtx.ArticleSecurityRepository.FindOne(l.ctx, conn, req.Id); err != nil {
return nil, xerr.NewErrMsgErr("不存在", err)
}
// 不可编辑判断
//if dm.ReviewStatus != domain.ReviewStatusWait {
// return nil, xerr.NewErrMsgErr("内容已审核", err)
//}
// 赋值
if req.Status == 1 {
dm.ReviewStatus = domain.ReviewStatusPass
} else {
dm.ReviewStatus = domain.ReviewStatusFail
}
dm.ReviewAt = time.Now().Unix()
// 更新
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
dm, err = l.svcCtx.ArticleSecurityRepository.UpdateWithVersion(l.ctx, conn, dm)
if err != nil {
return err
}
if err = core.HandlerSecurityContent(l.ctx, l.svcCtx, conn, core.ContentBody{Id: dm.ContentId, Type: dm.ContentType}, dm.ReviewStatus); err != nil {
return err
}
// 更新文章/评论可见
return err
}, true); err != nil {
return nil, xerr.NewErrMsg("更新失败")
}
resp = &types.ArticleSecurityAuditResponse{}
return
}
... ...
package secuirty
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ArticleSecurityGetLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewArticleSecurityGetLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ArticleSecurityGetLogic {
return &ArticleSecurityGetLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ArticleSecurityGetLogic) ArticleSecurityGet(req *types.ArticleSecurityGetRequest) (resp *types.ArticleSecurityGetResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ArticleSecurity
reviewer *domain.User
article *domain.Article
comment *domain.ArticleComment
)
// 货号唯一
if dm, err = l.svcCtx.ArticleSecurityRepository.FindOne(l.ctx, conn, req.Id); err != nil {
return nil, xerr.NewErrMsgErr("不存在", err)
}
if dm.Reviewer > 0 {
if reviewer, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, dm.Reviewer); err != nil {
return nil, err
}
}
resp = &types.ArticleSecurityGetResponse{
ArticleSecurity: NewTypesArticleSecurity(dm, reviewer),
}
if dm.ContentType == domain.TypeArticle {
if article, _ = l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, dm.ContentId); article != nil {
resp.ArticleSecurity.Content.Text = article.Summary
}
} else if dm.ContentType == domain.TypeComment {
if comment, _ = l.svcCtx.ArticleCommentRepository.FindOne(l.ctx, conn, dm.ContentId); comment != nil {
resp.ArticleSecurity.Content.Text = comment.Content
}
}
return
}
... ...
package secuirty
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
"strings"
"github.com/zeromicro/go-zero/core/logx"
)
type ArticleSecuritySearchLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewArticleSecuritySearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ArticleSecuritySearchLogic {
return &ArticleSecuritySearchLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ArticleSecuritySearchLogic) ArticleSecuritySearch(req *types.ArticleSecuritySearchRequest) (resp *types.ArticleSecuritySearchResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dms []*domain.ArticleSecurity
total int64
userToken = contextdata.GetUserTokenFromCtx(l.ctx)
)
queryOptions := domain.IndexCompanyId(userToken.CompanyId)().WithOffsetLimit(req.Page, req.Size).
WithKV("reviewStatus", req.ReviewStatus).
WithKV("suggest", req.Suggest).
WithKV("contentType", req.ContentType).
WithKV("authorName", req.AuthorName).
WithKV("beginTime", req.BeginTime).
WithKV("endTime", req.EndTime)
total, dms, err = l.svcCtx.ArticleSecurityRepository.Find(l.ctx, conn, queryOptions)
list := make([]types.ArticleSecurityItem, 0)
for i := range dms {
list = append(list, NewTypesArticleSecurity(dms[i], nil))
}
resp = &types.ArticleSecuritySearchResponse{
List: list,
Total: total,
}
return
}
func NewDomainArticleSecurity(item types.ArticleSecurityItem) *domain.ArticleSecurity {
return &domain.ArticleSecurity{}
}
func NewTypesArticleSecurity(item *domain.ArticleSecurity, reviewer *domain.User) types.ArticleSecurityItem {
result := types.ArticleSecurityItem{
Id: item.Id,
Content: types.ContentDetailItem{
Id: item.ContentId,
Type: item.ContentType,
},
ContentKeyWords: strings.Join(item.ContentKeyWords, ","),
Label: item.Label,
Prob: item.Prob,
Suggest: describeSuggest(item.Suggest),
Author: item.AuthorName,
ReviewAt: item.CreatedAt,
ReviewStatus: item.ReviewStatus,
ReleaseAt: item.CreatedAt,
Reviewer: "",
}
if reviewer != nil {
result.Reviewer = reviewer.Name
}
for _, detail := range item.Detail.Detail {
if detail.Label.String() == "0" {
continue
}
result.CheckList = append(result.CheckList, types.CheckDetailItem{
Label: detail.Label.String(),
Prob: detail.Prob,
Suggest: describeSuggest(detail.Suggest),
})
}
return result
}
func describeContentType(t int) string {
if t == domain.TypeArticle {
return "文本-帖子"
}
if t == domain.TypeComment {
return "文本-评论"
}
return ""
}
func describeSuggest(s string) string {
if s == "risk" {
return "风险"
}
if s == "pass" {
return "通过"
}
if s == "review" {
return "人工审核"
}
return ""
}
... ...
... ... @@ -36,6 +36,7 @@ type ServiceContext struct {
ArticleCategoryRepository domain.ArticleCategoryRepository
ArticleAndTagRepository domain.ArticleAndTagRepository
ArticleDraftOperationRepository domain.ArticleDraftOperationRepository
ArticleSecurityRepository domain.ArticleSecurityRepository
CompanyRepository domain.CompanyRepository
DepartmentRepository domain.DepartmentRepository
... ... @@ -94,6 +95,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
ArticleAndTagRepository: repository.NewArticleAndTagRepository(cache.NewCachedRepository(mlCache)),
ArticleCategoryRepository: repository.NewArticleCategoryRepository(cache.NewCachedRepository(mlCache)),
ArticleDraftOperationRepository: repository.NewArticleDraftOperationRepository(cache.NewCachedRepository(mlCache)),
ArticleSecurityRepository: repository.NewArticleSecurityRepository(cache.NewCachedRepository(mlCache)),
CompanyRepository: repository.NewCompanyRepository(cache.NewCachedRepository(mlCache)),
DepartmentRepository: repository.NewDepartmentRepository(cache.NewCachedRepository(mlCache)),
... ...
... ... @@ -1849,3 +1849,62 @@ type CategoryOptionValue struct {
Label string `json:"label"` // 名称
Value int64 `json:"value"` // 分类ID
}
type ArticleSecurityGetRequest struct {
Id int64 `path:"id"`
}
type ArticleSecurityGetResponse struct {
ArticleSecurity ArticleSecurityItem `json:"item"`
}
type ArticleSecurityAuditRequest struct {
Id int64 `json:"id"` //id
Status int `json:"status"` // 1:成功 0:失败
}
type ArticleSecurityAuditResponse struct {
}
type ArticleSecuritySearchRequest struct {
Page int `json:"page,optional"`
Size int `json:"size,optional"`
ReviewStatus int `json:"reviewStatus,optional"` // 审核结果 1:待审核 2:通过 3:拒绝
Suggest string `json:"suggest"` // 建议 通过、风险、人工审核
ContentType int `json:"contentType"` // 内容类型 (1:文章 2:评论)
AuthorName string `json:"authorName"` // 作者名称
BeginTime int64 `json:"beginTime"` // 开始时间
EndTime int64 `json:"endTime"` // 结束时间
}
type ArticleSecuritySearchResponse struct {
List []ArticleSecurityItem `json:"list"`
Total int64 `json:"total"`
}
type ArticleSecurityItem struct {
Id int64 `json:"id"` // 唯一标识
ContentKeyWords string `json:"contentKeyWords"` // 内容关键字
Content ContentDetailItem `json:"content"` // 内容详情
Label string `json:"label"` // 风控标签
Prob int `json:"prob"` // 分值
Suggest string `json:"suggest"` // 建议 通过、风险、人工审核
Author string `json:"author"` // 发布人
ReleaseAt int64 `json:"releaseAt"` // 发布时间
ReviewStatus int `json:"reviewStatus"` // 审核结果 1:待审核 2:通过 3:拒绝
Reviewer string `json:"reviewer"` // 审核人
ReviewAt int64 `json:"reviewAt"` // 审核时间(人工处置时间)
CheckList []CheckDetailItem `json:"checkList"` // 检查列表
}
type CheckDetailItem struct {
Label string `json:"label"` // 命中标签
Prob uint `json:"prob"` // 置信度。0-100,越高代表越有可能属于当前返回的标签(label)
Suggest string `json:"suggest"` // 建议
}
type ContentDetailItem struct {
Id int64 `json:"id"` // 内容ID
Type int `json:"type"` // 内容类型 (1:文章 2:评论)
Text string `json:"text"` // 内容文本
}
... ...
syntax = "v1"
info(
title: "xx实例"
desc: "xx实例"
author: "author"
email: "email"
version: "v1"
)
@server(
prefix: article_security/v1
group: article_security
jwt: JwtAuth
)
service Core {
@doc "详情"
@handler article_securityGet
get /article_security/:id (ArticleSecurityGetRequest) returns (ArticleSecurityGetResponse)
@doc "保存"
@handler article_securitySave
post /article_security (ArticleSecuritySaveRequest) returns (ArticleSecuritySaveResponse)
@doc "删除"
@handler article_securityDelete
delete /article_security/:id (ArticleSecurityDeleteRequest) returns (ArticleSecurityDeleteResponse)
@doc "更新"
@handler article_securityUpdate
put /article_security/:id (ArticleSecurityUpdateRequest) returns (ArticleSecurityUpdateResponse)
@doc "搜索"
@handler article_securitySearch
post /article_security/search (ArticleSecuritySearchRequest) returns (ArticleSecuritySearchResponse)
}
type (
ArticleSecurityGetRequest {
Id int64 `path:"id"`
}
ArticleSecurityGetResponse struct{
ArticleSecurity ArticleSecurityItem `json:"article_security"`
}
ArticleSecuritySaveRequest struct{
ArticleSecurity ArticleSecurityItem `json:"article_security"`
}
ArticleSecuritySaveResponse struct{}
ArticleSecurityDeleteRequest struct{
Id int64 `path:"id"`
}
ArticleSecurityDeleteResponse struct{}
ArticleSecurityUpdateRequest struct{
Id int64 `path:"id"`
ArticleSecurity ArticleSecurityItem `json:"article_security"`
}
ArticleSecurityUpdateResponse struct{}
ArticleSecuritySearchRequest struct{
Page int `json:"page"`
Size int `json:"size"`
}
ArticleSecuritySearchResponse{
List []ArticleSecurityItem `json:"list"`
Total int64 `json:"total"`
}
ArticleSecurityItem struct{
}
)
// logic CRUD
// Save
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ArticleSecurity
//)
//// 唯一判断
//dm = NewDomainArticleSecurity(req.ArticleSecurity)
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ArticleSecurityRepository.Insert(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("保存失败")
//}
////resp = &types.ArticleSecuritySaveResponse{}
//return
//func NewDomainArticleSecurity(item types.ArticleSecurityItem) *domain.ArticleSecurity {
// return &domain.ArticleSecurity{
// }
//}
//
//func NewTypesArticleSecurity(item *domain.ArticleSecurity) types.ArticleSecurityItem {
// return types.ArticleSecurityItem{
// Id: item.Id,
// }
//}
// Get
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ArticleSecurity
//)
//// 货号唯一
//if dm, err = l.svcCtx.ArticleSecurityRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//resp = &types.ArticleSecurityGetResponse{
// ArticleSecurity: NewTypesArticleSecurity(dm),
//}
//return
// Delete
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ArticleSecurity
//)
//if dm, err = l.svcCtx.ArticleSecurityRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// if dm, err = l.svcCtx.ArticleSecurityRepository.Delete(l.ctx, conn, dm); err != nil {
// return err
// }
// return nil
//}, true); err != nil {
// return nil, xerr.NewErrMsgErr("移除失败", err)
//}
//return
// Search
//var (
// conn = l.svcCtx.DefaultDBConn()
// dms []*domain.ArticleSecurity
// total int64
//)
//
//queryOptions := domain.NewQueryOptions().WithOffsetLimit(req.Page, req.Size).
// WithKV("", "")
//total, dms, err = l.svcCtx.ArticleSecurityRepository.Find(l.ctx, conn, queryOptions)
//list := make([]types.ArticleSecurityItem, 0)
//for i := range dms {
// list = append(list, NewTypesArticleSecurity(dms[i]))
//}
//resp = &types.ArticleSecuritySearchResponse{
// List: list,
// Total: total,
//}
//return
// Update
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ArticleSecurity
//)
//if dm, err = l.svcCtx.ArticleSecurityRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//// 不可编辑判断
//// 赋值
//// 更新
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ArticleSecurityRepository.UpdateWithVersion(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("更新失败")
//}
//resp = &types.ArticleSecurityUpdateResponse{}
//return
... ...
syntax = "proto3";
option go_package ="./pb";
package pb;
message ArticleSecurityGetReq {
int64 Id = 1;
}
message ArticleSecurityGetResp{
ArticleSecurityItem User = 1;
}
message ArticleSecuritySaveReq {
}
message ArticleSecuritySaveResp{
}
message ArticleSecurityDeleteReq {
int64 Id = 1;
}
message ArticleSecurityDeleteResp{
}
message ArticleSecurityUpdateReq {
int64 Id = 1;
}
message ArticleSecurityUpdateResp{
}
message ArticleSecuritySearchReq {
int64 PageNumber = 1;
int64 PageSize = 2;
}
message ArticleSecuritySearchResp{
repeated ArticleSecurityItem List =1;
int64 Total =2;
}
message ArticleSecurityItem {
}
service ArticleSecurityService {
rpc ArticleSecurityGet(ArticleSecurityGetReq) returns(ArticleSecurityGetResp);
rpc ArticleSecuritySave(ArticleSecuritySaveReq) returns(ArticleSecuritySaveResp);
rpc ArticleSecurityDelete(ArticleSecurityDeleteReq) returns(ArticleSecurityDeleteResp);
rpc ArticleSecurityUpdate(ArticleSecurityUpdateReq) returns(ArticleSecurityUpdateResp);
rpc ArticleSecuritySearch(ArticleSecuritySearchReq) returns(ArticleSecuritySearchResp);
}
... ...
... ... @@ -26,9 +26,12 @@ func Migrate(db *gorm.DB) {
//&models.ArticleAndTag{},
//&models.ArticleDraftOperation{},
//&models.ArticleCategory{},
&models.UserSubscribe{},
&models.MessageSubscribe{},
&models.UserWechat{},
//&models.UserSubscribe{},
//&models.MessageSubscribe{},
//&models.UserWechat{},
//&models.ArticleDraftOperation{},
//&models.ArticleCategory{},
&models.ArticleSecurity{},
}
db.AutoMigrate(modelsList...)
... ...
package models
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
"time"
)
type ArticleSecurity struct {
Id int64 // 唯一标识
CompanyId int64
ContentKeyWords []string `gorm:"type:jsonb;serializer:json"` // 内容关键字
ContentType int `json:"contentType,omitempty"` // 内容类型 (1:文章 2:评论)
ContentId int64 `json:"contentId,omitempty"` // 内容ID
AuthorId int64 `json:"authorId,omitempty"` // 发布人
AuthorName string `json:"authorName,omitempty"` // 发布人
Reviewer int64 `json:"reviewer,omitempty"` // 审核人
ReviewStatus int `json:"reviewStatus,omitempty"` // 审核状态 0:待审核 1:通过 2:拒绝
Label string // 标签
Prob int // 分值
Suggest string // 建议 通过、风险、人工审核
Detail domain.MsgCheckDetail `gorm:"type:jsonb;serializer:json"`
AutoReviewAt int64 `json:"autoReviewAt,omitempty"` // 自动审核时间
AutoReviewErrorCode string `json:"autoReviewErrorCode,omitempty"` // 自动审核错误码
ReviewAt int64 `json:"reviewAt,omitempty"` // 审核时间(人工处置时间)
CreatedAt int64
UpdatedAt int64
DeletedAt int64
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"`
Version int
}
func (m *ArticleSecurity) TableName() string {
return "article_security"
}
func (m *ArticleSecurity) BeforeCreate(tx *gorm.DB) (err error) {
m.CreatedAt = time.Now().Unix()
m.UpdatedAt = time.Now().Unix()
return
}
func (m *ArticleSecurity) BeforeUpdate(tx *gorm.DB) (err error) {
m.UpdatedAt = time.Now().Unix()
return
}
func (m *ArticleSecurity) CacheKeyFunc() string {
if m.Id == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
}
func (m *ArticleSecurity) CacheKeyFuncByObject(obj interface{}) string {
if v, ok := obj.(*ArticleSecurity); ok {
return v.CacheKeyFunc()
}
return ""
}
func (m *ArticleSecurity) CachePrimaryKeyFunc() string {
if len("") == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
}
... ...
... ... @@ -437,6 +437,28 @@ func (repository *ArticleCommentRepository) CustomSearchBy(ctx context.Context,
}
// CommentUserCount 统计评论人数
func (repository *ArticleCommentRepository) CommentUserCount(ctx context.Context, conn transaction.Conn, companyId int64, articleId int64) (int64, error) {
var (
err error
tx = conn.DB()
c int64
)
err = tx.Model(&models.ArticleComment{}).Where("company_id = ? and article_id = ?", companyId, articleId).Group("from_user_id").Count(&c).Error
return c, err
}
// ReplyUserCount 统计回复人数
func (repository *ArticleCommentRepository) ReplyUserCount(ctx context.Context, conn transaction.Conn, companyId int64, commentId int64) (int64, error) {
var (
err error
tx = conn.DB()
c int64
)
err = tx.Model(&models.ArticleComment{}).Where("company_id = ? and pid = ?", companyId, commentId).Group("from_user_id").Count(&c).Error
return c, err
}
func NewArticleCommentRepository(cache *cache.CachedRepository) domain.ArticleCommentRepository {
return &ArticleCommentRepository{CachedRepository: cache}
}
... ...
package repository
import (
"context"
"fmt"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/tiptok/gocomm/pkg/cache"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/models"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
"gorm.io/gorm"
)
type ArticleSecurityRepository struct {
*cache.CachedRepository
}
func (repository *ArticleSecurityRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.ArticleSecurity) (*domain.ArticleSecurity, error) {
var (
err error
m = &models.ArticleSecurity{}
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
if tx = tx.Model(m).Save(m); tx.Error != nil {
return nil, tx.Error
}
dm.Id = m.Id
return repository.ModelToDomainModel(m)
}
func (repository *ArticleSecurityRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.ArticleSecurity) (*domain.ArticleSecurity, error) {
var (
err error
m *models.ArticleSecurity
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Updates(m)
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ArticleSecurityRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.ArticleSecurity) (*domain.ArticleSecurity, error) {
var (
err error
m *models.ArticleSecurity
tx = transaction.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
oldVersion := dm.Version
m.Version += 1
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
if tx.RowsAffected == 0 {
return nil, domain.ErrUpdateFail
}
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ArticleSecurityRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.ArticleSecurity) (*domain.ArticleSecurity, error) {
var (
tx = conn.DB()
m = &models.ArticleSecurity{Id: dm.Identify().(int64)}
)
queryFunc := func() (interface{}, error) {
tx = tx.Where("id = ?", m.Id).Delete(m)
return m, tx.Error
}
if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return dm, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ArticleSecurityRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.ArticleSecurity, error) {
var (
err error
tx = conn.DB()
m = new(models.ArticleSecurity)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ArticleSecurity)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ArticleSecurityRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.ArticleSecurity, error) {
var (
tx = conn.DB()
ms []*models.ArticleSecurity
dms = make([]*domain.ArticleSecurity, 0)
total int64
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(&ms).Order("id desc")
if v, ok := queryOptions["companyId"]; ok {
tx.Where("company_id = ?", v)
}
if v, ok := queryOptions["authorName"]; ok {
tx.Where("author_name like ? ", fmt.Sprintf("%%%v%%", v))
}
if v, ok := queryOptions["contentType"]; ok {
tx.Where("content_type = ? ", v)
}
if v, ok := queryOptions["reviewStatus"]; ok {
tx.Where("review_status = ? ", v)
}
if v, ok := queryOptions["suggest"]; ok {
tx.Where("suggest = ? ", v)
}
if v, ok := queryOptions["beginTime"]; ok {
tx.Where("created_at >= ?", v)
}
if v, ok := queryOptions["endTime"]; ok {
tx.Where("created_at < ?", v)
}
if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
return dms, tx.Error
}
return dms, nil
}
if _, err := repository.Query(queryFunc); err != nil {
return 0, nil, err
}
for _, item := range ms {
if dm, err := repository.ModelToDomainModel(item); err != nil {
return 0, dms, err
} else {
dms = append(dms, dm)
}
}
return total, dms, nil
}
func (repository *ArticleSecurityRepository) ModelToDomainModel(from *models.ArticleSecurity) (*domain.ArticleSecurity, error) {
to := &domain.ArticleSecurity{}
err := copier.Copy(to, from)
return to, err
}
func (repository *ArticleSecurityRepository) DomainModelToModel(from *domain.ArticleSecurity) (*models.ArticleSecurity, error) {
to := &models.ArticleSecurity{}
err := copier.Copy(to, from)
return to, err
}
func NewArticleSecurityRepository(cache *cache.CachedRepository) domain.ArticleSecurityRepository {
return &ArticleSecurityRepository{CachedRepository: cache}
}
... ...
... ... @@ -95,6 +95,7 @@ type ArticleShow int
const (
ArticleShowEnable ArticleShow = 1
ArticleShowDisable ArticleShow = 2
ArticleShowIllegal ArticleShow = 3
)
func (a ArticleShow) Named() string {
... ... @@ -103,6 +104,8 @@ func (a ArticleShow) Named() string {
return "显示"
case ArticleShowDisable:
return "隐藏"
case ArticleShowIllegal:
return "违规"
}
return ""
}
... ...
... ... @@ -39,6 +39,7 @@ type CommentShow int
const (
CommentShowEnable CommentShow = 1
CommentShowDisable CommentShow = 2
CommentShowIllegal CommentShow = 3
)
func (show CommentShow) Named() string {
... ... @@ -47,6 +48,8 @@ func (show CommentShow) Named() string {
return "显示"
case CommentShowDisable:
return "隐藏"
case CommentShowIllegal:
return "违规"
}
return ""
}
... ... @@ -80,6 +83,10 @@ type ArticleCommentRepository interface {
// 特定的查询
CustomSearchBy(ctx context.Context, conn transaction.Conn, companyId int64, page int, size int,
topId int64, articleTitle string, contentLike string, fromUserId int64, show int, createdAtRange [2]int64) (int, []*ArticleCommentShow, error)
// CommentUserCount 统计帖子评论人数
CommentUserCount(ctx context.Context, conn transaction.Conn, companyId int64, articleId int64) (int64, error)
// ReplyUserCount 统计评论回复人数
ReplyUserCount(ctx context.Context, conn transaction.Conn, companyId int64, commentId int64) (int64, error)
}
// 运营点数 填写的最大值
... ...
package domain
import (
"context"
"github.com/silenceper/wechat/v2/miniprogram/security"
"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
)
type ArticleSecurity struct {
Id int64 // 唯一标识
CompanyId int64
ContentKeyWords []string // 内容关键字
ContentType int `json:"contentType,omitempty"` // 内容类型 (1:文章 2:评论)
ContentId int64 `json:"contentId,omitempty"` // 内容ID
AuthorId int64 `json:"authorId,omitempty"` // 发布人
AuthorName string `json:"authorName,omitempty"` // 发布人
Reviewer int64 `json:"reviewer,omitempty"` // 审核人
ReviewStatus int `json:"reviewStatus,omitempty"` // 审核状态 1:待审核 2:通过 3:拒绝
Label string // 标签
Prob int // 分值
Suggest string // 建议 通过、风险、人工审核
Detail MsgCheckDetail `json:"detail,omitempty"`
AutoReviewAt int64 `json:"autoReviewAt,omitempty"` // 自动审核时间
AutoReviewErrorCode string `json:"autoReviewErrorCode,omitempty"` // 自动审核错误码
ReviewAt int64 `json:"reviewAt,omitempty"` // 审核时间(人工处置时间)
CreatedAt int64 `json:"createdAt,omitempty"`
UpdatedAt int64 `json:"updatedAt,omitempty"`
DeletedAt int64 `json:"deletedAt,omitempty"`
Version int `json:"version,omitempty"`
}
const (
ReviewStatusWait = iota + 1
ReviewStatusPass
ReviewStatusFail
)
const (
TypeArticle = 1
TypeComment = 2
)
type MsgCheckDetail security.MsgCheckResponse
type ArticleSecurityRepository interface {
Insert(ctx context.Context, conn transaction.Conn, dm *ArticleSecurity) (*ArticleSecurity, error)
Update(ctx context.Context, conn transaction.Conn, dm *ArticleSecurity) (*ArticleSecurity, error)
UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *ArticleSecurity) (*ArticleSecurity, error)
Delete(ctx context.Context, conn transaction.Conn, dm *ArticleSecurity) (*ArticleSecurity, error)
FindOne(ctx context.Context, conn transaction.Conn, id int64) (*ArticleSecurity, error)
Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*ArticleSecurity, error)
}
func (m *ArticleSecurity) Identify() interface{} {
if m.Id == 0 {
return nil
}
return m.Id
}
... ...
... ... @@ -21,9 +21,10 @@ type MessageSystem struct {
type MsgSystemType int
const (
MsgTypeNormal MsgSystemType = 1 //1业务正常通知
MsgTypeAbnormal MsgSystemType = 2 //2业务异常通知
MsgTypeDeleted MsgSystemType = 3 //3帖子删除通知
MsgTypeNormal MsgSystemType = 1 //1 业务正常通知(帖子定性)
MsgTypeAbnormal MsgSystemType = 2 //2 业务异常通知(评论删除)
MsgTypeDeleted MsgSystemType = 3 //3 帖子删除通知(帖子删除)
MsgTypeIllegal MsgSystemType = 4 //4 内容违规
)
type MessageSystemRepository interface {
... ...
... ... @@ -63,3 +63,8 @@ CREATE TABLE `user_wechat`
`id` int(0) NOT NULL COMMENT '唯一标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
CREATE TABLE `article_security` (
`id` int(0) NOT NULL COMMENT '唯一标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
\ No newline at end of file
... ...