feature(1.2.8): swagger 接口文档新增 Security
- 将 middleware 命名为 interceptor - 将 deploy 命名为 deployments - 移除 pkg/errno - 使用 proposal 目录 - 优化代码
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# FROM 基于 golang:1.15-alpine
|
||||
FROM golang:1.15-alpine AS builder
|
||||
# FROM 基于 golang:1.16-alpine
|
||||
FROM golang:1.16-alpine AS builder
|
||||
|
||||
# ENV 设置环境变量
|
||||
ENV GOPATH=/opt/repo
|
||||
ENV GO111MODULE=on
|
||||
ENV GOPROXY=https://goproxy.io,direct
|
||||
|
||||
# ADD 源路径 目标路径
|
||||
# COPY 源路径 目标路径
|
||||
COPY . $GOPATH/src/github.com/xinliangnote/go-gin-api
|
||||
|
||||
# RUN 执行 go build .
|
||||
|
||||
@@ -89,14 +89,14 @@ func main() {
|
||||
funcContent += fmt.Sprintf("// @Description%s \n", nameArr[1])
|
||||
// Tags
|
||||
funcContent += fmt.Sprintf("%s \n", v.Decorations().Start.All()[1])
|
||||
funcContent += fmt.Sprintf("// @Accept multipart/form-data \n")
|
||||
funcContent += fmt.Sprintf("// @Accept application/x-www-form-urlencoded \n")
|
||||
funcContent += fmt.Sprintf("// @Produce json \n")
|
||||
funcContent += fmt.Sprintf("// @Param Request body %sRequest true \"请求信息\" \n", Lcfirst(v.Names[0].String()))
|
||||
funcContent += fmt.Sprintf("// @Success 200 {object} %sResponse \n", Lcfirst(v.Names[0].String()))
|
||||
funcContent += fmt.Sprintf("// @Failure 400 {object} code.Failure \n")
|
||||
// Router
|
||||
funcContent += fmt.Sprintf("%s \n", v.Decorations().Start.All()[2])
|
||||
funcContent += fmt.Sprintf("func (h *handler) %s() core.HandlerFunc { \n return func(c core.Context) {\n\n}}", v.Names[0].String())
|
||||
funcContent += fmt.Sprintf("func (h *handler) %s() core.HandlerFunc { \n return func(ctx core.Context) {\n\n}}", v.Names[0].String())
|
||||
|
||||
funcFile.WriteString(funcContent)
|
||||
funcFile.Close()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package configs
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
// MinGoVersion 最小 Go 版本
|
||||
MinGoVersion = 1.16
|
||||
@@ -28,12 +30,15 @@ const (
|
||||
// HeaderLoginToken 登录验证 Token,Header 中传递的参数
|
||||
HeaderLoginToken = "Token"
|
||||
|
||||
// HeaderSignToken 签名验证 Token,Header 中传递的参数
|
||||
// HeaderSignToken 签名验证 Authorization,Header 中传递的参数
|
||||
HeaderSignToken = "Authorization"
|
||||
|
||||
// HeaderSignTokenDate 签名验证 Date,Header 中传递的参数
|
||||
HeaderSignTokenDate = "Authorization-Date"
|
||||
|
||||
// HeaderSignTokenTimeout 签名有效期为 2 分钟
|
||||
HeaderSignTokenTimeout = time.Minute * 2
|
||||
|
||||
// RedisKeyPrefixLoginUser Redis Key 前缀 - 登录用户信息
|
||||
RedisKeyPrefixLoginUser = ProjectName + ":login-user:"
|
||||
|
||||
@@ -48,4 +53,7 @@ const (
|
||||
|
||||
// MaxRequestsPerSecond 每秒最大请求量
|
||||
MaxRequestsPerSecond = 10000
|
||||
|
||||
// LoginSessionTTL 登录有效期为 24 小时
|
||||
LoginSessionTTL = time.Hour * 24
|
||||
)
|
||||
|
||||
716
docs/docs.go
716
docs/docs.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
basePath: /
|
||||
definitions:
|
||||
admin.ListMenuData:
|
||||
properties:
|
||||
@@ -428,6 +429,21 @@ definitions:
|
||||
description: 主键ID
|
||||
type: integer
|
||||
type: object
|
||||
helper.md5Response:
|
||||
properties:
|
||||
md5_str:
|
||||
description: MD5后的字符串
|
||||
type: string
|
||||
type: object
|
||||
helper.signResponse:
|
||||
properties:
|
||||
authorization:
|
||||
description: 签名信息-Authorization
|
||||
type: string
|
||||
authorization_date:
|
||||
description: 签名信息-Authorization-Date
|
||||
type: string
|
||||
type: object
|
||||
menu.createActionResponse:
|
||||
properties:
|
||||
id:
|
||||
@@ -647,7 +663,6 @@ definitions:
|
||||
$ref: '#/definitions/tool.tableData'
|
||||
type: array
|
||||
type: object
|
||||
host: 127.0.0.1:9999
|
||||
info:
|
||||
contact: {}
|
||||
license:
|
||||
@@ -659,17 +674,21 @@ paths:
|
||||
/api/admin:
|
||||
get:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 管理员列表
|
||||
parameters:
|
||||
- description: 第几页
|
||||
- default: 1
|
||||
description: 第几页
|
||||
in: query
|
||||
name: page
|
||||
required: true
|
||||
type: integer
|
||||
- description: 每页显示条数
|
||||
- default: 10
|
||||
description: 每页显示条数
|
||||
in: query
|
||||
name: page_size
|
||||
type: string
|
||||
required: true
|
||||
type: integer
|
||||
- description: 用户名
|
||||
in: query
|
||||
name: username
|
||||
@@ -693,12 +712,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 管理员列表
|
||||
tags:
|
||||
- API.admin
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 新增管理员
|
||||
parameters:
|
||||
- description: 用户名
|
||||
@@ -716,7 +737,7 @@ paths:
|
||||
name: mobile
|
||||
required: true
|
||||
type: string
|
||||
- description: 密码
|
||||
- description: MD5后的密码
|
||||
in: formData
|
||||
name: password
|
||||
required: true
|
||||
@@ -732,6 +753,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 新增管理员
|
||||
tags:
|
||||
- API.admin
|
||||
@@ -757,13 +780,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 删除管理员
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/info:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: 管理员详情
|
||||
produces:
|
||||
- application/json
|
||||
@@ -776,43 +801,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 管理员详情
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/login:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
description: 管理员登录
|
||||
parameters:
|
||||
- description: 用户名
|
||||
in: formData
|
||||
name: username
|
||||
required: true
|
||||
type: string
|
||||
- description: 密码
|
||||
in: formData
|
||||
name: password
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/admin.loginResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 管理员登录
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/logout:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: 管理员登出
|
||||
produces:
|
||||
- application/json
|
||||
@@ -825,13 +822,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 管理员登出
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/menu:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 提交菜单授权
|
||||
parameters:
|
||||
- description: Hashid
|
||||
@@ -855,13 +854,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 提交菜单授权
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/menu/:id:
|
||||
/api/admin/menu/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: 菜单授权列表
|
||||
parameters:
|
||||
- description: hashId
|
||||
@@ -880,13 +881,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 菜单授权列表
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/modify_password:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 修改密码
|
||||
parameters:
|
||||
- description: 旧密码
|
||||
@@ -910,13 +913,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 修改密码
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/modify_personal_info:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 修改个人信息
|
||||
parameters:
|
||||
- description: 昵称
|
||||
@@ -940,13 +945,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 修改个人信息
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/offline:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 下线管理员
|
||||
parameters:
|
||||
- description: Hashid
|
||||
@@ -965,6 +972,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 下线管理员
|
||||
tags:
|
||||
- API.admin
|
||||
@@ -990,13 +999,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 重置密码
|
||||
tags:
|
||||
- API.admin
|
||||
/api/admin/used:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 更新管理员为启用/禁用
|
||||
parameters:
|
||||
- description: Hashid
|
||||
@@ -1020,23 +1031,29 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 更新管理员为启用/禁用
|
||||
tags:
|
||||
- API.admin
|
||||
/api/authorized:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: 调用方列表
|
||||
parameters:
|
||||
- description: 第几页
|
||||
- default: 1
|
||||
description: 第几页
|
||||
in: query
|
||||
name: page
|
||||
required: true
|
||||
type: integer
|
||||
- description: 每页显示条数
|
||||
- default: 10
|
||||
description: 每页显示条数
|
||||
in: query
|
||||
name: page_size
|
||||
type: string
|
||||
required: true
|
||||
type: integer
|
||||
- description: 调用方key
|
||||
in: query
|
||||
name: business_key
|
||||
@@ -1064,12 +1081,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 调用方列表
|
||||
tags:
|
||||
- API.authorized
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 新增调用方
|
||||
parameters:
|
||||
- description: 调用方key
|
||||
@@ -1098,6 +1117,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 新增调用方
|
||||
tags:
|
||||
- API.authorized
|
||||
@@ -1123,16 +1144,18 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 删除调用方
|
||||
tags:
|
||||
- API.authorized
|
||||
/api/authorized/used:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 更新调用方为启用/禁用
|
||||
parameters:
|
||||
- description: Hashid
|
||||
- description: hashID
|
||||
in: formData
|
||||
name: id
|
||||
required: true
|
||||
@@ -1153,13 +1176,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 更新调用方为启用/禁用
|
||||
tags:
|
||||
- API.authorized
|
||||
/api/authorized_api:
|
||||
get:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 调用方接口地址列表
|
||||
parameters:
|
||||
- description: hashID
|
||||
@@ -1178,12 +1203,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 调用方接口地址列表
|
||||
tags:
|
||||
- API.authorized
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 授权调用方接口地址
|
||||
parameters:
|
||||
- description: HashID
|
||||
@@ -1212,6 +1239,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 授权调用方接口地址
|
||||
tags:
|
||||
- API.authorized
|
||||
@@ -1237,13 +1266,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 删除调用方接口地址
|
||||
tags:
|
||||
- API.authorized
|
||||
/api/config/email:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 修改邮件配置
|
||||
parameters:
|
||||
- description: 邮箱服务器
|
||||
@@ -1282,23 +1313,29 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 修改邮件配置
|
||||
tags:
|
||||
- API.config
|
||||
/api/cron:
|
||||
get:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 任务列表
|
||||
parameters:
|
||||
- description: 第几页
|
||||
- default: 1
|
||||
description: 第几页
|
||||
in: query
|
||||
name: page
|
||||
required: true
|
||||
type: integer
|
||||
- description: 每页显示条数
|
||||
- default: 10
|
||||
description: 每页显示条数
|
||||
in: query
|
||||
name: page_size
|
||||
type: string
|
||||
required: true
|
||||
type: integer
|
||||
- description: 任务名称
|
||||
in: query
|
||||
name: name
|
||||
@@ -1322,12 +1359,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 任务列表
|
||||
tags:
|
||||
- API.cron
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 创建任务
|
||||
parameters:
|
||||
- description: 任务名称
|
||||
@@ -1406,10 +1445,12 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 创建任务
|
||||
tags:
|
||||
- API.cron
|
||||
/api/cron/:id:
|
||||
/api/cron/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
@@ -1431,6 +1472,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 获取单条任务详情
|
||||
tags:
|
||||
- API.cron
|
||||
@@ -1455,16 +1498,17 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 手动执行单条任务
|
||||
tags:
|
||||
- API.cron
|
||||
/api/cron/{id}:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 编辑任务
|
||||
parameters:
|
||||
- description: Hashid
|
||||
- description: hashID
|
||||
in: formData
|
||||
name: id
|
||||
required: true
|
||||
@@ -1545,16 +1589,18 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 编辑任务
|
||||
tags:
|
||||
- API.cron
|
||||
/api/cron/used:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 更新任务为启用/禁用
|
||||
parameters:
|
||||
- description: Hashid
|
||||
- description: hashID
|
||||
in: formData
|
||||
name: id
|
||||
required: true
|
||||
@@ -1575,13 +1621,47 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 更新任务为启用/禁用
|
||||
tags:
|
||||
- API.cron
|
||||
/api/login:
|
||||
post:
|
||||
consumes:
|
||||
- application/x-www-form-urlencoded
|
||||
description: 管理员登录
|
||||
parameters:
|
||||
- description: 用户名
|
||||
in: formData
|
||||
name: username
|
||||
required: true
|
||||
type: string
|
||||
- description: MD5后的密码
|
||||
in: formData
|
||||
name: password
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/admin.loginResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 管理员登录
|
||||
tags:
|
||||
- API.admin
|
||||
/api/menu:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: 菜单列表
|
||||
produces:
|
||||
- application/json
|
||||
@@ -1594,12 +1674,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 菜单列表
|
||||
tags:
|
||||
- API.menu
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 创建/编辑菜单
|
||||
parameters:
|
||||
- description: 请求信息
|
||||
@@ -1619,6 +1701,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 创建/编辑菜单
|
||||
tags:
|
||||
- API.menu
|
||||
@@ -1644,12 +1728,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 删除菜单
|
||||
tags:
|
||||
- API.menu
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: 菜单详情
|
||||
parameters:
|
||||
- description: hashId
|
||||
@@ -1668,16 +1754,18 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 菜单详情
|
||||
tags:
|
||||
- API.menu
|
||||
/api/menu/sort:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 更新菜单排序
|
||||
parameters:
|
||||
- description: Hashid
|
||||
- description: hashId
|
||||
in: formData
|
||||
name: id
|
||||
required: true
|
||||
@@ -1698,16 +1786,18 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 更新菜单排序
|
||||
tags:
|
||||
- API.menu
|
||||
/api/menu/used:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 更新菜单为启用/禁用
|
||||
parameters:
|
||||
- description: Hashid
|
||||
- description: hashId
|
||||
in: formData
|
||||
name: id
|
||||
required: true
|
||||
@@ -1728,13 +1818,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 更新菜单为启用/禁用
|
||||
tags:
|
||||
- API.menu
|
||||
/api/menu_action:
|
||||
get:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 功能权限列表
|
||||
parameters:
|
||||
- description: hashID
|
||||
@@ -1753,12 +1845,14 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 功能权限列表
|
||||
tags:
|
||||
- API.menu
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 创建功能权限
|
||||
parameters:
|
||||
- description: HashID
|
||||
@@ -1787,6 +1881,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 创建功能权限
|
||||
tags:
|
||||
- API.menu
|
||||
@@ -1812,13 +1908,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 删除功能权限
|
||||
tags:
|
||||
- API.menu
|
||||
/api/tool/cache/clear:
|
||||
patch:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 清空缓存
|
||||
parameters:
|
||||
- description: Redis Key
|
||||
@@ -1837,13 +1935,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 清空缓存
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/cache/search:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 查询缓存
|
||||
parameters:
|
||||
- description: Redis Key
|
||||
@@ -1862,13 +1962,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 查询缓存
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/data/dbs:
|
||||
get:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 查询 DB
|
||||
produces:
|
||||
- application/json
|
||||
@@ -1881,13 +1983,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 查询 DB
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/data/mysql:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 执行 SQL 语句
|
||||
parameters:
|
||||
- description: 数据库名称
|
||||
@@ -1916,13 +2020,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 执行 SQL 语句
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/data/tables:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 查询 Table
|
||||
parameters:
|
||||
- description: 数据库名称
|
||||
@@ -1941,13 +2047,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 查询 Table
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/hashids/decode/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: HashIds 解密
|
||||
parameters:
|
||||
- description: 需解密的密文
|
||||
@@ -1966,13 +2074,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: HashIds 解密
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/hashids/encode/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
- application/x-www-form-urlencoded
|
||||
description: HashIds 加密
|
||||
parameters:
|
||||
- description: 需加密的数字
|
||||
@@ -1991,13 +2101,15 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: HashIds 加密
|
||||
tags:
|
||||
- API.tool
|
||||
/api/tool/send_message:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/x-www-form-urlencoded
|
||||
description: 发送消息
|
||||
parameters:
|
||||
- description: 消息内容
|
||||
@@ -2016,7 +2128,79 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginToken: []
|
||||
summary: 发送消息
|
||||
tags:
|
||||
- API.tool
|
||||
/helper/md5/{str}:
|
||||
get:
|
||||
consumes:
|
||||
- application/x-www-form-urlencoded
|
||||
description: 加密
|
||||
parameters:
|
||||
- description: 需要加密的字符串
|
||||
in: path
|
||||
name: str
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/helper.md5Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 加密
|
||||
tags:
|
||||
- Helper
|
||||
/helper/sign:
|
||||
post:
|
||||
consumes:
|
||||
- application/x-www-form-urlencoded
|
||||
description: 签名
|
||||
parameters:
|
||||
- description: 调用方 KEY
|
||||
in: formData
|
||||
name: key
|
||||
required: true
|
||||
type: string
|
||||
- description: 请求路径 (不附带 querystring),例如:/api/login
|
||||
in: formData
|
||||
name: path
|
||||
required: true
|
||||
type: string
|
||||
- description: 请求方式,例如:POST
|
||||
in: formData
|
||||
name: method
|
||||
required: true
|
||||
type: string
|
||||
- description: 请求参数,例如:username=tom&password=123456
|
||||
in: formData
|
||||
name: params
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/helper.signResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 签名
|
||||
tags:
|
||||
- Helper
|
||||
securityDefinitions:
|
||||
LoginToken:
|
||||
in: header
|
||||
name: token
|
||||
type: apiKey
|
||||
swagger: "2.0"
|
||||
|
||||
53
internal/alert/alert.go
Normal file
53
internal/alert/alert.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package alert
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/mail"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// NotifyHandler 告警通知
|
||||
func NotifyHandler(logger *zap.Logger) func(msg *proposal.AlertMessage) {
|
||||
if logger == nil {
|
||||
panic("logger required")
|
||||
}
|
||||
|
||||
return func(msg *proposal.AlertMessage) {
|
||||
cfg := configs.Get().Mail
|
||||
if cfg.Host == "" || cfg.Port == 0 || cfg.User == "" || cfg.Pass == "" || cfg.To == "" {
|
||||
logger.Error("Mail config error")
|
||||
return
|
||||
}
|
||||
|
||||
subject, body, err := newHTMLEmail(
|
||||
msg.Method,
|
||||
msg.HOST,
|
||||
msg.URI,
|
||||
msg.TraceID,
|
||||
msg.ErrorMessage,
|
||||
msg.ErrorStack,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("email template error", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
options := &mail.Options{
|
||||
MailHost: cfg.Host,
|
||||
MailPort: cfg.Port,
|
||||
MailUser: cfg.User,
|
||||
MailPass: cfg.Pass,
|
||||
MailTo: cfg.To,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
if err := mail.Send(options); err != nil {
|
||||
logger.Error("发送告警通知邮件失败", zap.Error(errors.WithStack(err)))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,54 @@
|
||||
package templates
|
||||
package alert
|
||||
|
||||
const PanicMail = `
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewHTMLEmail 告警邮件模板
|
||||
func newHTMLEmail(method, host, uri, id string, msg interface{}, stack string) (subject string, body string, err error) {
|
||||
mailData := &struct {
|
||||
URL string
|
||||
ID string
|
||||
Msg string
|
||||
Stack string
|
||||
Year int
|
||||
}{
|
||||
URL: fmt.Sprintf("%s %s%s", method, host, uri),
|
||||
ID: id,
|
||||
Msg: fmt.Sprintf("%+v", msg),
|
||||
Stack: stack,
|
||||
Year: time.Now().Year(),
|
||||
}
|
||||
|
||||
// subject 邮件主题
|
||||
subject = fmt.Sprintf("[系统告警]-%s", uri)
|
||||
|
||||
// body 邮件内容
|
||||
body, err = getEmailHTMLContent(mailTemplate, mailData)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getEmailHTMLContent 获取邮件模板
|
||||
func getEmailHTMLContent(mailTpl string, mailData interface{}) (string, error) {
|
||||
tpl, err := template.New("email tpl").Parse(mailTpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
err = tpl.Execute(buffer, mailData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
const mailTemplate = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
@@ -27,7 +75,7 @@ const PanicMail = `
|
||||
<!-- Logo -->
|
||||
<tr>
|
||||
<td style="padding: 25px 0; text-align: center;">
|
||||
系统异常
|
||||
系统告警
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -7,14 +7,13 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
Username string `form:"username" binding:"required"` // 用户名
|
||||
Nickname string `form:"nickname" binding:"required"` // 昵称
|
||||
Mobile string `form:"mobile" binding:"required"` // 手机号
|
||||
Password string `form:"password" binding:"required"` // 密码
|
||||
Password string `form:"password" binding:"required"` // MD5后的密码
|
||||
}
|
||||
|
||||
type createResponse struct {
|
||||
@@ -25,24 +24,25 @@ type createResponse struct {
|
||||
// @Summary 新增管理员
|
||||
// @Description 新增管理员
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param username formData string true "用户名"
|
||||
// @Param nickname formData string true "昵称"
|
||||
// @Param mobile formData string true "手机号"
|
||||
// @Param password formData string true "密码"
|
||||
// @Param password formData string true "MD5后的密码"
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Create() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -55,10 +55,10 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
|
||||
id, err := h.adminService.Create(c, createData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminCreateError,
|
||||
code.Text(code.AdminCreateError)).WithErr(err),
|
||||
code.Text(code.AdminCreateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type createAdminMenuRequest struct {
|
||||
@@ -22,32 +21,33 @@ type createAdminMenuResponse struct {
|
||||
// @Summary 提交菜单授权
|
||||
// @Description 提交菜单授权
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param actions formData string true "功能权限ID,多个用,分割"
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/menu [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) CreateAdminMenu() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createAdminMenuRequest)
|
||||
res := new(createAdminMenuResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -58,10 +58,10 @@ func (h *handler) CreateAdminMenu() core.HandlerFunc {
|
||||
|
||||
err = h.adminService.CreateMenu(c, createData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminMenuCreateError,
|
||||
code.Text(code.AdminMenuCreateError)).WithErr(err),
|
||||
code.Text(code.AdminMenuCreateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type deleteRequest struct {
|
||||
@@ -26,25 +25,26 @@ type deleteResponse struct {
|
||||
// @Success 200 {object} deleteResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/{id} [delete]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Delete() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteRequest)
|
||||
res := new(deleteResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) Delete() core.HandlerFunc {
|
||||
|
||||
err = h.adminService.Delete(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminDeleteError,
|
||||
code.Text(code.AdminDeleteError)).WithErr(err),
|
||||
code.Text(code.AdminDeleteError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,9 +10,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type detailResponse struct {
|
||||
@@ -26,35 +23,36 @@ type detailResponse struct {
|
||||
// @Summary 管理员详情
|
||||
// @Description 管理员详情
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Success 200 {object} detailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/info [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Detail() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
return func(ctx core.Context) {
|
||||
res := new(detailResponse)
|
||||
|
||||
searchOneData := new(admin.SearchOneData)
|
||||
searchOneData.Id = cast.ToInt32(c.UserID())
|
||||
searchOneData.Id = ctx.SessionUserInfo().UserID
|
||||
searchOneData.IsUsed = 1
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
info, err := h.adminService.Detail(ctx, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminDetailError,
|
||||
code.Text(code.AdminDetailError)).WithErr(err),
|
||||
code.Text(code.AdminDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
menuCacheData, err := h.cache.Get(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(searchOneData.Id)+":menu", redis.WithTrace(c.Trace()))
|
||||
menuCacheData, err := h.cache.Get(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(searchOneData.Id)+":menu", redis.WithTrace(ctx.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminDetailError,
|
||||
code.Text(code.AdminDetailError)).WithErr(err),
|
||||
code.Text(code.AdminDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -62,10 +60,10 @@ func (h *handler) Detail() core.HandlerFunc {
|
||||
var menuData []admin.ListMyMenuData
|
||||
err = json.Unmarshal([]byte(menuCacheData), &menuData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminDetailError,
|
||||
code.Text(code.AdminDetailError)).WithErr(err),
|
||||
code.Text(code.AdminDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -74,6 +72,6 @@ func (h *handler) Detail() core.HandlerFunc {
|
||||
res.Nickname = info.Nickname
|
||||
res.Mobile = info.Mobile
|
||||
res.Menu = menuData
|
||||
c.Payload(res)
|
||||
ctx.Payload(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
@@ -49,25 +48,26 @@ type listResponse struct {
|
||||
// @Summary 管理员列表
|
||||
// @Description 管理员列表
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param page query int false "第几页"
|
||||
// @Param page_size query string false "每页显示条数"
|
||||
// @Param page query int true "第几页" default(1)
|
||||
// @Param page_size query int true "每页显示条数" default(10)
|
||||
// @Param username query string false "用户名"
|
||||
// @Param nickname query string false "昵称"
|
||||
// @Param mobile query string false "手机号"
|
||||
// @Success 200 {object} listResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) List() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(listRequest)
|
||||
res := new(listResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -91,20 +91,20 @@ func (h *handler) List() core.HandlerFunc {
|
||||
|
||||
resListData, err := h.adminService.PageList(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminListError,
|
||||
code.Text(code.AdminListError)).WithErr(err),
|
||||
code.Text(code.AdminListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
resCountData, err := h.adminService.PageListCount(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminListError,
|
||||
code.Text(code.AdminListError)).WithErr(err),
|
||||
code.Text(code.AdminListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -116,10 +116,10 @@ func (h *handler) List() core.HandlerFunc {
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type listAdminMenuRequest struct {
|
||||
@@ -22,31 +21,32 @@ type listAdminMenuResponse struct {
|
||||
// @Summary 菜单授权列表
|
||||
// @Description 菜单授权列表
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id path string true "hashId"
|
||||
// @Success 200 {object} listAdminMenuResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/menu/:id [get]
|
||||
// @Router /api/admin/menu/{id} [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ListAdminMenu() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(listAdminMenuRequest)
|
||||
res := new(listAdminMenuResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -57,10 +57,10 @@ func (h *handler) ListAdminMenu() core.HandlerFunc {
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminMenuListError,
|
||||
code.Text(code.AdminMenuListError)).WithErr(err),
|
||||
code.Text(code.AdminMenuListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -72,10 +72,10 @@ func (h *handler) ListAdminMenu() core.HandlerFunc {
|
||||
|
||||
listData, err := h.adminService.ListMenu(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminMenuListError,
|
||||
code.Text(code.AdminMenuListError)).WithErr(err),
|
||||
code.Text(code.AdminMenuListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,15 +3,14 @@ package admin
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -28,22 +27,23 @@ type loginResponse struct {
|
||||
// @Summary 管理员登录
|
||||
// @Description 管理员登录
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param username formData string true "用户名"
|
||||
// @Param password formData string true "密码"
|
||||
// @Param password formData string true "MD5后的密码"
|
||||
// @Success 200 {object} loginResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/login [post]
|
||||
// @Router /api/login [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Login() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(loginRequest)
|
||||
res := new(loginResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -55,47 +55,38 @@ func (h *handler) Login() core.HandlerFunc {
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.Text(code.AdminLoginError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if info == nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(errors.New("未查询出符合条件的用户")),
|
||||
code.Text(code.AdminLoginError)).WithError(errors.New("未查询出符合条件的用户")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
token := password.GenerateLoginToken(info.Id)
|
||||
|
||||
adminCacheData := &struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
Username string `json:"username"` // 用户名
|
||||
Nickname string `json:"nickname"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
}{
|
||||
Id: info.Id,
|
||||
Username: info.Username,
|
||||
Nickname: info.Nickname,
|
||||
Mobile: info.Mobile,
|
||||
// 用户信息
|
||||
sessionUserInfo := &proposal.SessionUserInfo{
|
||||
UserID: info.Id,
|
||||
UserName: info.Username,
|
||||
}
|
||||
|
||||
// 用户信息
|
||||
adminJsonInfo, _ := json.Marshal(adminCacheData)
|
||||
|
||||
// 将用户信息记录到 Redis 中
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token, string(adminJsonInfo), time.Hour*24, redis.WithTrace(c.Trace()))
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token, string(sessionUserInfo.Marshal()), configs.LoginSessionTTL, redis.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.Text(code.AdminLoginError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -104,10 +95,10 @@ func (h *handler) Login() core.HandlerFunc {
|
||||
searchMenuData.AdminId = info.Id
|
||||
menu, err := h.adminService.MyMenu(c, searchMenuData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.Text(code.AdminLoginError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -116,12 +107,12 @@ func (h *handler) Login() core.HandlerFunc {
|
||||
menuJsonInfo, _ := json.Marshal(menu)
|
||||
|
||||
// 将菜单栏信息记录到 Redis 中
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":menu", string(menuJsonInfo), time.Hour*24, redis.WithTrace(c.Trace()))
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":menu", string(menuJsonInfo), configs.LoginSessionTTL, redis.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.Text(code.AdminLoginError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -130,10 +121,10 @@ func (h *handler) Login() core.HandlerFunc {
|
||||
searchActionData.AdminId = info.Id
|
||||
action, err := h.adminService.MyAction(c, searchActionData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.Text(code.AdminLoginError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -142,12 +133,12 @@ func (h *handler) Login() core.HandlerFunc {
|
||||
actionJsonInfo, _ := json.Marshal(action)
|
||||
|
||||
// 将可访问接口信息记录到 Redis 中
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":action", string(actionJsonInfo), time.Hour*24, redis.WithTrace(c.Trace()))
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":action", string(actionJsonInfo), configs.LoginSessionTTL, redis.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.Text(code.AdminLoginError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -19,21 +18,22 @@ type logoutResponse struct {
|
||||
// @Summary 管理员登出
|
||||
// @Description 管理员登出
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Success 200 {object} logoutResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/logout [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Logout() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
res := new(logoutResponse)
|
||||
res.Username = c.UserName()
|
||||
res.Username = c.SessionUserInfo().UserName
|
||||
|
||||
if !h.cache.Del(configs.RedisKeyPrefixLoginUser+c.GetHeader(configs.HeaderLoginToken), redis.WithTrace(c.Trace())) {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLogOutError,
|
||||
code.Text(code.AdminLogOutError)).WithErr(errors.New("cache del err")),
|
||||
code.Text(code.AdminLogOutError)).WithError(errors.New("cache del err")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type modifyPasswordRequest struct {
|
||||
@@ -25,53 +22,52 @@ type modifyPasswordResponse struct {
|
||||
// @Summary 修改密码
|
||||
// @Description 修改密码
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param old_password formData string true "旧密码"
|
||||
// @Param new_password formData string true "新密码"
|
||||
// @Success 200 {object} modifyPasswordResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/modify_password [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ModifyPassword() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
return func(ctx core.Context) {
|
||||
req := new(modifyPasswordRequest)
|
||||
res := new(modifyPasswordResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
userId := cast.ToInt32(c.UserID())
|
||||
|
||||
searchOneData := new(admin.SearchOneData)
|
||||
searchOneData.Id = userId
|
||||
searchOneData.Id = ctx.SessionUserInfo().UserID
|
||||
searchOneData.Password = password.GeneratePassword(req.OldPassword)
|
||||
searchOneData.IsUsed = 1
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
info, err := h.adminService.Detail(ctx, searchOneData)
|
||||
if err != nil || info == nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminModifyPasswordError,
|
||||
code.Text(code.AdminModifyPasswordError)).WithErr(err),
|
||||
code.Text(code.AdminModifyPasswordError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.ModifyPassword(c, userId, req.NewPassword); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if err := h.adminService.ModifyPassword(ctx, ctx.SessionUserInfo().UserID, req.NewPassword); err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminModifyPasswordError,
|
||||
code.Text(code.AdminModifyPasswordError)).WithErr(err),
|
||||
code.Text(code.AdminModifyPasswordError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Username = c.UserName()
|
||||
c.Payload(res)
|
||||
res.Username = ctx.SessionUserInfo().UserName
|
||||
ctx.Payload(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type modifyPersonalInfoRequest struct {
|
||||
@@ -24,42 +21,41 @@ type modifyPersonalInfoResponse struct {
|
||||
// @Summary 修改个人信息
|
||||
// @Description 修改个人信息
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param nickname formData string true "昵称"
|
||||
// @Param mobile formData string true "手机号"
|
||||
// @Success 200 {object} modifyPersonalInfoResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/modify_personal_info [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ModifyPersonalInfo() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
return func(ctx core.Context) {
|
||||
req := new(modifyPersonalInfoRequest)
|
||||
res := new(modifyPersonalInfoResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
userId := cast.ToInt32(c.UserID())
|
||||
|
||||
modifyData := new(admin.ModifyData)
|
||||
modifyData.Nickname = req.Nickname
|
||||
modifyData.Mobile = req.Mobile
|
||||
|
||||
if err := h.adminService.ModifyPersonalInfo(c, userId, modifyData); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if err := h.adminService.ModifyPersonalInfo(ctx, ctx.SessionUserInfo().UserID, modifyData); err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminModifyPersonalInfoError,
|
||||
code.Text(code.AdminModifyPersonalInfoError)).WithErr(err),
|
||||
code.Text(code.AdminModifyPersonalInfoError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Username = c.UserName()
|
||||
c.Payload(res)
|
||||
res.Username = ctx.SessionUserInfo().UserName
|
||||
ctx.Payload(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type offlineRequest struct {
|
||||
@@ -23,31 +22,32 @@ type offlineResponse struct {
|
||||
// @Summary 下线管理员
|
||||
// @Description 下线管理员
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Success 200 {object} offlineResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/offline [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Offline() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(offlineRequest)
|
||||
res := new(offlineResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func (h *handler) Offline() core.HandlerFunc {
|
||||
|
||||
b := h.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), redis.WithTrace(c.Trace()))
|
||||
if !b {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminOfflineError,
|
||||
code.Text(code.AdminOfflineError)),
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type resetPasswordRequest struct {
|
||||
@@ -26,25 +25,26 @@ type resetPasswordResponse struct {
|
||||
// @Success 200 {object} resetPasswordResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/reset_password/{id} [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ResetPassword() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(resetPasswordRequest)
|
||||
res := new(resetPasswordResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) ResetPassword() core.HandlerFunc {
|
||||
|
||||
err = h.adminService.ResetPassword(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminResetPasswordError,
|
||||
code.Text(code.AdminResetPasswordError)).WithErr(err),
|
||||
code.Text(code.AdminResetPasswordError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateUsedRequest struct {
|
||||
@@ -21,32 +20,33 @@ type updateUsedResponse struct {
|
||||
// @Summary 更新管理员为启用/禁用
|
||||
// @Description 更新管理员为启用/禁用
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} updateUsedResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/used [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateUsedRequest)
|
||||
res := new(updateUsedResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -55,10 +55,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
|
||||
err = h.adminService.UpdateUsed(c, id, req.Used)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminUpdateError,
|
||||
code.Text(code.AdminUpdateError)).WithErr(err),
|
||||
code.Text(code.AdminUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ type Handler interface {
|
||||
|
||||
// Login 管理员登录
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/login [post]
|
||||
// @Router /api/login [post]
|
||||
Login() core.HandlerFunc
|
||||
|
||||
// Logout 管理员登出
|
||||
@@ -78,7 +78,7 @@ type Handler interface {
|
||||
|
||||
// ListAdminMenu 菜单授权列表
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/menu/:id [get]
|
||||
// @Router /api/admin/menu/{id} [get]
|
||||
ListAdminMenu() core.HandlerFunc
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
@@ -23,7 +22,7 @@ type createResponse struct {
|
||||
// @Summary 新增调用方
|
||||
// @Description 新增调用方
|
||||
// @Tags API.authorized
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param business_key formData string true "调用方key"
|
||||
// @Param business_developer formData string true "调用方对接人"
|
||||
@@ -31,15 +30,16 @@ type createResponse struct {
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Create() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -51,10 +51,10 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
|
||||
id, err := h.authorizedService.Create(c, createData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedCreateError,
|
||||
code.Text(code.AuthorizedCreateError)).WithErr(err),
|
||||
code.Text(code.AuthorizedCreateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type createAPIRequest struct {
|
||||
@@ -23,7 +22,7 @@ type createAPIResponse struct {
|
||||
// @Summary 授权调用方接口地址
|
||||
// @Description 授权调用方接口地址
|
||||
// @Tags API.authorized
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "HashID"
|
||||
// @Param method formData string true "请求方法"
|
||||
@@ -31,25 +30,26 @@ type createAPIResponse struct {
|
||||
// @Success 200 {object} createAPIResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized_api [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) CreateAPI() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createAPIRequest)
|
||||
res := new(createAPIResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -59,10 +59,10 @@ func (h *handler) CreateAPI() core.HandlerFunc {
|
||||
// 通过 id 查询出 business_key
|
||||
authorizedInfo, err := h.authorizedService.Detail(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedDetailError,
|
||||
code.Text(code.AuthorizedDetailError)).WithErr(err),
|
||||
code.Text(code.AuthorizedDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -74,10 +74,10 @@ func (h *handler) CreateAPI() core.HandlerFunc {
|
||||
|
||||
createId, err := h.authorizedService.CreateAPI(c, createAPIData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedCreateAPIError,
|
||||
code.Text(code.AuthorizedCreateAPIError)).WithErr(err),
|
||||
code.Text(code.AuthorizedCreateAPIError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type deleteRequest struct {
|
||||
@@ -26,25 +25,26 @@ type deleteResponse struct {
|
||||
// @Success 200 {object} deleteResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized/{id} [delete]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Delete() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteRequest)
|
||||
res := new(deleteResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) Delete() core.HandlerFunc {
|
||||
|
||||
err = h.authorizedService.Delete(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedDeleteError,
|
||||
code.Text(code.AuthorizedDeleteError)).WithErr(err),
|
||||
code.Text(code.AuthorizedDeleteError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type deleteAPIRequest struct {
|
||||
@@ -26,25 +25,26 @@ type deleteAPIResponse struct {
|
||||
// @Success 200 {object} deleteAPIResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized_api/{id} [delete]
|
||||
// @Security LoginToken
|
||||
func (h *handler) DeleteAPI() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteAPIRequest)
|
||||
res := new(deleteAPIResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) DeleteAPI() core.HandlerFunc {
|
||||
|
||||
err = h.authorizedService.DeleteAPI(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedDeleteAPIError,
|
||||
code.Text(code.AuthorizedDeleteAPIError)).WithErr(err),
|
||||
code.Text(code.AuthorizedDeleteAPIError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
@@ -48,10 +47,10 @@ type listResponse struct {
|
||||
// @Summary 调用方列表
|
||||
// @Description 调用方列表
|
||||
// @Tags API.authorized
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param page query int false "第几页"
|
||||
// @Param page_size query string false "每页显示条数"
|
||||
// @Param page query int true "第几页" default(1)
|
||||
// @Param page_size query int true "每页显示条数" default(10)
|
||||
// @Param business_key query string false "调用方key"
|
||||
// @Param business_secret query string false "调用方secret"
|
||||
// @Param business_developer query string false "调用方对接人"
|
||||
@@ -59,15 +58,16 @@ type listResponse struct {
|
||||
// @Success 200 {object} listResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) List() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(listRequest)
|
||||
res := new(listResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -91,20 +91,20 @@ func (h *handler) List() core.HandlerFunc {
|
||||
|
||||
resListData, err := h.authorizedService.PageList(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedListError,
|
||||
code.Text(code.AuthorizedListError)).WithErr(err),
|
||||
code.Text(code.AuthorizedListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
resCountData, err := h.authorizedService.PageListCount(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedListError,
|
||||
code.Text(code.AuthorizedListError)).WithErr(err),
|
||||
code.Text(code.AuthorizedListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -116,10 +116,10 @@ func (h *handler) List() core.HandlerFunc {
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -31,31 +30,32 @@ type listAPIResponse struct {
|
||||
// @Summary 调用方接口地址列表
|
||||
// @Description 调用方接口地址列表
|
||||
// @Tags API.authorized
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id query string true "hashID"
|
||||
// @Success 200 {object} listAPIResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized_api [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ListAPI() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(listAPIRequest)
|
||||
res := new(listAPIResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -65,10 +65,10 @@ func (h *handler) ListAPI() core.HandlerFunc {
|
||||
// 通过 id 查询出 business_key
|
||||
authorizedInfo, err := h.authorizedService.Detail(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedDetailError,
|
||||
code.Text(code.AuthorizedDetailError)).WithErr(err),
|
||||
code.Text(code.AuthorizedDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -80,10 +80,10 @@ func (h *handler) ListAPI() core.HandlerFunc {
|
||||
|
||||
resListData, err := h.authorizedService.ListAPI(c, searchAPIData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedListAPIError,
|
||||
code.Text(code.AuthorizedListAPIError)).WithErr(err),
|
||||
code.Text(code.AuthorizedListAPIError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -93,10 +93,10 @@ func (h *handler) ListAPI() core.HandlerFunc {
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateUsedRequest struct {
|
||||
@@ -21,32 +20,33 @@ type updateUsedResponse struct {
|
||||
// @Summary 更新调用方为启用/禁用
|
||||
// @Description 更新调用方为启用/禁用
|
||||
// @Tags API.authorized
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param id formData string true "hashID"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} updateUsedResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized/used [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateUsedRequest)
|
||||
res := new(updateUsedResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -55,10 +55,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
|
||||
err = h.authorizedService.UpdateUsed(c, id, req.Used)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedUpdateError,
|
||||
code.Text(code.AuthorizedUpdateError)).WithErr(err),
|
||||
code.Text(code.AuthorizedUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/mail"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
@@ -31,7 +30,7 @@ type emailResponse struct {
|
||||
// @Summary 修改邮件配置
|
||||
// @Description 修改邮件配置
|
||||
// @Tags API.config
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param host formData string true "邮箱服务器"
|
||||
// @Param port formData string true "端口"
|
||||
@@ -41,15 +40,16 @@ type emailResponse struct {
|
||||
// @Success 200 {object} emailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/config/email [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Email() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(emailRequest)
|
||||
res := new(emailResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -64,10 +64,10 @@ func (h *handler) Email() core.HandlerFunc {
|
||||
Body: fmt.Sprintf("%s[%s] 已添加您为系统告警通知人。", configs.ProjectName, env.Active().Value()),
|
||||
}
|
||||
if err := mail.Send(options); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.SendEmailError,
|
||||
code.Text(code.SendEmailError)+err.Error()).WithErr(err),
|
||||
code.Text(code.SendEmailError)+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -80,10 +80,10 @@ func (h *handler) Email() core.HandlerFunc {
|
||||
|
||||
err := viper.WriteConfig()
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.WriteConfigError,
|
||||
code.Text(code.WriteConfigError)).WithErr(err),
|
||||
code.Text(code.WriteConfigError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/cron"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
@@ -35,7 +34,7 @@ type createResponse struct {
|
||||
// @Summary 创建任务
|
||||
// @Description 创建任务
|
||||
// @Tags API.cron
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param name formData string true "任务名称"
|
||||
// @Param spec formData string true "crontab 表达式"
|
||||
@@ -54,15 +53,16 @@ type createResponse struct {
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/cron [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Create() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -85,10 +85,10 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
|
||||
id, err := h.cronService.Create(ctx, createData)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CronCreateError,
|
||||
code.Text(code.CronCreateError)).WithErr(err),
|
||||
code.Text(code.CronCreateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/cron"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -42,26 +41,27 @@ type detailResponse struct {
|
||||
// @Param id path string true "hashId"
|
||||
// @Success 200 {object} detailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/cron/:id [get]
|
||||
// @Router /api/cron/{id} [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Detail() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(detailRequest)
|
||||
res := new(detailResponse)
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -71,10 +71,10 @@ func (h *handler) Detail() core.HandlerFunc {
|
||||
|
||||
info, err := h.cronService.Detail(ctx, searchOneData)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CronDetailError,
|
||||
code.Text(code.CronDetailError)).WithErr(err),
|
||||
code.Text(code.CronDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -28,36 +27,37 @@ type executeResponse struct {
|
||||
// @Param id path string true "hashId"
|
||||
// @Success 200 {object} detailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/cron/:id [patch]
|
||||
// @Router /api/cron/{id} [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Execute() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(executeRequest)
|
||||
res := new(executeResponse)
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.cronService.Execute(ctx, cast.ToInt32(ids[0]))
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CronExecuteError,
|
||||
code.Text(code.CronExecuteError)).WithErr(err),
|
||||
code.Text(code.CronExecuteError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql/cron_task"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/cron"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
@@ -58,25 +57,26 @@ type listResponse struct {
|
||||
// @Summary 任务列表
|
||||
// @Description 任务列表
|
||||
// @Tags API.cron
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param page query int false "第几页"
|
||||
// @Param page_size query string false "每页显示条数"
|
||||
// @Param page query int true "第几页" default(1)
|
||||
// @Param page_size query int true "每页显示条数" default(10)
|
||||
// @Param name query string false "任务名称"
|
||||
// @Param protocol query int false "执行方式 1:shell 2:http"
|
||||
// @Param is_used query int false "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} listResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/cron [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) List() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(listRequest)
|
||||
res := new(listResponse)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -100,20 +100,20 @@ func (h *handler) List() core.HandlerFunc {
|
||||
|
||||
resListData, err := h.cronService.PageList(ctx, searchData)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CronListError,
|
||||
code.Text(code.CronListError)).WithErr(err),
|
||||
code.Text(code.CronListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
resCountData, err := h.cronService.PageListCount(ctx, searchData)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CronListError,
|
||||
code.Text(code.CronListError)).WithErr(err),
|
||||
code.Text(code.CronListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -126,10 +126,10 @@ func (h *handler) List() core.HandlerFunc {
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/cron"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type modifyRequest struct {
|
||||
@@ -36,9 +35,9 @@ type modifyResponse struct {
|
||||
// @Summary 编辑任务
|
||||
// @Description 编辑任务
|
||||
// @Tags API.cron
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param id formData string true "hashID"
|
||||
// @Param name formData string true "任务名称"
|
||||
// @Param spec formData string true "crontab 表达式"
|
||||
// @Param command formData string true "执行命令"
|
||||
@@ -56,25 +55,26 @@ type modifyResponse struct {
|
||||
// @Success 200 {object} modifyResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/cron/{id} [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Modify() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(modifyRequest)
|
||||
res := new(modifyResponse)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -98,10 +98,10 @@ func (h *handler) Modify() core.HandlerFunc {
|
||||
modifyData.IsUsed = req.IsUsed
|
||||
|
||||
if err := h.cronService.Modify(ctx, id, modifyData); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CronUpdateError,
|
||||
code.Text(code.CronUpdateError)).WithErr(err),
|
||||
code.Text(code.CronUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateUsedRequest struct {
|
||||
@@ -22,32 +21,33 @@ type updateUsedResponse struct {
|
||||
// @Summary 更新任务为启用/禁用
|
||||
// @Description 更新任务为启用/禁用
|
||||
// @Tags API.cron
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param id formData string true "hashID"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} updateUsedResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/cron/used [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(updateUsedRequest)
|
||||
res := new(updateUsedResponse)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -56,10 +56,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
|
||||
err = h.cronService.UpdateUsed(ctx, id, req.Used)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AdminUpdateError,
|
||||
code.Text(code.AdminUpdateError)).WithErr(err),
|
||||
code.Text(code.AdminUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ type Handler interface {
|
||||
|
||||
// Detail 获取单条任务详情
|
||||
// @Tags API.cron
|
||||
// @Router /api/cron/:id [get]
|
||||
// @Router /api/cron/{id} [get]
|
||||
Detail() core.HandlerFunc
|
||||
|
||||
// Execute 手动执行任务
|
||||
// @Tags API.cron
|
||||
// @Router /api/cron/:id [patch]
|
||||
// @Router /api/cron/{id} [patch]
|
||||
Execute() core.HandlerFunc
|
||||
}
|
||||
|
||||
|
||||
49
internal/api/helper/func_md5.go
Executable file
49
internal/api/helper/func_md5.go
Executable file
@@ -0,0 +1,49 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type md5Request struct {
|
||||
Str string `uri:"str" binding:"required"` // 需要加密的字符串
|
||||
}
|
||||
|
||||
type md5Response struct {
|
||||
Md5Str string `json:"md5_str"` // MD5后的字符串
|
||||
}
|
||||
|
||||
// Md5 加密
|
||||
// @Summary 加密
|
||||
// @Description 加密
|
||||
// @Tags Helper
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param str path string true "需要加密的字符串"
|
||||
// @Success 200 {object} md5Response
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /helper/md5/{str} [get]
|
||||
func (h *handler) Md5() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(md5Request)
|
||||
res := new(md5Response)
|
||||
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
m := md5.New()
|
||||
m.Write([]byte(req.Str))
|
||||
res.Md5Str = hex.EncodeToString(m.Sum(nil))
|
||||
ctx.Payload(res)
|
||||
}
|
||||
}
|
||||
100
internal/api/helper/func_sign.go
Executable file
100
internal/api/helper/func_sign.go
Executable file
@@ -0,0 +1,100 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/signature"
|
||||
)
|
||||
|
||||
type signRequest struct {
|
||||
Key string `form:"key" binding:"required"` // 调用方 KEY
|
||||
Path string `form:"path" binding:"required"` // 请求路径 (不附带 querystring),例如:/api/login
|
||||
Method string `form:"method" binding:"required"` // 请求方式,例如:POST
|
||||
Params string `form:"params" binding:"required"` // 请求参数,例如:username=tom&password=123456
|
||||
}
|
||||
|
||||
type signResponse struct {
|
||||
Authorization string `json:"authorization"` // 签名信息-Authorization
|
||||
AuthorizationDate string `json:"authorization_date"` // 签名信息-Authorization-Date
|
||||
}
|
||||
|
||||
// Sign 签名
|
||||
// @Summary 签名
|
||||
// @Description 签名
|
||||
// @Tags Helper
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param key formData string true "调用方 KEY"
|
||||
// @Param path formData string true "请求路径 (不附带 querystring),例如:/api/login"
|
||||
// @Param method formData string true "请求方式,例如:POST"
|
||||
// @Param params formData string true "请求参数,例如:username=tom&password=123456"
|
||||
// @Success 200 {object} signResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /helper/sign [post]
|
||||
func (h *handler) Sign() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(signRequest)
|
||||
res := new(signResponse)
|
||||
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
authorizedInfo, err := h.authorizedService.DetailByKey(ctx, req.Key)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if authorizedInfo.IsUsed == -1 {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New(req.Key + " 已被禁止调用")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(req.Params)
|
||||
|
||||
params, err := url.ParseQuery(req.Params)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
"params 传递格式不正确"),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
sign := signature.New(req.Key, authorizedInfo.Secret, configs.HeaderSignTokenTimeout)
|
||||
authorized, date, err := sign.Generate(req.Path, req.Method, params)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
"sign 生成失败"),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Authorization = authorized
|
||||
res.AuthorizationDate = date
|
||||
ctx.Payload(res)
|
||||
}
|
||||
}
|
||||
42
internal/api/helper/handler.go
Normal file
42
internal/api/helper/handler.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
i()
|
||||
|
||||
// Md5 加密
|
||||
// @Tags Helper
|
||||
// @Router /helper/md5/{str} [get]
|
||||
Md5() core.HandlerFunc
|
||||
|
||||
// Sign 签名
|
||||
// @Tags Helper
|
||||
// @Router /helper/sign [post]
|
||||
Sign() core.HandlerFunc
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
logger *zap.Logger
|
||||
db mysql.Repo
|
||||
authorizedService authorized.Service
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo) Handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
db: db,
|
||||
authorizedService: authorized.New(db, cache),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) i() {}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/menu"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -28,21 +27,22 @@ type createResponse struct {
|
||||
// @Summary 创建/编辑菜单
|
||||
// @Description 创建/编辑菜单
|
||||
// @Tags API.menu
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param Request body createRequest true "请求信息"
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Create() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -50,10 +50,10 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
if req.Id != "" { // 编辑功能
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -67,10 +67,10 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
|
||||
err = h.menuService.Modify(c, id, updateData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuUpdateError,
|
||||
code.Text(code.MenuUpdateError)).WithErr(err),
|
||||
code.Text(code.MenuUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -97,10 +97,10 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
|
||||
id, err := h.menuService.Create(c, createData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuCreateError,
|
||||
code.Text(code.MenuCreateError)).WithErr(err),
|
||||
code.Text(code.MenuCreateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/menu"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type createActionRequest struct {
|
||||
@@ -23,7 +22,7 @@ type createActionResponse struct {
|
||||
// @Summary 创建功能权限
|
||||
// @Description 创建功能权限
|
||||
// @Tags API.menu
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "HashID"
|
||||
// @Param method formData string true "请求方法"
|
||||
@@ -31,25 +30,26 @@ type createActionResponse struct {
|
||||
// @Success 200 {object} createActionResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu_action [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) CreateAction() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createActionRequest)
|
||||
res := new(createActionResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -60,10 +60,10 @@ func (h *handler) CreateAction() core.HandlerFunc {
|
||||
searchOneData.Id = id
|
||||
menuInfo, err := h.menuService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuDetailError,
|
||||
code.Text(code.MenuDetailError)).WithErr(err),
|
||||
code.Text(code.MenuDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -75,10 +75,10 @@ func (h *handler) CreateAction() core.HandlerFunc {
|
||||
|
||||
createId, err := h.menuService.CreateAction(c, createActionData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuCreateActionError,
|
||||
code.Text(code.MenuCreateActionError)).WithErr(err),
|
||||
code.Text(code.MenuCreateActionError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type deleteRequest struct {
|
||||
@@ -26,25 +25,26 @@ type deleteResponse struct {
|
||||
// @Success 200 {object} deleteResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu/{id} [delete]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Delete() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteRequest)
|
||||
res := new(deleteResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) Delete() core.HandlerFunc {
|
||||
|
||||
err = h.menuService.Delete(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuDeleteError,
|
||||
code.Text(code.MenuDeleteError)).WithErr(err),
|
||||
code.Text(code.MenuDeleteError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type deleteActionRequest struct {
|
||||
@@ -26,25 +25,26 @@ type deleteActionResponse struct {
|
||||
// @Success 200 {object} deleteActionResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu_action/{id} [delete]
|
||||
// @Security LoginToken
|
||||
func (h *handler) DeleteAction() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteActionRequest)
|
||||
res := new(deleteActionResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) DeleteAction() core.HandlerFunc {
|
||||
|
||||
err = h.menuService.DeleteAction(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuDeleteActionError,
|
||||
code.Text(code.MenuDeleteActionError)).WithErr(err),
|
||||
code.Text(code.MenuDeleteActionError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/menu"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type detailRequest struct {
|
||||
@@ -25,31 +24,32 @@ type detailResponse struct {
|
||||
// @Summary 菜单详情
|
||||
// @Description 菜单详情
|
||||
// @Tags API.menu
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id path string true "hashId"
|
||||
// @Success 200 {object} detailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu/{id} [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Detail() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(detailRequest)
|
||||
res := new(detailResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -61,10 +61,10 @@ func (h *handler) Detail() core.HandlerFunc {
|
||||
|
||||
info, err := h.menuService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuDetailError,
|
||||
code.Text(code.MenuDetailError)).WithErr(err),
|
||||
code.Text(code.MenuDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/menu"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -30,20 +29,21 @@ type listResponse struct {
|
||||
// @Summary 菜单列表
|
||||
// @Description 菜单列表
|
||||
// @Tags API.menu
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Success 200 {object} listResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) List() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
res := new(listResponse)
|
||||
resListData, err := h.menuService.List(c, new(menu.SearchData))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuListError,
|
||||
code.Text(code.MenuListError)).WithErr(err),
|
||||
code.Text(code.MenuListError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func (h *handler) List() core.HandlerFunc {
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/menu"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -31,31 +30,32 @@ type listActionResponse struct {
|
||||
// @Summary 功能权限列表
|
||||
// @Description 功能权限列表
|
||||
// @Tags API.menu
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id query string true "hashID"
|
||||
// @Success 200 {object} listActionResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu_action [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ListAction() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(listActionRequest)
|
||||
res := new(listActionResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -67,10 +67,10 @@ func (h *handler) ListAction() core.HandlerFunc {
|
||||
|
||||
menuInfo, err := h.menuService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuDetailError,
|
||||
code.Text(code.MenuDetailError)).WithErr(err),
|
||||
code.Text(code.MenuDetailError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -82,10 +82,10 @@ func (h *handler) ListAction() core.HandlerFunc {
|
||||
|
||||
resListData, err := h.menuService.ListAction(c, searchListData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizedListAPIError,
|
||||
code.Text(code.AuthorizedListAPIError)).WithErr(err),
|
||||
code.Text(code.AuthorizedListAPIError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -95,10 +95,10 @@ func (h *handler) ListAction() core.HandlerFunc {
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateSortRequest struct {
|
||||
@@ -21,32 +20,33 @@ type updateSortResponse struct {
|
||||
// @Summary 更新菜单排序
|
||||
// @Description 更新菜单排序
|
||||
// @Tags API.menu
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param id formData string true "hashId"
|
||||
// @Param sort formData int true "排序"
|
||||
// @Success 200 {object} updateSortResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu/sort [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) UpdateSort() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateSortRequest)
|
||||
res := new(updateSortResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -55,10 +55,10 @@ func (h *handler) UpdateSort() core.HandlerFunc {
|
||||
|
||||
err = h.menuService.UpdateSort(c, id, req.Sort)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuUpdateError,
|
||||
code.Text(code.MenuUpdateError)).WithErr(err),
|
||||
code.Text(code.MenuUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateUsedRequest struct {
|
||||
@@ -21,32 +20,33 @@ type updateUsedResponse struct {
|
||||
// @Summary 更新菜单为启用/禁用
|
||||
// @Description 更新菜单为启用/禁用
|
||||
// @Tags API.menu
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param id formData string true "hashId"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} updateUsedResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu/used [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateUsedRequest)
|
||||
res := new(updateUsedResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -55,10 +55,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
|
||||
err = h.menuService.UpdateUsed(c, id, req.Used)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MenuUpdateError,
|
||||
code.Text(code.MenuUpdateError)).WithErr(err),
|
||||
code.Text(code.MenuUpdateError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type clearCacheRequest struct {
|
||||
@@ -21,27 +20,28 @@ type clearCacheResponse struct {
|
||||
// @Summary 清空缓存
|
||||
// @Description 清空缓存
|
||||
// @Tags API.tool
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param redis_key formData string true "Redis Key"
|
||||
// @Success 200 {object} searchCacheResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/cache/clear [patch]
|
||||
// @Security LoginToken
|
||||
func (h *handler) ClearCache() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(clearCacheRequest)
|
||||
res := new(clearCacheResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if b := h.cache.Exists(req.RedisKey); b != true {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CacheNotExist,
|
||||
code.Text(code.CacheNotExist)),
|
||||
@@ -51,7 +51,7 @@ func (h *handler) ClearCache() core.HandlerFunc {
|
||||
|
||||
b := h.cache.Del(req.RedisKey, redis.WithTrace(c.Trace()))
|
||||
if b != true {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CacheDelError,
|
||||
code.Text(code.CacheDelError)),
|
||||
|
||||
@@ -17,11 +17,12 @@ type dbData struct {
|
||||
// @Summary 查询 DB
|
||||
// @Description 查询 DB
|
||||
// @Tags API.tool
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Success 200 {object} dbsResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/data/dbs [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Dbs() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
res := new(dbsResponse)
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type hashIdsDecodeRequest struct {
|
||||
@@ -20,31 +19,32 @@ type hashIdsDecodeResponse struct {
|
||||
// @Summary HashIds 解密
|
||||
// @Description HashIds 解密
|
||||
// @Tags API.tool
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id path string true "需解密的密文"
|
||||
// @Success 200 {object} hashIdsDecodeResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/hashids/decode/{id} [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) HashIdsDecode() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(hashIdsDecodeRequest)
|
||||
res := new(hashIdsDecodeResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
hashId, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsDecodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -22,31 +21,32 @@ type hashIdsEncodeResponse struct {
|
||||
// @Summary HashIds 加密
|
||||
// @Description HashIds 加密
|
||||
// @Tags API.tool
|
||||
// @Accept json
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param id path string true "需加密的数字"
|
||||
// @Success 200 {object} hashIdsEncodeResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/hashids/encode/{id} [get]
|
||||
// @Security LoginToken
|
||||
func (h *handler) HashIdsEncode() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(hashIdsEncodeRequest)
|
||||
res := new(hashIdsEncodeResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(req.Id)})
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsEncodeError,
|
||||
code.Text(code.HashIdsEncodeError)).WithErr(err),
|
||||
code.Text(code.HashIdsEncodeError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type searchCacheRequest struct {
|
||||
@@ -22,27 +21,28 @@ type searchCacheResponse struct {
|
||||
// @Summary 查询缓存
|
||||
// @Description 查询缓存
|
||||
// @Tags API.tool
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param redis_key formData string true "Redis Key"
|
||||
// @Success 200 {object} searchCacheResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/cache/search [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) SearchCache() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(searchCacheRequest)
|
||||
res := new(searchCacheResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if b := h.cache.Exists(req.RedisKey); b != true {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CacheNotExist,
|
||||
code.Text(code.CacheNotExist)),
|
||||
@@ -52,20 +52,20 @@ func (h *handler) SearchCache() core.HandlerFunc {
|
||||
|
||||
val, err := h.cache.Get(req.RedisKey, redis.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CacheGetError,
|
||||
code.Text(code.CacheGetError)).WithErr(err),
|
||||
code.Text(code.CacheGetError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ttl, err := h.cache.TTL(req.RedisKey)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.CacheGetError,
|
||||
code.Text(code.CacheGetError)).WithErr(err),
|
||||
code.Text(code.CacheGetError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -72,7 +71,7 @@ var filterListKeyword = []string{
|
||||
// @Summary 执行 SQL 语句
|
||||
// @Description 执行 SQL 语句
|
||||
// @Tags API.tool
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param db_name formData string true "数据库名称"
|
||||
// @Param table_name formData string true "数据表名称"
|
||||
@@ -80,22 +79,23 @@ var filterListKeyword = []string{
|
||||
// @Success 200 {object} searchMySQLResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/data/mysql [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) SearchMySQL() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(searchMySQLRequest)
|
||||
res := new(searchMySQLResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
sql := strings.ToLower(strings.TrimSpace(req.SQL))
|
||||
if sql == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
"SQL 语句不能为空!"),
|
||||
@@ -104,7 +104,7 @@ func (h *handler) SearchMySQL() core.HandlerFunc {
|
||||
}
|
||||
|
||||
if preFilterList[string([]byte(sql)[:6])] {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
"SQL 语句不能以 "+string([]byte(sql)[:6])+" 开头!"),
|
||||
@@ -124,7 +124,7 @@ func (h *handler) SearchMySQL() core.HandlerFunc {
|
||||
}
|
||||
|
||||
if !isWhiteList {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
"SQL 语句存在敏感词: "+f+"!"),
|
||||
@@ -142,10 +142,10 @@ func (h *handler) SearchMySQL() core.HandlerFunc {
|
||||
// TODO 后期支持查询多个数据库
|
||||
rows, err := h.db.GetDbR().Raw(sql).Rows()
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
"MySQL "+err.Error()).WithErr(err),
|
||||
"MySQL "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -191,10 +191,10 @@ func (h *handler) SearchMySQL() core.HandlerFunc {
|
||||
|
||||
rows, err = h.db.GetDbR().Raw(sqlTableColumn).Rows()
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
"MySQL "+err.Error()).WithErr(err),
|
||||
"MySQL "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
|
||||
"github.com/xinliangnote/go-gin-api/internal/websocket/sysmessage"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
|
||||
)
|
||||
|
||||
@@ -24,12 +23,13 @@ type sendMessageResponse struct {
|
||||
// @Summary 发送消息
|
||||
// @Description 发送消息
|
||||
// @Tags API.tool
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param message formData string true "消息内容"
|
||||
// @Success 200 {object} sendMessageResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/send_message [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) SendMessage() core.HandlerFunc {
|
||||
type messageBody struct {
|
||||
Username string `json:"username"`
|
||||
@@ -41,45 +41,45 @@ func (h *handler) SendMessage() core.HandlerFunc {
|
||||
req := new(sendMessageRequest)
|
||||
res := new(sendMessageResponse)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
validation.Error(err)).WithErr(err),
|
||||
validation.Error(err)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := sysmessage.GetConn()
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.SocketConnectError,
|
||||
code.Text(code.SocketConnectError)).WithErr(err),
|
||||
code.Text(code.SocketConnectError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
messageData := new(messageBody)
|
||||
messageData.Username = ctx.UserName()
|
||||
messageData.Username = ctx.SessionUserInfo().UserName
|
||||
messageData.Message = req.Message
|
||||
messageData.Time = timeutil.CSTLayoutString()
|
||||
|
||||
messageJsonData, err := json.Marshal(messageData)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.SocketSendError,
|
||||
code.Text(code.SocketSendError)).WithErr(err),
|
||||
code.Text(code.SocketSendError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
err = conn.OnSend(messageJsonData)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.SocketSendError,
|
||||
code.Text(code.SocketSendError)).WithErr(err),
|
||||
code.Text(code.SocketSendError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type tablesRequest struct {
|
||||
@@ -26,21 +25,22 @@ type tableData struct {
|
||||
// @Summary 查询 Table
|
||||
// @Description 查询 Table
|
||||
// @Tags API.tool
|
||||
// @Accept multipart/form-data
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param db_name formData string true "数据库名称"
|
||||
// @Success 200 {object} tablesResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/tool/data/tables [post]
|
||||
// @Security LoginToken
|
||||
func (h *handler) Tables() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(tablesRequest)
|
||||
res := new(tablesResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -50,10 +50,10 @@ func (h *handler) Tables() core.HandlerFunc {
|
||||
// TODO 后期支持查询多个数据库
|
||||
rows, err := h.db.GetDbR().Raw(sqlTables).Rows()
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)).WithErr(err),
|
||||
code.Text(code.MySQLExecError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
26
internal/metrics/metrics.go
Normal file
26
internal/metrics/metrics.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// RecordHandler 指标处理
|
||||
func RecordHandler(logger *zap.Logger) func(msg *proposal.MetricsMessage) {
|
||||
if logger == nil {
|
||||
panic("logger required")
|
||||
}
|
||||
|
||||
return func(msg *proposal.MetricsMessage) {
|
||||
RecordMetrics(
|
||||
msg.Method,
|
||||
msg.Path,
|
||||
msg.IsSuccess,
|
||||
msg.HTTPCode,
|
||||
msg.BusinessCode,
|
||||
msg.CostSeconds,
|
||||
msg.TraceID,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -37,15 +37,15 @@ func init() {
|
||||
}
|
||||
|
||||
// RecordMetrics 记录指标
|
||||
func RecordMetrics(method, uri string, success bool, httpCode, businessCode int, costSeconds float64, traceId string) {
|
||||
func RecordMetrics(method, path string, success bool, httpCode, businessCode int, costSeconds float64, traceId string) {
|
||||
metricsRequestsTotal.With(prometheus.Labels{
|
||||
"method": method,
|
||||
"path": uri,
|
||||
"path": path,
|
||||
}).Inc()
|
||||
|
||||
metricsRequestsCost.With(prometheus.Labels{
|
||||
"method": method,
|
||||
"path": uri,
|
||||
"path": path,
|
||||
"success": cast.ToString(success),
|
||||
"http_code": cast.ToString(httpCode),
|
||||
"business_code": cast.ToString(businessCode),
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -28,9 +28,9 @@ const (
|
||||
_BodyName = "_body_"
|
||||
_PayloadName = "_payload_"
|
||||
_GraphPayloadName = "_graph_payload_"
|
||||
_UserID = "_user_id_"
|
||||
_UserName = "_user_name_"
|
||||
_SessionUserInfo = "_session_user_info"
|
||||
_AbortErrorName = "_abort_error_"
|
||||
_IsRecordMetrics = "_is_record_metrics_"
|
||||
)
|
||||
|
||||
var contextPool = &sync.Pool{
|
||||
@@ -101,8 +101,8 @@ type Context interface {
|
||||
HTML(name string, obj interface{})
|
||||
|
||||
// AbortWithError 错误返回
|
||||
AbortWithError(err errno.Error)
|
||||
abortError() errno.Error
|
||||
AbortWithError(err BusinessError)
|
||||
abortError() BusinessError
|
||||
|
||||
// Header 获取 Header 对象
|
||||
Header() http.Header
|
||||
@@ -111,18 +111,19 @@ type Context interface {
|
||||
// SetHeader 设置 Header
|
||||
SetHeader(key, value string)
|
||||
|
||||
// UserID 获取 UserID
|
||||
UserID() int64
|
||||
setUserID(userID int64)
|
||||
// SessionUserInfo 当前用户信息
|
||||
SessionUserInfo() proposal.SessionUserInfo
|
||||
setSessionUserInfo(info proposal.SessionUserInfo)
|
||||
|
||||
// UserName 获取 UserName
|
||||
UserName() string
|
||||
setUserName(userName string)
|
||||
|
||||
// Alias 设置路由别名 for metrics uri
|
||||
// Alias 设置路由别名 for metrics path
|
||||
Alias() string
|
||||
setAlias(path string)
|
||||
|
||||
// disableRecordMetrics 设置禁止记录指标
|
||||
disableRecordMetrics()
|
||||
ableRecordMetrics()
|
||||
isRecordMetrics() bool
|
||||
|
||||
// RequestInputParams 获取所有参数
|
||||
RequestInputParams() url.Values
|
||||
// RequestPostFormParams 获取 PostForm 参数
|
||||
@@ -279,35 +280,22 @@ func (c *context) SetHeader(key, value string) {
|
||||
c.ctx.Header(key, value)
|
||||
}
|
||||
|
||||
func (c *context) UserID() int64 {
|
||||
val, ok := c.ctx.Get(_UserID)
|
||||
func (c *context) SessionUserInfo() proposal.SessionUserInfo {
|
||||
val, ok := c.ctx.Get(_SessionUserInfo)
|
||||
if !ok {
|
||||
return 0
|
||||
return proposal.SessionUserInfo{}
|
||||
}
|
||||
|
||||
return val.(int64)
|
||||
return val.(proposal.SessionUserInfo)
|
||||
}
|
||||
|
||||
func (c *context) setUserID(userID int64) {
|
||||
c.ctx.Set(_UserID, userID)
|
||||
func (c *context) setSessionUserInfo(info proposal.SessionUserInfo) {
|
||||
c.ctx.Set(_SessionUserInfo, info)
|
||||
}
|
||||
|
||||
func (c *context) UserName() string {
|
||||
val, ok := c.ctx.Get(_UserName)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (c *context) setUserName(userName string) {
|
||||
c.ctx.Set(_UserName, userName)
|
||||
}
|
||||
|
||||
func (c *context) AbortWithError(err errno.Error) {
|
||||
func (c *context) AbortWithError(err BusinessError) {
|
||||
if err != nil {
|
||||
httpCode := err.GetHttpCode()
|
||||
httpCode := err.HTTPCode()
|
||||
if httpCode == 0 {
|
||||
httpCode = http.StatusInternalServerError
|
||||
}
|
||||
@@ -317,9 +305,9 @@ func (c *context) AbortWithError(err errno.Error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) abortError() errno.Error {
|
||||
func (c *context) abortError() BusinessError {
|
||||
err, _ := c.ctx.Get(_AbortErrorName)
|
||||
return err.(errno.Error)
|
||||
return err.(BusinessError)
|
||||
}
|
||||
|
||||
func (c *context) Alias() string {
|
||||
@@ -337,6 +325,23 @@ func (c *context) setAlias(path string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) isRecordMetrics() bool {
|
||||
isRecordMetrics, ok := c.ctx.Get(_IsRecordMetrics)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return isRecordMetrics.(bool)
|
||||
}
|
||||
|
||||
func (c *context) ableRecordMetrics() {
|
||||
c.ctx.Set(_IsRecordMetrics, true)
|
||||
}
|
||||
|
||||
func (c *context) disableRecordMetrics() {
|
||||
c.ctx.Set(_IsRecordMetrics, false)
|
||||
}
|
||||
|
||||
// RequestInputParams 获取所有参数
|
||||
func (c *context) RequestInputParams() url.Values {
|
||||
_ = c.ctx.Request.ParseForm()
|
||||
|
||||
@@ -12,10 +12,10 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
_ "github.com/xinliangnote/go-gin-api/docs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/browser"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/color"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
||||
|
||||
@@ -46,20 +46,13 @@ type option struct {
|
||||
disablePProf bool
|
||||
disableSwagger bool
|
||||
disablePrometheus bool
|
||||
panicNotify OnPanicNotify
|
||||
recordMetrics RecordMetrics
|
||||
enableCors bool
|
||||
enableRate bool
|
||||
enableOpenBrowser string
|
||||
alertNotify proposal.NotifyHandler
|
||||
recordHandler proposal.RecordHandler
|
||||
}
|
||||
|
||||
// OnPanicNotify 发生panic时通知用
|
||||
type OnPanicNotify func(ctx Context, err interface{}, stackInfo string)
|
||||
|
||||
// RecordMetrics 记录prometheus指标用
|
||||
// 如果使用AliasForRecordMetrics配置了别名,uri将被替换为别名。
|
||||
type RecordMetrics func(method, uri string, success bool, httpCode, businessCode int, costSeconds float64, traceId string)
|
||||
|
||||
// WithDisablePProf 禁用 pprof
|
||||
func WithDisablePProf() Option {
|
||||
return func(opt *option) {
|
||||
@@ -81,17 +74,17 @@ func WithDisablePrometheus() Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPanicNotify 设置panic时的通知回调
|
||||
func WithPanicNotify(notify OnPanicNotify) Option {
|
||||
// WithAlertNotify 设置告警通知
|
||||
func WithAlertNotify(notifyHandler proposal.NotifyHandler) Option {
|
||||
return func(opt *option) {
|
||||
opt.panicNotify = notify
|
||||
opt.alertNotify = notifyHandler
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecordMetrics 设置记录prometheus记录指标回调
|
||||
func WithRecordMetrics(record RecordMetrics) Option {
|
||||
// WithRecordMetrics 设置记录接口指标
|
||||
func WithRecordMetrics(recordHandler proposal.RecordHandler) Option {
|
||||
return func(opt *option) {
|
||||
opt.recordMetrics = record
|
||||
opt.recordHandler = recordHandler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,41 +95,48 @@ func WithEnableOpenBrowser(uri string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableCors 开启CORS
|
||||
// WithEnableCors 设置支持跨域
|
||||
func WithEnableCors() Option {
|
||||
return func(opt *option) {
|
||||
opt.enableCors = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableRate 设置支持限流
|
||||
func WithEnableRate() Option {
|
||||
return func(opt *option) {
|
||||
opt.enableRate = true
|
||||
}
|
||||
}
|
||||
|
||||
func DisableTrace(ctx Context) {
|
||||
// DisableTraceLog 禁止记录日志
|
||||
func DisableTraceLog(ctx Context) {
|
||||
ctx.disableTrace()
|
||||
}
|
||||
|
||||
// AliasForRecordMetrics 对请求uri起个别名,用于prometheus记录指标。
|
||||
// 如:Get /user/:username 这样的uri,因为username会有非常多的情况,这样记录prometheus指标会非常的不有好。
|
||||
// DisableRecordMetrics 禁止记录指标
|
||||
func DisableRecordMetrics(ctx Context) {
|
||||
ctx.disableRecordMetrics()
|
||||
}
|
||||
|
||||
// AliasForRecordMetrics 对请求路径起个别名,用于记录指标。
|
||||
// 如:Get /user/:username 这样的路径,因为 username 会有非常多的情况,这样记录指标非常不友好。
|
||||
func AliasForRecordMetrics(path string) HandlerFunc {
|
||||
return func(ctx Context) {
|
||||
ctx.setAlias(path)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapAuthHandler 用来处理 Auth 的入口,在之后的handler中只需 ctx.UserID() ctx.UserName() 即可。
|
||||
func WrapAuthHandler(handler func(Context) (userID int64, userName string, err errno.Error)) HandlerFunc {
|
||||
// WrapAuthHandler 用来处理 Auth 的入口
|
||||
func WrapAuthHandler(handler func(Context) (sessionUserInfo proposal.SessionUserInfo, err BusinessError)) HandlerFunc {
|
||||
return func(ctx Context) {
|
||||
userID, userName, err := handler(ctx)
|
||||
sessionUserInfo, err := handler(ctx)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(err)
|
||||
return
|
||||
}
|
||||
ctx.setUserID(userID)
|
||||
ctx.setUserName(userName)
|
||||
|
||||
ctx.setSessionUserInfo(sessionUserInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +328,11 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
})
|
||||
|
||||
mux.engine.Use(func(ctx *gin.Context) {
|
||||
|
||||
if ctx.Writer.Status() == http.StatusNotFound {
|
||||
return
|
||||
}
|
||||
|
||||
ts := time.Now()
|
||||
|
||||
context := newContext(ctx)
|
||||
@@ -335,6 +340,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
|
||||
context.init()
|
||||
context.setLogger(logger)
|
||||
context.ableRecordMetrics()
|
||||
|
||||
if !withoutTracePaths[ctx.Request.URL.Path] {
|
||||
if traceId := context.GetHeader(trace.Header); traceId != "" {
|
||||
@@ -345,24 +351,6 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
stackInfo := string(debug.Stack())
|
||||
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
||||
context.AbortWithError(errno.NewError(
|
||||
http.StatusInternalServerError,
|
||||
code.ServerError,
|
||||
code.Text(code.ServerError)),
|
||||
)
|
||||
|
||||
if notify := opt.panicNotify; notify != nil {
|
||||
notify(context, err, stackInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Writer.Status() == http.StatusNotFound {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
response interface{}
|
||||
businessCode int
|
||||
@@ -372,57 +360,103 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
graphResponse interface{}
|
||||
)
|
||||
|
||||
if ct := context.Trace(); ct != nil {
|
||||
context.SetHeader(trace.Header, ct.ID())
|
||||
traceId = ct.ID()
|
||||
}
|
||||
|
||||
// region 发生 Panic 异常发送告警提醒
|
||||
if err := recover(); err != nil {
|
||||
stackInfo := string(debug.Stack())
|
||||
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
||||
context.AbortWithError(Error(
|
||||
http.StatusInternalServerError,
|
||||
code.ServerError,
|
||||
code.Text(code.ServerError)),
|
||||
)
|
||||
|
||||
if notifyHandler := opt.alertNotify; notifyHandler != nil {
|
||||
notifyHandler(&proposal.AlertMessage{
|
||||
ProjectName: configs.ProjectName,
|
||||
Env: env.Active().Value(),
|
||||
TraceID: traceId,
|
||||
HOST: context.Host(),
|
||||
URI: context.URI(),
|
||||
Method: context.Method(),
|
||||
ErrorMessage: err,
|
||||
ErrorStack: stackInfo,
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 发生错误,进行返回
|
||||
if ctx.IsAborted() {
|
||||
for i := range ctx.Errors { // gin error
|
||||
for i := range ctx.Errors {
|
||||
multierr.AppendInto(&abortErr, ctx.Errors[i])
|
||||
}
|
||||
|
||||
if err := context.abortError(); err != nil { // customer err
|
||||
multierr.AppendInto(&abortErr, err.GetErr())
|
||||
response = err
|
||||
businessCode = err.GetBusinessCode()
|
||||
businessCodeMsg = err.GetMsg()
|
||||
|
||||
if x := context.Trace(); x != nil {
|
||||
context.SetHeader(trace.Header, x.ID())
|
||||
traceId = x.ID()
|
||||
}
|
||||
|
||||
ctx.JSON(err.GetHttpCode(), &code.Failure{
|
||||
Code: businessCode,
|
||||
Message: businessCodeMsg,
|
||||
// 判断是否需要发送告警通知
|
||||
if err.IsAlert() {
|
||||
if notifyHandler := opt.alertNotify; notifyHandler != nil {
|
||||
notifyHandler(&proposal.AlertMessage{
|
||||
ProjectName: configs.ProjectName,
|
||||
Env: env.Active().Value(),
|
||||
TraceID: traceId,
|
||||
HOST: context.Host(),
|
||||
URI: context.URI(),
|
||||
Method: context.Method(),
|
||||
ErrorMessage: err.Message(),
|
||||
ErrorStack: fmt.Sprintf("%+v", err.StackError()),
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
multierr.AppendInto(&abortErr, err.StackError())
|
||||
businessCode = err.BusinessCode()
|
||||
businessCodeMsg = err.Message()
|
||||
response = &code.Failure{
|
||||
Code: businessCode,
|
||||
Message: businessCodeMsg,
|
||||
}
|
||||
ctx.JSON(err.HTTPCode(), response)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 正确返回
|
||||
response = context.getPayload()
|
||||
if response != nil {
|
||||
if x := context.Trace(); x != nil {
|
||||
context.SetHeader(trace.Header, x.ID())
|
||||
traceId = x.ID()
|
||||
}
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
graphResponse = context.getGraphPayload()
|
||||
|
||||
if opt.recordMetrics != nil {
|
||||
uri := context.URI()
|
||||
// region 记录指标
|
||||
if opt.recordHandler != nil && context.isRecordMetrics() {
|
||||
path := context.Path()
|
||||
if alias := context.Alias(); alias != "" {
|
||||
uri = alias
|
||||
path = alias
|
||||
}
|
||||
|
||||
opt.recordMetrics(
|
||||
context.Method(),
|
||||
uri,
|
||||
!ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK,
|
||||
ctx.Writer.Status(),
|
||||
businessCode,
|
||||
time.Since(ts).Seconds(),
|
||||
traceId,
|
||||
)
|
||||
opt.recordHandler(&proposal.MetricsMessage{
|
||||
ProjectName: configs.ProjectName,
|
||||
Env: env.Active().Value(),
|
||||
TraceID: traceId,
|
||||
HOST: context.Host(),
|
||||
Path: path,
|
||||
Method: context.Method(),
|
||||
HTTPCode: ctx.Writer.Status(),
|
||||
BusinessCode: businessCode,
|
||||
CostSeconds: time.Since(ts).Seconds(),
|
||||
IsSuccess: !ctx.IsAborted() && (ctx.Writer.Status() == http.StatusOK),
|
||||
})
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 记录日志
|
||||
var t *trace.Trace
|
||||
if x := context.Trace(); x != nil {
|
||||
t = x.(*trace.Trace)
|
||||
@@ -454,6 +488,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
responseBody = response
|
||||
}
|
||||
|
||||
graphResponse = context.getGraphPayload()
|
||||
if graphResponse != nil {
|
||||
responseBody = graphResponse
|
||||
}
|
||||
@@ -468,10 +503,10 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
CostSeconds: time.Since(ts).Seconds(),
|
||||
})
|
||||
|
||||
t.Success = !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK
|
||||
t.Success = !ctx.IsAborted() && (ctx.Writer.Status() == http.StatusOK)
|
||||
t.CostSeconds = time.Since(ts).Seconds()
|
||||
|
||||
logger.Info("core-interceptor",
|
||||
logger.Info("trace-log",
|
||||
zap.Any("method", ctx.Request.Method),
|
||||
zap.Any("path", decodedURL),
|
||||
zap.Any("http_code", ctx.Writer.Status()),
|
||||
@@ -482,6 +517,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
zap.Any("trace_info", t),
|
||||
zap.Error(abortErr),
|
||||
)
|
||||
// endregion
|
||||
}()
|
||||
|
||||
ctx.Next()
|
||||
@@ -494,7 +530,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
defer releaseContext(context)
|
||||
|
||||
if !limiter.Allow() {
|
||||
context.AbortWithError(errno.NewError(
|
||||
context.AbortWithError(Error(
|
||||
http.StatusTooManyRequests,
|
||||
code.TooManyRequests,
|
||||
code.Text(code.TooManyRequests)),
|
||||
@@ -506,8 +542,9 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
})
|
||||
}
|
||||
|
||||
mux.engine.NoMethod(wrapHandlers(DisableTrace)...)
|
||||
mux.engine.NoRoute(wrapHandlers(DisableTrace)...)
|
||||
mux.engine.NoMethod(wrapHandlers(DisableTraceLog)...)
|
||||
mux.engine.NoRoute(wrapHandlers(DisableTraceLog)...)
|
||||
|
||||
system := mux.Group("/system")
|
||||
{
|
||||
// 健康检查
|
||||
|
||||
82
internal/pkg/core/error.go
Normal file
82
internal/pkg/core/error.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
var _ BusinessError = (*businessError)(nil)
|
||||
|
||||
type BusinessError interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
|
||||
// WithError 设置错误信息
|
||||
WithError(err error) BusinessError
|
||||
|
||||
// WithAlert 设置告警通知
|
||||
WithAlert() BusinessError
|
||||
|
||||
// BusinessCode 获取业务码
|
||||
BusinessCode() int
|
||||
|
||||
// HTTPCode 获取 HTTP 状态码
|
||||
HTTPCode() int
|
||||
|
||||
// Message 获取错误描述
|
||||
Message() string
|
||||
|
||||
// StackError 获取带堆栈的错误信息
|
||||
StackError() error
|
||||
|
||||
// IsAlert 是否开启告警通知
|
||||
IsAlert() bool
|
||||
}
|
||||
|
||||
type businessError struct {
|
||||
httpCode int // HTTP 状态码
|
||||
businessCode int // 业务码
|
||||
message string // 错误描述
|
||||
stackError error // 含有堆栈信息的错误
|
||||
isAlert bool // 是否告警通知
|
||||
}
|
||||
|
||||
func Error(httpCode, businessCode int, message string) BusinessError {
|
||||
return &businessError{
|
||||
httpCode: httpCode,
|
||||
businessCode: businessCode,
|
||||
message: message,
|
||||
isAlert: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *businessError) i() {}
|
||||
|
||||
func (e *businessError) WithError(err error) BusinessError {
|
||||
e.stackError = errors.WithStack(err)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *businessError) WithAlert() BusinessError {
|
||||
e.isAlert = true
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *businessError) HTTPCode() int {
|
||||
return e.httpCode
|
||||
}
|
||||
|
||||
func (e *businessError) BusinessCode() int {
|
||||
return e.businessCode
|
||||
}
|
||||
|
||||
func (e *businessError) Message() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func (e *businessError) StackError() error {
|
||||
return e.stackError
|
||||
}
|
||||
|
||||
func (e *businessError) IsAlert() bool {
|
||||
return e.isAlert
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/mail"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Email 发生 panic 时进行邮件通知
|
||||
func Email(ctx core.Context, err interface{}, stackInfo string) {
|
||||
cfg := configs.Get().Mail
|
||||
if cfg.Host == "" || cfg.Port == 0 || cfg.User == "" || cfg.Pass == "" || cfg.To == "" {
|
||||
ctx.Logger().Error("Mail config error")
|
||||
return
|
||||
}
|
||||
|
||||
tractID := ""
|
||||
if ctx.Trace() != nil {
|
||||
tractID = ctx.Trace().ID()
|
||||
}
|
||||
|
||||
subject, body, htmlErr := NewPanicHTMLEmail(
|
||||
ctx.Method(),
|
||||
ctx.Host(),
|
||||
ctx.URI(),
|
||||
tractID,
|
||||
err,
|
||||
stackInfo,
|
||||
)
|
||||
if htmlErr != nil {
|
||||
ctx.Logger().Error("NewPanicHTMLEmail error", zap.Error(htmlErr))
|
||||
return
|
||||
}
|
||||
|
||||
options := &mail.Options{
|
||||
MailHost: cfg.Host,
|
||||
MailPort: cfg.Port,
|
||||
MailUser: cfg.User,
|
||||
MailPass: cfg.Pass,
|
||||
MailTo: cfg.To,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
sendErr := mail.Send(options)
|
||||
if sendErr != nil {
|
||||
ctx.Logger().Error("Mail Send error", zap.Error(sendErr))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify/templates"
|
||||
)
|
||||
|
||||
// NewPanicHTMLEmail 发送系统异常邮件 html
|
||||
func NewPanicHTMLEmail(method, host, uri, id string, msg interface{}, stack string) (subject string, body string, err error) {
|
||||
mailData := &struct {
|
||||
URL string
|
||||
ID string
|
||||
Msg string
|
||||
Stack string
|
||||
Year int
|
||||
}{
|
||||
URL: fmt.Sprintf("%s %s%s", method, host, uri),
|
||||
ID: id,
|
||||
Msg: fmt.Sprintf("%+v", msg),
|
||||
Stack: stack,
|
||||
Year: time.Now().Year(),
|
||||
}
|
||||
|
||||
mailTplContent, err := getEmailHTMLContent(templates.PanicMail, mailData)
|
||||
return fmt.Sprintf("[系统异常]-%s", uri), mailTplContent, err
|
||||
}
|
||||
|
||||
// getEmailHTMLContent 获取邮件模板
|
||||
func getEmailHTMLContent(mailTpl string, mailData interface{}) (string, error) {
|
||||
tpl, err := template.New("email tpl").Parse(mailTpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buffer := new(bytes.Buffer)
|
||||
err = tpl.Execute(buffer, mailData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
28
internal/proposal/alert.go
Normal file
28
internal/proposal/alert.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package proposal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AlertMessage 告警信息
|
||||
type AlertMessage struct {
|
||||
ProjectName string `json:"project_name"` // 项目名,用于区分不同项目告警信息
|
||||
Env string `json:"env"` // 运行环境
|
||||
TraceID string `json:"trace_id"` // 唯一ID,用于追踪关联
|
||||
HOST string `json:"host"` // 请求 HOST
|
||||
URI string `json:"uri"` // 请求 URI
|
||||
Method string `json:"method"` // 请求 Method
|
||||
ErrorMessage interface{} `json:"error_message"` // 错误信息
|
||||
ErrorStack string `json:"error_stack"` // 堆栈信息
|
||||
Timestamp time.Time `json:"timestamp"` // 时间戳
|
||||
}
|
||||
|
||||
// Marshal 序列化到JSON
|
||||
func (a *AlertMessage) Marshal() (jsonRaw []byte) {
|
||||
jsonRaw, _ = json.Marshal(a)
|
||||
return
|
||||
}
|
||||
|
||||
// NotifyHandler 告警的发送句柄
|
||||
type NotifyHandler func(msg *AlertMessage)
|
||||
28
internal/proposal/metrics.go
Normal file
28
internal/proposal/metrics.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package proposal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// MetricsMessage 指标信息
|
||||
type MetricsMessage struct {
|
||||
ProjectName string `json:"project_name"` // 项目名,用于区分不同项目告警信息
|
||||
Env string `json:"env"` // 运行环境
|
||||
TraceID string `json:"trace_id"` // 唯一ID,用于追踪关联
|
||||
HOST string `json:"host"` // 请求 HOST
|
||||
Path string `json:"path"` // 请求 Path
|
||||
Method string `json:"method"` // 请求 Method
|
||||
HTTPCode int `json:"http_code"` // HTTP 状态码
|
||||
BusinessCode int `json:"business_code"` // 业务码
|
||||
CostSeconds float64 `json:"cost_seconds"` // 耗时,单位:秒
|
||||
IsSuccess bool `json:"is_success"` // 状态,是否成功
|
||||
}
|
||||
|
||||
// Marshal 序列化到JSON
|
||||
func (m *MetricsMessage) Marshal() (jsonRaw []byte) {
|
||||
jsonRaw, _ = json.Marshal(m)
|
||||
return
|
||||
}
|
||||
|
||||
// RecordHandler 指标的记录句柄
|
||||
type RecordHandler func(msg *MetricsMessage)
|
||||
15
internal/proposal/session.go
Normal file
15
internal/proposal/session.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package proposal
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// SessionUserInfo 当前用户会话信息
|
||||
type SessionUserInfo struct {
|
||||
UserID int32 `json:"user_id"` // 用户ID
|
||||
UserName string `json:"user_name"` // 用户名
|
||||
}
|
||||
|
||||
// Marshal 序列化到JSON
|
||||
func (user *SessionUserInfo) Marshal() (jsonRaw []byte) {
|
||||
jsonRaw, _ = json.Marshal(user)
|
||||
return
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -62,10 +61,10 @@ func (h *handler) AdminMenu() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(adminMenuRequest)
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -89,10 +88,10 @@ func (h *handler) MenuAction() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(menuActionRequest)
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -56,10 +55,10 @@ func (h *handler) Api() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(apiRequest)
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -44,10 +43,10 @@ func (h *handler) Edit() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(editRequest)
|
||||
if err := ctx.ShouldBindURI(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal/tablesqls"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/spf13/cast"
|
||||
@@ -68,10 +67,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(initExecuteRequest)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -80,7 +79,7 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
versionStr := runtime.Version()
|
||||
version := cast.ToFloat32(versionStr[2:6])
|
||||
if version < configs.MinGoVersion {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.GoVersionError,
|
||||
code.Text(code.GoVersionError)),
|
||||
@@ -101,10 +100,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
})
|
||||
|
||||
if err := redisClient.Ping().Err(); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.RedisConnectError,
|
||||
code.Text(code.RedisConnectError)).WithErr(err),
|
||||
code.Text(code.RedisConnectError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -131,10 +130,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLConnectError,
|
||||
code.Text(code.MySQLConnectError)).WithErr(err),
|
||||
code.Text(code.MySQLConnectError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -165,10 +164,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
viper.Set("mysql.write.name", req.MySQLName)
|
||||
|
||||
if viper.WriteConfig() != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.WriteConfigError,
|
||||
code.Text(code.WriteConfigError)).WithErr(err),
|
||||
code.Text(code.WriteConfigError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -182,10 +181,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
if v["table_sql"] != "" {
|
||||
// region 初始化表结构
|
||||
if err = db.Exec(v["table_sql"]).Error; err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithErr(err),
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -196,10 +195,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
// region 初始化默认数据
|
||||
if v["table_data_sql"] != "" {
|
||||
if err = db.Exec(v["table_data_sql"]).Error; err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithErr(err),
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -214,10 +213,10 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
// region 生成 install 完成标识
|
||||
f, err := os.Create(configs.ProjectInstallMark)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithErr(err),
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal/tablesqls"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -56,10 +55,10 @@ func (h *handler) UpgradeExecute() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(upgradeExecuteRequest)
|
||||
if err := ctx.ShouldBindForm(req); err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
code.Text(code.ParamBindError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -68,29 +67,29 @@ func (h *handler) UpgradeExecute() core.HandlerFunc {
|
||||
db := h.db.GetDbW()
|
||||
|
||||
if upgradeTableList[req.TableName] == nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)).WithErr(errors.New("数据表不存在")),
|
||||
code.Text(code.MySQLExecError)).WithError(errors.New("数据表不存在")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !upgradeTableOp[req.Op] {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)).WithErr(errors.New("非法操作")),
|
||||
code.Text(code.MySQLExecError)).WithError(errors.New("非法操作")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Op == "table" {
|
||||
if err := db.Exec(upgradeTableList[req.TableName]["table_sql"]).Error; err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithErr(err),
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -98,10 +97,10 @@ func (h *handler) UpgradeExecute() core.HandlerFunc {
|
||||
outPutString = "初始化 MySQL 数据表:" + req.TableName + " 成功。"
|
||||
} else if req.Op == "table_data" {
|
||||
if err := db.Exec(upgradeTableList[req.TableName]["table_data_sql"]).Error; err != nil {
|
||||
ctx.AbortWithError(errno.NewError(
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.MySQLExecError,
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithErr(err),
|
||||
code.Text(code.MySQLExecError)+" "+err.Error()).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
6
internal/repository/mysql/authorized/model.go
Normal file
6
internal/repository/mysql/authorized/model.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package authorized
|
||||
|
||||
const (
|
||||
IsUsedYES = 1 // 启用
|
||||
IsUsedNo = -1 // 禁用
|
||||
)
|
||||
@@ -74,7 +74,10 @@ func after(db *gorm.DB) {
|
||||
sqlInfo.Stack = utils.FileWithLineNum()
|
||||
sqlInfo.Rows = db.Statement.RowsAffected
|
||||
sqlInfo.CostSeconds = time.Since(ts).Seconds()
|
||||
|
||||
if ctx.Trace != nil {
|
||||
ctx.Trace.AppendSQL(sqlInfo)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
56
internal/router/interceptor/check_login.go
Normal file
56
internal/router/interceptor/check_login.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package interceptor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
func (i *interceptor) CheckLogin(ctx core.Context) (sessionUserInfo proposal.SessionUserInfo, err core.BusinessError) {
|
||||
token := ctx.GetHeader(configs.HeaderLoginToken)
|
||||
if token == "" {
|
||||
err = core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("Header 中缺少 Token 参数"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !i.cache.Exists(configs.RedisKeyPrefixLoginUser + token) {
|
||||
err = core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("请先登录"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cacheData, cacheErr := i.cache.Get(configs.RedisKeyPrefixLoginUser+token, redis.WithTrace(ctx.Trace()))
|
||||
if cacheErr != nil {
|
||||
err = core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithError(cacheErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
jsonErr := json.Unmarshal([]byte(cacheData), &sessionUserInfo)
|
||||
if jsonErr != nil {
|
||||
core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithError(jsonErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package middleware
|
||||
package interceptor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -9,47 +9,46 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/urltable"
|
||||
)
|
||||
|
||||
func (m *middleware) RBAC() core.HandlerFunc {
|
||||
func (i *interceptor) CheckRBAC() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
token := c.GetHeader("Token")
|
||||
if token == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Token 参数")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("Header 中缺少 Token 参数")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(configs.RedisKeyPrefixLoginUser + token) {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if !i.cache.Exists(configs.RedisKeyPrefixLoginUser + token) {
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.CacheGetError,
|
||||
code.Text(code.CacheGetError)).WithErr(errors.New("请先登录 1")),
|
||||
code.Text(code.CacheGetError)).WithError(errors.New("请先登录")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(configs.RedisKeyPrefixLoginUser + token + ":action") {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if !i.cache.Exists(configs.RedisKeyPrefixLoginUser + token + ":action") {
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.CacheGetError,
|
||||
code.Text(code.CacheGetError)).WithErr(errors.New("请先登录 2")),
|
||||
code.Text(code.CacheGetError)).WithError(errors.New("当前账号未配置 RBAC 权限")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
actionData, err := m.cache.Get(configs.RedisKeyPrefixLoginUser+token+":action", redis.WithTrace(c.Trace()))
|
||||
actionData, err := i.cache.Get(configs.RedisKeyPrefixLoginUser+token+":action", redis.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.CacheGetError,
|
||||
code.Text(code.CacheGetError)).WithErr(err),
|
||||
code.Text(code.CacheGetError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -57,10 +56,10 @@ func (m *middleware) RBAC() core.HandlerFunc {
|
||||
var actions []admin.MyActionData
|
||||
err = json.Unmarshal([]byte(actionData), &actions)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(err),
|
||||
code.Text(code.AuthorizationError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -72,10 +71,10 @@ func (m *middleware) RBAC() core.HandlerFunc {
|
||||
}
|
||||
|
||||
if pattern, _ := table.Mapping(c.Method() + c.Path()); pattern == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.RBACError,
|
||||
code.Text(code.RBACError)).WithErr(errors.New(c.Method() + c.Path() + " 未进行 RBAC 授权")),
|
||||
code.Text(code.RBACError)).WithError(errors.New(c.Method() + c.Path() + " 未进行 RBAC 授权")),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1,39 +1,36 @@
|
||||
package middleware
|
||||
package interceptor
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/signature"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/urltable"
|
||||
)
|
||||
|
||||
const (
|
||||
ttl = time.Minute * 2 // 签名超时时间 2 分钟
|
||||
minLength = 2 // split space 最小长度
|
||||
notUsed = -1 // -1 表示被禁用
|
||||
|
||||
)
|
||||
|
||||
var whiteListPath = map[string]bool{
|
||||
"/login/web": true,
|
||||
}
|
||||
|
||||
func (m *middleware) Signature() core.HandlerFunc {
|
||||
func (i *interceptor) CheckSignature() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
if !env.Active().IsPro() {
|
||||
return
|
||||
}
|
||||
|
||||
// 签名信息
|
||||
authorization := c.GetHeader(configs.HeaderSignToken)
|
||||
if authorization == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Authorization 参数")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("Header 中缺少 Authorization 参数")),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -41,51 +38,51 @@ func (m *middleware) Signature() core.HandlerFunc {
|
||||
// 时间信息
|
||||
date := c.GetHeader(configs.HeaderSignTokenDate)
|
||||
if date == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Date 参数")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("Header 中缺少 Date 参数")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过签名信息获取 key
|
||||
authorizationSplit := strings.Split(authorization, " ")
|
||||
if len(authorizationSplit) < minLength {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if len(authorizationSplit) < 2 {
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中 Authorization 格式错误")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("Header 中 Authorization 格式错误")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
key := authorizationSplit[0]
|
||||
|
||||
data, err := m.authorizedService.DetailByKey(c, key)
|
||||
data, err := i.authorizedService.DetailByKey(c, key)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(err),
|
||||
code.Text(code.AuthorizationError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if data.IsUsed == notUsed {
|
||||
c.AbortWithError(errno.NewError(
|
||||
if data.IsUsed == authorized.IsUsedNo {
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New(key + " 已被禁止调用")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New(key + " 已被禁止调用")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if len(data.Apis) < 1 {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New(key + " 未进行接口授权")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New(key + " 未进行接口授权")),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -98,30 +95,30 @@ func (m *middleware) Signature() core.HandlerFunc {
|
||||
}
|
||||
|
||||
if pattern, _ := table.Mapping(c.Method() + c.Path()); pattern == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New(c.Method() + c.Path() + " 未进行接口授权")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New(c.Method() + c.Path() + " 未进行接口授权")),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ok, err := signature.New(key, data.Secret, ttl).Verify(authorization, date, c.Path(), c.Method(), c.RequestInputParams())
|
||||
ok, err := signature.New(key, data.Secret, configs.HeaderSignTokenTimeout).Verify(authorization, date, c.Path(), c.Method(), c.RequestInputParams())
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(err),
|
||||
code.Text(code.AuthorizationError)).WithError(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !ok {
|
||||
c.AbortWithError(errno.NewError(
|
||||
c.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中 Authorization 信息错误")),
|
||||
code.Text(code.AuthorizationError)).WithError(errors.New("Header 中 Authorization 信息错误")),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1,36 +1,33 @@
|
||||
package middleware
|
||||
package interceptor
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/proposal"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/admin"
|
||||
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Middleware = (*middleware)(nil)
|
||||
var _ Interceptor = (*interceptor)(nil)
|
||||
|
||||
type Interceptor interface {
|
||||
// CheckLogin 验证是否登录
|
||||
CheckLogin(ctx core.Context) (info proposal.SessionUserInfo, err core.BusinessError)
|
||||
|
||||
// CheckRBAC 验证 RBAC 权限是否合法
|
||||
CheckRBAC() core.HandlerFunc
|
||||
|
||||
// CheckSignature 验证签名是否合法,对用签名算法 pkg/signature
|
||||
CheckSignature() core.HandlerFunc
|
||||
|
||||
type Middleware interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
|
||||
// DisableLog 不记录日志
|
||||
DisableLog() core.HandlerFunc
|
||||
|
||||
// Signature 签名验证,对用签名算法 pkg/signature
|
||||
Signature() core.HandlerFunc
|
||||
|
||||
// Token 签名验证,对登录用户的验证
|
||||
Token(ctx core.Context) (userId int64, userName string, err errno.Error)
|
||||
|
||||
// RBAC 权限验证
|
||||
RBAC() core.HandlerFunc
|
||||
}
|
||||
|
||||
type middleware struct {
|
||||
type interceptor struct {
|
||||
logger *zap.Logger
|
||||
cache redis.Repo
|
||||
db mysql.Repo
|
||||
@@ -38,8 +35,8 @@ type middleware struct {
|
||||
adminService admin.Service
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, cache redis.Repo, db mysql.Repo) Middleware {
|
||||
return &middleware{
|
||||
func New(logger *zap.Logger, cache redis.Repo, db mysql.Repo) Interceptor {
|
||||
return &interceptor{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
db: db,
|
||||
@@ -48,4 +45,4 @@ func New(logger *zap.Logger, cache redis.Repo, db mysql.Repo) Middleware {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *middleware) i() {}
|
||||
func (i *interceptor) i() {}
|
||||
@@ -1,9 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
func (m *middleware) DisableLog() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
core.DisableTrace(c)
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
func (m *middleware) Token(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
token := ctx.GetHeader(configs.HeaderLoginToken)
|
||||
if token == "" {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Token 参数"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(configs.RedisKeyPrefixLoginUser + token) {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("请先登录"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cacheData, cacheErr := m.cache.Get(configs.RedisKeyPrefixLoginUser+token, redis.WithTrace(ctx.Trace()))
|
||||
if cacheErr != nil {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(cacheErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type userInfo struct {
|
||||
Id int64 `json:"id"` // 用户ID
|
||||
Username string `json:"username"` // 用户名
|
||||
}
|
||||
|
||||
var userData userInfo
|
||||
|
||||
jsonErr := json.Unmarshal([]byte(cacheData), &userData)
|
||||
if jsonErr != nil {
|
||||
errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(jsonErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
userId = userData.Id
|
||||
userName = userData.Username
|
||||
|
||||
return
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/alert"
|
||||
"github.com/xinliangnote/go-gin-api/internal/metrics"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/metrics"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/cron"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
|
||||
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
|
||||
"github.com/xinliangnote/go-gin-api/internal/router/middleware"
|
||||
"github.com/xinliangnote/go-gin-api/internal/router/interceptor"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/file"
|
||||
|
||||
@@ -20,7 +20,7 @@ type resource struct {
|
||||
logger *zap.Logger
|
||||
db mysql.Repo
|
||||
cache redis.Repo
|
||||
middles middleware.Middleware
|
||||
interceptors interceptor.Interceptor
|
||||
cronServer cron.Server
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ func NewHTTPServer(logger *zap.Logger, cronLogger *zap.Logger) (*Server, error)
|
||||
core.WithEnableOpenBrowser(openBrowserUri),
|
||||
core.WithEnableCors(),
|
||||
core.WithEnableRate(),
|
||||
core.WithPanicNotify(notify.Email),
|
||||
core.WithRecordMetrics(metrics.RecordMetrics),
|
||||
core.WithAlertNotify(alert.NotifyHandler(logger)),
|
||||
core.WithRecordMetrics(metrics.RecordHandler(logger)),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -82,7 +82,7 @@ func NewHTTPServer(logger *zap.Logger, cronLogger *zap.Logger) (*Server, error)
|
||||
}
|
||||
|
||||
r.mux = mux
|
||||
r.middles = middleware.New(logger, r.cache, r.db)
|
||||
r.interceptors = interceptor.New(logger, r.cache, r.db)
|
||||
|
||||
// 设置 Render 路由
|
||||
setRenderRouter(r)
|
||||
|
||||
@@ -5,24 +5,33 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/cron"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/helper"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/menu"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/tool"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func setApiRouter(r *resource) {
|
||||
// helper
|
||||
helperHandler := helper.New(r.logger, r.db, r.cache)
|
||||
|
||||
helpers := r.mux.Group("/helper")
|
||||
{
|
||||
helpers.GET("/md5/:str", helperHandler.Md5())
|
||||
helpers.POST("/sign", helperHandler.Sign())
|
||||
}
|
||||
|
||||
// admin
|
||||
adminHandler := admin.New(r.logger, r.db, r.cache)
|
||||
|
||||
// 需要签名验证,无需登录验证,无需 RBAC 权限验证
|
||||
login := r.mux.Group("/api", r.middles.Signature())
|
||||
login := r.mux.Group("/api", r.interceptors.CheckSignature())
|
||||
{
|
||||
login.POST("/login", adminHandler.Login())
|
||||
}
|
||||
|
||||
// 需要签名验证、登录验证,无需 RBAC 权限验证
|
||||
notRBAC := r.mux.Group("/api", core.WrapAuthHandler(r.middles.Token), r.middles.Signature())
|
||||
notRBAC := r.mux.Group("/api", core.WrapAuthHandler(r.interceptors.CheckLogin), r.interceptors.CheckSignature())
|
||||
{
|
||||
notRBAC.POST("/admin/logout", adminHandler.Logout())
|
||||
notRBAC.PATCH("/admin/modify_password", adminHandler.ModifyPassword())
|
||||
@@ -31,7 +40,7 @@ func setApiRouter(r *resource) {
|
||||
}
|
||||
|
||||
// 需要签名验证、登录验证、RBAC 权限验证
|
||||
api := r.mux.Group("/api", core.WrapAuthHandler(r.middles.Token), r.middles.Signature(), r.middles.RBAC())
|
||||
api := r.mux.Group("/api", core.WrapAuthHandler(r.interceptors.CheckLogin), r.interceptors.CheckSignature(), r.interceptors.CheckRBAC())
|
||||
{
|
||||
// authorized
|
||||
authorizedHandler := authorized.New(r.logger, r.db, r.cache)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/render/admin"
|
||||
"github.com/xinliangnote/go-gin-api/internal/render/authorized"
|
||||
"github.com/xinliangnote/go-gin-api/internal/render/config"
|
||||
@@ -27,7 +28,7 @@ func setRenderRouter(r *resource) {
|
||||
renderCron := cron.New(r.logger, r.db, r.cache)
|
||||
|
||||
// 无需记录日志,无需 RBAC 权限验证
|
||||
notRBAC := r.mux.Group("", r.middles.DisableLog())
|
||||
notRBAC := r.mux.Group("", core.DisableTraceLog, core.DisableRecordMetrics)
|
||||
{
|
||||
// 首页
|
||||
notRBAC.GET("", renderIndex.Index())
|
||||
@@ -46,7 +47,7 @@ func setRenderRouter(r *resource) {
|
||||
}
|
||||
|
||||
// 无需记录日志,需要 RBAC 权限验证
|
||||
render := r.mux.Group("", r.middles.DisableLog())
|
||||
render := r.mux.Group("", core.DisableTraceLog, core.DisableRecordMetrics)
|
||||
{
|
||||
// 配置信息
|
||||
render.GET("/config/email", renderConfig.Email())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/websocket/sysmessage"
|
||||
)
|
||||
|
||||
@@ -8,7 +9,7 @@ func setSocketRouter(r *resource) {
|
||||
systemMessage := sysmessage.New(r.logger, r.db, r.cache)
|
||||
|
||||
// 无需记录日志
|
||||
socket := r.mux.Group("/socket", r.middles.DisableLog())
|
||||
socket := r.mux.Group("/socket", core.DisableTraceLog, core.DisableRecordMetrics)
|
||||
{
|
||||
// 系统消息
|
||||
socket.GET("/system/message", systemMessage.Connect())
|
||||
|
||||
@@ -19,7 +19,7 @@ func (s *service) Create(ctx core.Context, adminData *CreateAdminData) (id int32
|
||||
model.Password = password.GeneratePassword(adminData.Password)
|
||||
model.Nickname = adminData.Nickname
|
||||
model.Mobile = adminData.Mobile
|
||||
model.CreatedUser = ctx.UserName()
|
||||
model.CreatedUser = ctx.SessionUserInfo().UserName
|
||||
model.IsUsed = 1
|
||||
model.IsDeleted = -1
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ func (s *service) CreateMenu(ctx core.Context, menuData *CreateMenuData) (err er
|
||||
createModel := admin_menu.NewModel()
|
||||
createModel.AdminId = menuData.AdminId
|
||||
createModel.MenuId = cast.ToInt32(v)
|
||||
createModel.CreatedUser = ctx.UserName()
|
||||
createModel.CreatedUser = ctx.SessionUserInfo().UserName
|
||||
|
||||
_, err = createModel.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func (s *service) Delete(ctx core.Context, id int32) (err error) {
|
||||
data := map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := admin.NewQueryBuilder()
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func (s *service) ModifyPassword(ctx core.Context, id int32, newPassword string) (err error) {
|
||||
data := map[string]interface{}{
|
||||
"password": password.GeneratePassword(newPassword),
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := admin.NewQueryBuilder()
|
||||
|
||||
@@ -15,7 +15,7 @@ func (s *service) ModifyPersonalInfo(ctx core.Context, id int32, modifyData *Mod
|
||||
data := map[string]interface{}{
|
||||
"nickname": modifyData.Nickname,
|
||||
"mobile": modifyData.Mobile,
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := admin.NewQueryBuilder()
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func (s *service) ResetPassword(ctx core.Context, id int32) (err error) {
|
||||
data := map[string]interface{}{
|
||||
"password": password.ResetPassword(),
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := admin.NewQueryBuilder()
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error) {
|
||||
data := map[string]interface{}{
|
||||
"is_used": used,
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := admin.NewQueryBuilder()
|
||||
|
||||
@@ -25,7 +25,7 @@ func (s *service) Create(ctx core.Context, authorizedData *CreateAuthorizedData)
|
||||
model.BusinessSecret = secret
|
||||
model.BusinessDeveloper = authorizedData.BusinessDeveloper
|
||||
model.Remark = authorizedData.Remark
|
||||
model.CreatedUser = ctx.UserName()
|
||||
model.CreatedUser = ctx.SessionUserInfo().UserName
|
||||
model.IsUsed = 1
|
||||
model.IsDeleted = -1
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ func (s *service) CreateAPI(ctx core.Context, authorizedAPIData *CreateAuthorize
|
||||
model.BusinessKey = authorizedAPIData.BusinessKey
|
||||
model.Method = authorizedAPIData.Method
|
||||
model.Api = authorizedAPIData.API
|
||||
model.CreatedUser = ctx.UserName()
|
||||
model.CreatedUser = ctx.SessionUserInfo().UserName
|
||||
model.IsDeleted = -1
|
||||
|
||||
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
|
||||
@@ -23,7 +23,7 @@ func (s *service) Delete(ctx core.Context, id int32) (err error) {
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := authorized.NewQueryBuilder()
|
||||
|
||||
@@ -23,7 +23,7 @@ func (s *service) DeleteAPI(ctx core.Context, id int32) (err error) {
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := authorized_api.NewQueryBuilder()
|
||||
|
||||
@@ -2,7 +2,6 @@ package authorized
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
@@ -68,7 +67,7 @@ func (s *service) DetailByKey(ctx core.Context, key string) (cacheData *CacheAut
|
||||
|
||||
cacheDataByte, _ := json.Marshal(cacheData)
|
||||
|
||||
err = s.cache.Set(cacheKey, string(cacheDataByte), time.Hour*24, redis.WithTrace(ctx.Trace()))
|
||||
err = s.cache.Set(cacheKey, string(cacheDataByte), configs.LoginSessionTTL, redis.WithTrace(ctx.Trace()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error)
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_used": used,
|
||||
"updated_user": ctx.UserName(),
|
||||
"updated_user": ctx.SessionUserInfo().UserName,
|
||||
}
|
||||
|
||||
qb := authorized.NewQueryBuilder()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user