diff --git a/Dockerfile b/Dockerfile
index 8663cad..4776560 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -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 .
diff --git a/cmd/handlergen/main.go b/cmd/handlergen/main.go
index d005778..097abca 100644
--- a/cmd/handlergen/main.go
+++ b/cmd/handlergen/main.go
@@ -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()
diff --git a/configs/constants.go b/configs/constants.go
index 1a253ae..ae5d98b 100644
--- a/configs/constants.go
+++ b/configs/constants.go
@@ -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
)
diff --git a/deploy/loki/loki.yaml b/deployments/loki/loki.yaml
similarity index 100%
rename from deploy/loki/loki.yaml
rename to deployments/loki/loki.yaml
diff --git a/deploy/loki/promtail.yaml b/deployments/loki/promtail.yaml
similarity index 100%
rename from deploy/loki/promtail.yaml
rename to deployments/loki/promtail.yaml
diff --git a/deploy/prometheus/prometheus.yml b/deployments/prometheus/prometheus.yml
similarity index 100%
rename from deploy/prometheus/prometheus.yml
rename to deployments/prometheus/prometheus.yml
diff --git a/docs/docs.go b/docs/docs.go
index 629dd36..8a5d1d9 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -29,9 +29,14 @@ var doc = `{
"paths": {
"/api/admin": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "管理员列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -43,15 +48,19 @@ var doc = `{
"parameters": [
{
"type": "integer",
+ "default": 1,
"description": "第几页",
"name": "page",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
- "type": "string",
+ "type": "integer",
+ "default": 10,
"description": "每页显示条数",
"name": "page_size",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
"type": "string",
@@ -88,9 +97,14 @@ var doc = `{
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "新增管理员",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -123,7 +137,7 @@ var doc = `{
},
{
"type": "string",
- "description": "密码",
+ "description": "MD5后的密码",
"name": "password",
"in": "formData",
"required": true
@@ -147,9 +161,14 @@ var doc = `{
},
"/api/admin/info": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "管理员详情",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -174,56 +193,16 @@ var doc = `{
}
}
},
- "/api/admin/login": {
- "post": {
- "description": "管理员登录",
- "consumes": [
- "multipart/form-data"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "API.admin"
- ],
- "summary": "管理员登录",
- "parameters": [
- {
- "type": "string",
- "description": "用户名",
- "name": "username",
- "in": "formData",
- "required": true
- },
- {
- "type": "string",
- "description": "密码",
- "name": "password",
- "in": "formData",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/admin.loginResponse"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/code.Failure"
- }
- }
- }
- }
- },
"/api/admin/logout": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "管理员登出",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -250,9 +229,14 @@ var doc = `{
},
"/api/admin/menu": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "提交菜单授权",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -293,11 +277,16 @@ var doc = `{
}
}
},
- "/api/admin/menu/:id": {
+ "/api/admin/menu/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "菜单授权列表",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -333,9 +322,14 @@ var doc = `{
},
"/api/admin/modify_password": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "修改密码",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -378,9 +372,14 @@ var doc = `{
},
"/api/admin/modify_personal_info": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "修改个人信息",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -423,9 +422,14 @@ var doc = `{
},
"/api/admin/offline": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "下线管理员",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -461,6 +465,11 @@ var doc = `{
},
"/api/admin/reset_password/{id}": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "重置密码",
"consumes": [
"application/json"
@@ -499,9 +508,14 @@ var doc = `{
},
"/api/admin/used": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新管理员为启用/禁用",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -544,6 +558,11 @@ var doc = `{
},
"/api/admin/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除管理员",
"consumes": [
"application/json"
@@ -582,9 +601,14 @@ var doc = `{
},
"/api/authorized": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "调用方列表",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -596,15 +620,19 @@ var doc = `{
"parameters": [
{
"type": "integer",
+ "default": 1,
"description": "第几页",
"name": "page",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
- "type": "string",
+ "type": "integer",
+ "default": 10,
"description": "每页显示条数",
"name": "page_size",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
"type": "string",
@@ -647,9 +675,14 @@ var doc = `{
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "新增调用方",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -699,9 +732,14 @@ var doc = `{
},
"/api/authorized/used": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新调用方为启用/禁用",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -713,7 +751,7 @@ var doc = `{
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashID",
"name": "id",
"in": "formData",
"required": true
@@ -744,6 +782,11 @@ var doc = `{
},
"/api/authorized/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除调用方",
"consumes": [
"application/json"
@@ -782,9 +825,14 @@ var doc = `{
},
"/api/authorized_api": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "调用方接口地址列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -818,9 +866,14 @@ var doc = `{
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "授权调用方接口地址",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -870,6 +923,11 @@ var doc = `{
},
"/api/authorized_api/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除调用方接口地址",
"consumes": [
"application/json"
@@ -908,9 +966,14 @@ var doc = `{
},
"/api/config/email": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "修改邮件配置",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -974,9 +1037,14 @@ var doc = `{
},
"/api/cron": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "任务列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -988,15 +1056,19 @@ var doc = `{
"parameters": [
{
"type": "integer",
+ "default": 1,
"description": "第几页",
"name": "page",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
- "type": "string",
+ "type": "integer",
+ "default": 10,
"description": "每页显示条数",
"name": "page_size",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
"type": "string",
@@ -1033,9 +1105,14 @@ var doc = `{
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "创建任务",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1155,8 +1232,63 @@ var doc = `{
}
}
},
- "/api/cron/:id": {
+ "/api/cron/used": {
+ "patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
+ "description": "更新任务为启用/禁用",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "API.cron"
+ ],
+ "summary": "更新任务为启用/禁用",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "hashID",
+ "name": "id",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "是否启用 1:是 -1:否",
+ "name": "used",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/cron.updateUsedResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
+ },
+ "/api/cron/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "获取单条任务详情",
"consumes": [
"application/json"
@@ -1192,93 +1324,15 @@ var doc = `{
}
}
},
- "patch": {
- "description": "手动执行单条任务",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "API.cron"
- ],
- "summary": "手动执行单条任务",
- "parameters": [
- {
- "type": "string",
- "description": "hashId",
- "name": "id",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/cron.detailResponse"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/code.Failure"
- }
- }
- }
- }
- },
- "/api/cron/used": {
- "patch": {
- "description": "更新任务为启用/禁用",
- "consumes": [
- "multipart/form-data"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "API.cron"
- ],
- "summary": "更新任务为启用/禁用",
- "parameters": [
- {
- "type": "string",
- "description": "Hashid",
- "name": "id",
- "in": "formData",
- "required": true
- },
- {
- "type": "integer",
- "description": "是否启用 1:是 -1:否",
- "name": "used",
- "in": "formData",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/cron.updateUsedResponse"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/code.Failure"
- }
- }
- }
- }
- },
- "/api/cron/{id}": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "编辑任务",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1290,7 +1344,7 @@ var doc = `{
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashID",
"name": "id",
"in": "formData",
"required": true
@@ -1403,13 +1457,109 @@ var doc = `{
}
}
}
+ },
+ "patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
+ "description": "手动执行单条任务",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "API.cron"
+ ],
+ "summary": "手动执行单条任务",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "hashId",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/cron.detailResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
+ },
+ "/api/login": {
+ "post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
+ "description": "管理员登录",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "API.admin"
+ ],
+ "summary": "管理员登录",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "用户名",
+ "name": "username",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "MD5后的密码",
+ "name": "password",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/admin.loginResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
}
},
"/api/menu": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "菜单列表",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1434,9 +1584,14 @@ var doc = `{
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "创建/编辑菜单",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1474,9 +1629,14 @@ var doc = `{
},
"/api/menu/sort": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新菜单排序",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1488,7 +1648,7 @@ var doc = `{
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashId",
"name": "id",
"in": "formData",
"required": true
@@ -1519,9 +1679,14 @@ var doc = `{
},
"/api/menu/used": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新菜单为启用/禁用",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1533,7 +1698,7 @@ var doc = `{
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashId",
"name": "id",
"in": "formData",
"required": true
@@ -1564,9 +1729,14 @@ var doc = `{
},
"/api/menu/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "菜单详情",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1600,6 +1770,11 @@ var doc = `{
}
},
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除菜单",
"consumes": [
"application/json"
@@ -1638,9 +1813,14 @@ var doc = `{
},
"/api/menu_action": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "功能权限列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1674,9 +1854,14 @@ var doc = `{
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "创建功能权限",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1726,6 +1911,11 @@ var doc = `{
},
"/api/menu_action/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除功能权限",
"consumes": [
"application/json"
@@ -1764,9 +1954,14 @@ var doc = `{
},
"/api/tool/cache/clear": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "清空缓存",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1802,9 +1997,14 @@ var doc = `{
},
"/api/tool/cache/search": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "查询缓存",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1840,9 +2040,14 @@ var doc = `{
},
"/api/tool/data/dbs": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "查询 DB",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1869,9 +2074,14 @@ var doc = `{
},
"/api/tool/data/mysql": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "执行 SQL 语句",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1921,9 +2131,14 @@ var doc = `{
},
"/api/tool/data/tables": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "查询 Table",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1959,9 +2174,14 @@ var doc = `{
},
"/api/tool/hashids/decode/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "HashIds 解密",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1997,9 +2217,14 @@ var doc = `{
},
"/api/tool/hashids/encode/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "HashIds 加密",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -2035,9 +2260,14 @@ var doc = `{
},
"/api/tool/send_message": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "发送消息",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -2070,6 +2300,103 @@ var doc = `{
}
}
}
+ },
+ "/helper/md5/{str}": {
+ "get": {
+ "description": "加密",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Helper"
+ ],
+ "summary": "加密",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "需要加密的字符串",
+ "name": "str",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/helper.md5Response"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
+ },
+ "/helper/sign": {
+ "post": {
+ "description": "签名",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Helper"
+ ],
+ "summary": "签名",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "调用方 KEY",
+ "name": "key",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "请求路径 (不附带 querystring),例如:/api/login",
+ "name": "path",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "请求方式,例如:POST",
+ "name": "method",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "请求参数,例如:username=tom\u0026password=123456",
+ "name": "params",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/helper.signResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
}
},
"definitions": {
@@ -2687,6 +3014,28 @@ var doc = `{
}
}
},
+ "helper.md5Response": {
+ "type": "object",
+ "properties": {
+ "md5_str": {
+ "description": "MD5后的字符串",
+ "type": "string"
+ }
+ }
+ },
+ "helper.signResponse": {
+ "type": "object",
+ "properties": {
+ "authorization": {
+ "description": "签名信息-Authorization",
+ "type": "string"
+ },
+ "authorization_date": {
+ "description": "签名信息-Authorization-Date",
+ "type": "string"
+ }
+ }
+ },
"menu.createActionResponse": {
"type": "object",
"properties": {
@@ -3004,6 +3353,13 @@ var doc = `{
}
}
}
+ },
+ "securityDefinitions": {
+ "LoginToken": {
+ "type": "apiKey",
+ "name": "token",
+ "in": "header"
+ }
}
}`
@@ -3019,8 +3375,8 @@ type swaggerInfo struct {
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = swaggerInfo{
Version: "2.0",
- Host: "127.0.0.1:9999",
- BasePath: "",
+ Host: "",
+ BasePath: "/",
Schemes: []string{},
Title: "swagger 接口文档",
Description: "",
diff --git a/docs/swagger.json b/docs/swagger.json
index 2b07639..e148093 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -9,13 +9,18 @@
},
"version": "2.0"
},
- "host": "127.0.0.1:9999",
+ "basePath": "/",
"paths": {
"/api/admin": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "管理员列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -27,15 +32,19 @@
"parameters": [
{
"type": "integer",
+ "default": 1,
"description": "第几页",
"name": "page",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
- "type": "string",
+ "type": "integer",
+ "default": 10,
"description": "每页显示条数",
"name": "page_size",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
"type": "string",
@@ -72,9 +81,14 @@
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "新增管理员",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -107,7 +121,7 @@
},
{
"type": "string",
- "description": "密码",
+ "description": "MD5后的密码",
"name": "password",
"in": "formData",
"required": true
@@ -131,9 +145,14 @@
},
"/api/admin/info": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "管理员详情",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -158,56 +177,16 @@
}
}
},
- "/api/admin/login": {
- "post": {
- "description": "管理员登录",
- "consumes": [
- "multipart/form-data"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "API.admin"
- ],
- "summary": "管理员登录",
- "parameters": [
- {
- "type": "string",
- "description": "用户名",
- "name": "username",
- "in": "formData",
- "required": true
- },
- {
- "type": "string",
- "description": "密码",
- "name": "password",
- "in": "formData",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/admin.loginResponse"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/code.Failure"
- }
- }
- }
- }
- },
"/api/admin/logout": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "管理员登出",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -234,9 +213,14 @@
},
"/api/admin/menu": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "提交菜单授权",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -277,11 +261,16 @@
}
}
},
- "/api/admin/menu/:id": {
+ "/api/admin/menu/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "菜单授权列表",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -317,9 +306,14 @@
},
"/api/admin/modify_password": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "修改密码",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -362,9 +356,14 @@
},
"/api/admin/modify_personal_info": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "修改个人信息",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -407,9 +406,14 @@
},
"/api/admin/offline": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "下线管理员",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -445,6 +449,11 @@
},
"/api/admin/reset_password/{id}": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "重置密码",
"consumes": [
"application/json"
@@ -483,9 +492,14 @@
},
"/api/admin/used": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新管理员为启用/禁用",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -528,6 +542,11 @@
},
"/api/admin/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除管理员",
"consumes": [
"application/json"
@@ -566,9 +585,14 @@
},
"/api/authorized": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "调用方列表",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -580,15 +604,19 @@
"parameters": [
{
"type": "integer",
+ "default": 1,
"description": "第几页",
"name": "page",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
- "type": "string",
+ "type": "integer",
+ "default": 10,
"description": "每页显示条数",
"name": "page_size",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
"type": "string",
@@ -631,9 +659,14 @@
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "新增调用方",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -683,9 +716,14 @@
},
"/api/authorized/used": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新调用方为启用/禁用",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -697,7 +735,7 @@
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashID",
"name": "id",
"in": "formData",
"required": true
@@ -728,6 +766,11 @@
},
"/api/authorized/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除调用方",
"consumes": [
"application/json"
@@ -766,9 +809,14 @@
},
"/api/authorized_api": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "调用方接口地址列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -802,9 +850,14 @@
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "授权调用方接口地址",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -854,6 +907,11 @@
},
"/api/authorized_api/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除调用方接口地址",
"consumes": [
"application/json"
@@ -892,9 +950,14 @@
},
"/api/config/email": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "修改邮件配置",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -958,9 +1021,14 @@
},
"/api/cron": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "任务列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -972,15 +1040,19 @@
"parameters": [
{
"type": "integer",
+ "default": 1,
"description": "第几页",
"name": "page",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
- "type": "string",
+ "type": "integer",
+ "default": 10,
"description": "每页显示条数",
"name": "page_size",
- "in": "query"
+ "in": "query",
+ "required": true
},
{
"type": "string",
@@ -1017,9 +1089,14 @@
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "创建任务",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1139,8 +1216,63 @@
}
}
},
- "/api/cron/:id": {
+ "/api/cron/used": {
+ "patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
+ "description": "更新任务为启用/禁用",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "API.cron"
+ ],
+ "summary": "更新任务为启用/禁用",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "hashID",
+ "name": "id",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "是否启用 1:是 -1:否",
+ "name": "used",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/cron.updateUsedResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
+ },
+ "/api/cron/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "获取单条任务详情",
"consumes": [
"application/json"
@@ -1176,93 +1308,15 @@
}
}
},
- "patch": {
- "description": "手动执行单条任务",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "API.cron"
- ],
- "summary": "手动执行单条任务",
- "parameters": [
- {
- "type": "string",
- "description": "hashId",
- "name": "id",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/cron.detailResponse"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/code.Failure"
- }
- }
- }
- }
- },
- "/api/cron/used": {
- "patch": {
- "description": "更新任务为启用/禁用",
- "consumes": [
- "multipart/form-data"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "API.cron"
- ],
- "summary": "更新任务为启用/禁用",
- "parameters": [
- {
- "type": "string",
- "description": "Hashid",
- "name": "id",
- "in": "formData",
- "required": true
- },
- {
- "type": "integer",
- "description": "是否启用 1:是 -1:否",
- "name": "used",
- "in": "formData",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/cron.updateUsedResponse"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/code.Failure"
- }
- }
- }
- }
- },
- "/api/cron/{id}": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "编辑任务",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1274,7 +1328,7 @@
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashID",
"name": "id",
"in": "formData",
"required": true
@@ -1387,13 +1441,109 @@
}
}
}
+ },
+ "patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
+ "description": "手动执行单条任务",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "API.cron"
+ ],
+ "summary": "手动执行单条任务",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "hashId",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/cron.detailResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
+ },
+ "/api/login": {
+ "post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
+ "description": "管理员登录",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "API.admin"
+ ],
+ "summary": "管理员登录",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "用户名",
+ "name": "username",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "MD5后的密码",
+ "name": "password",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/admin.loginResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
}
},
"/api/menu": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "菜单列表",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1418,9 +1568,14 @@
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "创建/编辑菜单",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1458,9 +1613,14 @@
},
"/api/menu/sort": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新菜单排序",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1472,7 +1632,7 @@
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashId",
"name": "id",
"in": "formData",
"required": true
@@ -1503,9 +1663,14 @@
},
"/api/menu/used": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "更新菜单为启用/禁用",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1517,7 +1682,7 @@
"parameters": [
{
"type": "string",
- "description": "Hashid",
+ "description": "hashId",
"name": "id",
"in": "formData",
"required": true
@@ -1548,9 +1713,14 @@
},
"/api/menu/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "菜单详情",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1584,6 +1754,11 @@
}
},
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除菜单",
"consumes": [
"application/json"
@@ -1622,9 +1797,14 @@
},
"/api/menu_action": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "功能权限列表",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1658,9 +1838,14 @@
}
},
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "创建功能权限",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1710,6 +1895,11 @@
},
"/api/menu_action/{id}": {
"delete": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "删除功能权限",
"consumes": [
"application/json"
@@ -1748,9 +1938,14 @@
},
"/api/tool/cache/clear": {
"patch": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "清空缓存",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1786,9 +1981,14 @@
},
"/api/tool/cache/search": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "查询缓存",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1824,9 +2024,14 @@
},
"/api/tool/data/dbs": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "查询 DB",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1853,9 +2058,14 @@
},
"/api/tool/data/mysql": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "执行 SQL 语句",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1905,9 +2115,14 @@
},
"/api/tool/data/tables": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "查询 Table",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1943,9 +2158,14 @@
},
"/api/tool/hashids/decode/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "HashIds 解密",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -1981,9 +2201,14 @@
},
"/api/tool/hashids/encode/{id}": {
"get": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "HashIds 加密",
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -2019,9 +2244,14 @@
},
"/api/tool/send_message": {
"post": {
+ "security": [
+ {
+ "LoginToken": []
+ }
+ ],
"description": "发送消息",
"consumes": [
- "multipart/form-data"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
@@ -2054,6 +2284,103 @@
}
}
}
+ },
+ "/helper/md5/{str}": {
+ "get": {
+ "description": "加密",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Helper"
+ ],
+ "summary": "加密",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "需要加密的字符串",
+ "name": "str",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/helper.md5Response"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
+ },
+ "/helper/sign": {
+ "post": {
+ "description": "签名",
+ "consumes": [
+ "application/x-www-form-urlencoded"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Helper"
+ ],
+ "summary": "签名",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "调用方 KEY",
+ "name": "key",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "请求路径 (不附带 querystring),例如:/api/login",
+ "name": "path",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "请求方式,例如:POST",
+ "name": "method",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "请求参数,例如:username=tom\u0026password=123456",
+ "name": "params",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/helper.signResponse"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/code.Failure"
+ }
+ }
+ }
+ }
}
},
"definitions": {
@@ -2671,6 +2998,28 @@
}
}
},
+ "helper.md5Response": {
+ "type": "object",
+ "properties": {
+ "md5_str": {
+ "description": "MD5后的字符串",
+ "type": "string"
+ }
+ }
+ },
+ "helper.signResponse": {
+ "type": "object",
+ "properties": {
+ "authorization": {
+ "description": "签名信息-Authorization",
+ "type": "string"
+ },
+ "authorization_date": {
+ "description": "签名信息-Authorization-Date",
+ "type": "string"
+ }
+ }
+ },
"menu.createActionResponse": {
"type": "object",
"properties": {
@@ -2988,5 +3337,12 @@
}
}
}
+ },
+ "securityDefinitions": {
+ "LoginToken": {
+ "type": "apiKey",
+ "name": "token",
+ "in": "header"
+ }
}
}
\ No newline at end of file
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index a8657ba..d72d09b 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -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"
diff --git a/internal/alert/alert.go b/internal/alert/alert.go
new file mode 100644
index 0000000..a2f1eb1
--- /dev/null
+++ b/internal/alert/alert.go
@@ -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
+ }
+}
diff --git a/internal/pkg/notify/templates/panic-mail.go b/internal/alert/email_template.go
similarity index 84%
rename from internal/pkg/notify/templates/panic-mail.go
rename to internal/alert/email_template.go
index 490b100..a21fd21 100644
--- a/internal/pkg/notify/templates/panic-mail.go
+++ b/internal/alert/email_template.go
@@ -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 = `
@@ -27,7 +75,7 @@ const PanicMail = `
|
- 系统异常
+ 系统告警
|
diff --git a/internal/api/admin/func_create.go b/internal/api/admin/func_create.go
index 7da0032..9e6eb76 100755
--- a/internal/api/admin/func_create.go
+++ b/internal/api/admin/func_create.go
@@ -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
}
diff --git a/internal/api/admin/func_createadminmenu.go b/internal/api/admin/func_createadminmenu.go
index 7789266..7ca7808 100755
--- a/internal/api/admin/func_createadminmenu.go
+++ b/internal/api/admin/func_createadminmenu.go
@@ -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
}
diff --git a/internal/api/admin/func_delete.go b/internal/api/admin/func_delete.go
index c42fcf5..45b337e 100755
--- a/internal/api/admin/func_delete.go
+++ b/internal/api/admin/func_delete.go
@@ -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
}
diff --git a/internal/api/admin/func_detail.go b/internal/api/admin/func_detail.go
index 6a8d903..4477253 100644
--- a/internal/api/admin/func_detail.go
+++ b/internal/api/admin/func_detail.go
@@ -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)
}
}
diff --git a/internal/api/admin/func_list.go b/internal/api/admin/func_list.go
index b623077..747058e 100755
--- a/internal/api/admin/func_list.go
+++ b/internal/api/admin/func_list.go
@@ -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
}
diff --git a/internal/api/admin/func_listadminmenu.go b/internal/api/admin/func_listadminmenu.go
index 68db90d..2864eb5 100755
--- a/internal/api/admin/func_listadminmenu.go
+++ b/internal/api/admin/func_listadminmenu.go
@@ -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
}
diff --git a/internal/api/admin/func_login.go b/internal/api/admin/func_login.go
index 8be2fbb..ab0e798 100644
--- a/internal/api/admin/func_login.go
+++ b/internal/api/admin/func_login.go
@@ -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
}
diff --git a/internal/api/admin/func_logout.go b/internal/api/admin/func_logout.go
index ab52467..fbc9930 100644
--- a/internal/api/admin/func_logout.go
+++ b/internal/api/admin/func_logout.go
@@ -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
}
diff --git a/internal/api/admin/func_modifypassword.go b/internal/api/admin/func_modifypassword.go
index f455b03..6150f6f 100644
--- a/internal/api/admin/func_modifypassword.go
+++ b/internal/api/admin/func_modifypassword.go
@@ -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)
}
}
diff --git a/internal/api/admin/func_modifypersonalinfo.go b/internal/api/admin/func_modifypersonalinfo.go
index a3533f5..74db8c1 100644
--- a/internal/api/admin/func_modifypersonalinfo.go
+++ b/internal/api/admin/func_modifypersonalinfo.go
@@ -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)
}
}
diff --git a/internal/api/admin/func_offline.go b/internal/api/admin/func_offline.go
index 44ba9c0..8bc9f0e 100755
--- a/internal/api/admin/func_offline.go
+++ b/internal/api/admin/func_offline.go
@@ -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)),
diff --git a/internal/api/admin/func_resetpassword.go b/internal/api/admin/func_resetpassword.go
index 0764d33..046587f 100755
--- a/internal/api/admin/func_resetpassword.go
+++ b/internal/api/admin/func_resetpassword.go
@@ -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
}
diff --git a/internal/api/admin/func_updateused.go b/internal/api/admin/func_updateused.go
index 70e4052..feff8f7 100755
--- a/internal/api/admin/func_updateused.go
+++ b/internal/api/admin/func_updateused.go
@@ -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
}
diff --git a/internal/api/admin/handler.go b/internal/api/admin/handler.go
index 4d1a46e..ada7eda 100644
--- a/internal/api/admin/handler.go
+++ b/internal/api/admin/handler.go
@@ -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
}
diff --git a/internal/api/authorized/func_create.go b/internal/api/authorized/func_create.go
index 8ceb194..4a888c7 100755
--- a/internal/api/authorized/func_create.go
+++ b/internal/api/authorized/func_create.go
@@ -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
}
diff --git a/internal/api/authorized/func_createapi.go b/internal/api/authorized/func_createapi.go
index 69d7fab..20905df 100755
--- a/internal/api/authorized/func_createapi.go
+++ b/internal/api/authorized/func_createapi.go
@@ -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
}
diff --git a/internal/api/authorized/func_delete.go b/internal/api/authorized/func_delete.go
index 4a6c6a8..41ac7df 100755
--- a/internal/api/authorized/func_delete.go
+++ b/internal/api/authorized/func_delete.go
@@ -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
}
diff --git a/internal/api/authorized/func_deleteapi.go b/internal/api/authorized/func_deleteapi.go
index c157a2b..97fccca 100755
--- a/internal/api/authorized/func_deleteapi.go
+++ b/internal/api/authorized/func_deleteapi.go
@@ -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
}
diff --git a/internal/api/authorized/func_list.go b/internal/api/authorized/func_list.go
index 16f19ff..54dbb2c 100755
--- a/internal/api/authorized/func_list.go
+++ b/internal/api/authorized/func_list.go
@@ -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
}
diff --git a/internal/api/authorized/func_listapi.go b/internal/api/authorized/func_listapi.go
index f0a0cb8..723653d 100755
--- a/internal/api/authorized/func_listapi.go
+++ b/internal/api/authorized/func_listapi.go
@@ -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
}
diff --git a/internal/api/authorized/func_updateused.go b/internal/api/authorized/func_updateused.go
index 38d1a13..ffe6dda 100755
--- a/internal/api/authorized/func_updateused.go
+++ b/internal/api/authorized/func_updateused.go
@@ -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
}
diff --git a/internal/api/config/func_email.go b/internal/api/config/func_email.go
index b42e7be..0794862 100755
--- a/internal/api/config/func_email.go
+++ b/internal/api/config/func_email.go
@@ -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
}
diff --git a/internal/api/cron/func_create.go b/internal/api/cron/func_create.go
index 812a06a..e57576c 100755
--- a/internal/api/cron/func_create.go
+++ b/internal/api/cron/func_create.go
@@ -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
}
diff --git a/internal/api/cron/func_detail.go b/internal/api/cron/func_detail.go
index 211ab17..47c4a71 100755
--- a/internal/api/cron/func_detail.go
+++ b/internal/api/cron/func_detail.go
@@ -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
}
diff --git a/internal/api/cron/func_execute.go b/internal/api/cron/func_execute.go
index f373ed6..60f56d7 100755
--- a/internal/api/cron/func_execute.go
+++ b/internal/api/cron/func_execute.go
@@ -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
}
diff --git a/internal/api/cron/func_list.go b/internal/api/cron/func_list.go
index 812db3d..0176c80 100755
--- a/internal/api/cron/func_list.go
+++ b/internal/api/cron/func_list.go
@@ -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
}
diff --git a/internal/api/cron/func_modify.go b/internal/api/cron/func_modify.go
index 82e5014..bb3ab37 100755
--- a/internal/api/cron/func_modify.go
+++ b/internal/api/cron/func_modify.go
@@ -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
}
diff --git a/internal/api/cron/func_updateused.go b/internal/api/cron/func_updateused.go
index 4772596..e81d5e1 100755
--- a/internal/api/cron/func_updateused.go
+++ b/internal/api/cron/func_updateused.go
@@ -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
}
diff --git a/internal/api/cron/handler.go b/internal/api/cron/handler.go
index f4b692b..7b6c66d 100644
--- a/internal/api/cron/handler.go
+++ b/internal/api/cron/handler.go
@@ -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
}
diff --git a/internal/api/helper/func_md5.go b/internal/api/helper/func_md5.go
new file mode 100755
index 0000000..caa2ebb
--- /dev/null
+++ b/internal/api/helper/func_md5.go
@@ -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)
+ }
+}
diff --git a/internal/api/helper/func_sign.go b/internal/api/helper/func_sign.go
new file mode 100755
index 0000000..c9fb3d9
--- /dev/null
+++ b/internal/api/helper/func_sign.go
@@ -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)
+ }
+}
diff --git a/internal/api/helper/handler.go b/internal/api/helper/handler.go
new file mode 100644
index 0000000..4e59169
--- /dev/null
+++ b/internal/api/helper/handler.go
@@ -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() {}
diff --git a/internal/api/menu/func_create.go b/internal/api/menu/func_create.go
index 04a667c..27f0596 100755
--- a/internal/api/menu/func_create.go
+++ b/internal/api/menu/func_create.go
@@ -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
}
diff --git a/internal/api/menu/func_createaction.go b/internal/api/menu/func_createaction.go
index 30864a7..cdc7878 100755
--- a/internal/api/menu/func_createaction.go
+++ b/internal/api/menu/func_createaction.go
@@ -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
}
diff --git a/internal/api/menu/func_delete.go b/internal/api/menu/func_delete.go
index da4fcd6..fc8c4a0 100755
--- a/internal/api/menu/func_delete.go
+++ b/internal/api/menu/func_delete.go
@@ -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
}
diff --git a/internal/api/menu/func_deleteaction.go b/internal/api/menu/func_deleteaction.go
index 8ee1889..cd4675c 100755
--- a/internal/api/menu/func_deleteaction.go
+++ b/internal/api/menu/func_deleteaction.go
@@ -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
}
diff --git a/internal/api/menu/func_detail.go b/internal/api/menu/func_detail.go
index d458853..c6f7b6b 100755
--- a/internal/api/menu/func_detail.go
+++ b/internal/api/menu/func_detail.go
@@ -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
}
diff --git a/internal/api/menu/func_list.go b/internal/api/menu/func_list.go
index e546cff..777097c 100755
--- a/internal/api/menu/func_list.go
+++ b/internal/api/menu/func_list.go
@@ -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
}
diff --git a/internal/api/menu/func_listaction.go b/internal/api/menu/func_listaction.go
index 4bf9b78..bd463c5 100755
--- a/internal/api/menu/func_listaction.go
+++ b/internal/api/menu/func_listaction.go
@@ -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
}
diff --git a/internal/api/menu/func_updatesort.go b/internal/api/menu/func_updatesort.go
index 628e122..1e38f0c 100755
--- a/internal/api/menu/func_updatesort.go
+++ b/internal/api/menu/func_updatesort.go
@@ -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
}
diff --git a/internal/api/menu/func_updateused.go b/internal/api/menu/func_updateused.go
index ae4d9f9..ba8d686 100755
--- a/internal/api/menu/func_updateused.go
+++ b/internal/api/menu/func_updateused.go
@@ -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
}
diff --git a/internal/api/tool/func_clearcache.go b/internal/api/tool/func_clearcache.go
index 5b7355f..e804da6 100644
--- a/internal/api/tool/func_clearcache.go
+++ b/internal/api/tool/func_clearcache.go
@@ -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)),
diff --git a/internal/api/tool/func_dbs.go b/internal/api/tool/func_dbs.go
index 0f97af6..118aead 100644
--- a/internal/api/tool/func_dbs.go
+++ b/internal/api/tool/func_dbs.go
@@ -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)
diff --git a/internal/api/tool/func_hashidsdecode.go b/internal/api/tool/func_hashidsdecode.go
index 6bd2445..4863b66 100755
--- a/internal/api/tool/func_hashidsdecode.go
+++ b/internal/api/tool/func_hashidsdecode.go
@@ -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
}
diff --git a/internal/api/tool/func_hashidsencode.go b/internal/api/tool/func_hashidsencode.go
index 49b6210..d52d78e 100755
--- a/internal/api/tool/func_hashidsencode.go
+++ b/internal/api/tool/func_hashidsencode.go
@@ -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
}
diff --git a/internal/api/tool/func_searchcache.go b/internal/api/tool/func_searchcache.go
index fd9af20..1f2643b 100644
--- a/internal/api/tool/func_searchcache.go
+++ b/internal/api/tool/func_searchcache.go
@@ -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
}
diff --git a/internal/api/tool/func_searchmysql.go b/internal/api/tool/func_searchmysql.go
index 922af41..f7795f4 100644
--- a/internal/api/tool/func_searchmysql.go
+++ b/internal/api/tool/func_searchmysql.go
@@ -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
}
diff --git a/internal/api/tool/func_sendmessage.go b/internal/api/tool/func_sendmessage.go
index 6d52b9e..ca20f30 100644
--- a/internal/api/tool/func_sendmessage.go
+++ b/internal/api/tool/func_sendmessage.go
@@ -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
}
diff --git a/internal/api/tool/func_tables.go b/internal/api/tool/func_tables.go
index 9aecdfd..8f6cd4c 100644
--- a/internal/api/tool/func_tables.go
+++ b/internal/api/tool/func_tables.go
@@ -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
}
diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go
new file mode 100644
index 0000000..a32b7d2
--- /dev/null
+++ b/internal/metrics/metrics.go
@@ -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,
+ )
+ }
+}
diff --git a/internal/pkg/metrics/metrics.go b/internal/metrics/prometheus.go
similarity index 89%
rename from internal/pkg/metrics/metrics.go
rename to internal/metrics/prometheus.go
index 34e586d..bd0e581 100644
--- a/internal/pkg/metrics/metrics.go
+++ b/internal/metrics/prometheus.go
@@ -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),
diff --git a/internal/pkg/core/context.go b/internal/pkg/core/context.go
index 63b05cb..0d33ba9 100644
--- a/internal/pkg/core/context.go
+++ b/internal/pkg/core/context.go
@@ -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()
diff --git a/internal/pkg/core/core.go b/internal/pkg/core/core.go
index 385b7a2..266f963 100644
--- a/internal/pkg/core/core.go
+++ b/internal/pkg/core/core.go
@@ -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()
+ // 判断是否需要发送告警通知
+ 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(),
+ })
+ }
}
- ctx.JSON(err.GetHttpCode(), &code.Failure{
+ multierr.AppendInto(&abortErr, err.StackError())
+ businessCode = err.BusinessCode()
+ businessCodeMsg = err.Message()
+ response = &code.Failure{
Code: businessCode,
Message: businessCodeMsg,
- })
- }
- } else {
- 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)
+ ctx.JSON(err.HTTPCode(), response)
}
}
+ // endregion
- graphResponse = context.getGraphPayload()
+ // region 正确返回
+ response = context.getPayload()
+ if response != nil {
+ ctx.JSON(http.StatusOK, response)
+ }
+ // endregion
- 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")
{
// 健康检查
diff --git a/internal/pkg/core/error.go b/internal/pkg/core/error.go
new file mode 100644
index 0000000..254736d
--- /dev/null
+++ b/internal/pkg/core/error.go
@@ -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
+}
diff --git a/internal/pkg/notify/notify.go b/internal/pkg/notify/notify.go
deleted file mode 100644
index 6937ab4..0000000
--- a/internal/pkg/notify/notify.go
+++ /dev/null
@@ -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
-}
diff --git a/internal/pkg/notify/template.go b/internal/pkg/notify/template.go
deleted file mode 100644
index 283f126..0000000
--- a/internal/pkg/notify/template.go
+++ /dev/null
@@ -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
-}
diff --git a/internal/proposal/alert.go b/internal/proposal/alert.go
new file mode 100644
index 0000000..e8f0669
--- /dev/null
+++ b/internal/proposal/alert.go
@@ -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)
diff --git a/internal/proposal/metrics.go b/internal/proposal/metrics.go
new file mode 100644
index 0000000..a887163
--- /dev/null
+++ b/internal/proposal/metrics.go
@@ -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)
diff --git a/internal/proposal/session.go b/internal/proposal/session.go
new file mode 100644
index 0000000..dc43c43
--- /dev/null
+++ b/internal/proposal/session.go
@@ -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
+}
diff --git a/internal/render/admin/admin.go b/internal/render/admin/admin.go
index 24c54f8..7103bab 100644
--- a/internal/render/admin/admin.go
+++ b/internal/render/admin/admin.go
@@ -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
}
diff --git a/internal/render/authorized/authorized.go b/internal/render/authorized/authorized.go
index dd0a50f..ac8b666 100644
--- a/internal/render/authorized/authorized.go
+++ b/internal/render/authorized/authorized.go
@@ -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
}
diff --git a/internal/render/cron/cron.go b/internal/render/cron/cron.go
index dd862b1..29b2d5e 100644
--- a/internal/render/cron/cron.go
+++ b/internal/render/cron/cron.go
@@ -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
}
diff --git a/internal/render/install/execute.go b/internal/render/install/execute.go
index 37e227f..9bf0e02 100644
--- a/internal/render/install/execute.go
+++ b/internal/render/install/execute.go
@@ -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
}
diff --git a/internal/render/upgrade/execute.go b/internal/render/upgrade/execute.go
index 4ce1196..79f5cc4 100644
--- a/internal/render/upgrade/execute.go
+++ b/internal/render/upgrade/execute.go
@@ -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
}
diff --git a/internal/repository/mysql/authorized/model.go b/internal/repository/mysql/authorized/model.go
new file mode 100644
index 0000000..c18c9d0
--- /dev/null
+++ b/internal/repository/mysql/authorized/model.go
@@ -0,0 +1,6 @@
+package authorized
+
+const (
+ IsUsedYES = 1 // 启用
+ IsUsedNo = -1 // 禁用
+)
diff --git a/internal/repository/mysql/plugin.go b/internal/repository/mysql/plugin.go
index 2c0906a..40ee7bd 100644
--- a/internal/repository/mysql/plugin.go
+++ b/internal/repository/mysql/plugin.go
@@ -74,7 +74,10 @@ func after(db *gorm.DB) {
sqlInfo.Stack = utils.FileWithLineNum()
sqlInfo.Rows = db.Statement.RowsAffected
sqlInfo.CostSeconds = time.Since(ts).Seconds()
- ctx.Trace.AppendSQL(sqlInfo)
+
+ if ctx.Trace != nil {
+ ctx.Trace.AppendSQL(sqlInfo)
+ }
return
}
diff --git a/internal/router/interceptor/check_login.go b/internal/router/interceptor/check_login.go
new file mode 100644
index 0000000..fd509e2
--- /dev/null
+++ b/internal/router/interceptor/check_login.go
@@ -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
+}
diff --git a/internal/router/middleware/middle_rbac.go b/internal/router/interceptor/check_rbac.go
similarity index 58%
rename from internal/router/middleware/middle_rbac.go
rename to internal/router/interceptor/check_rbac.go
index 71e7914..d118e41 100644
--- a/internal/router/middleware/middle_rbac.go
+++ b/internal/router/interceptor/check_rbac.go
@@ -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
}
diff --git a/internal/router/middleware/middle_signature.go b/internal/router/interceptor/check_signature.go
similarity index 51%
rename from internal/router/middleware/middle_signature.go
rename to internal/router/interceptor/check_signature.go
index b8a10f5..d375906 100644
--- a/internal/router/middleware/middle_signature.go
+++ b/internal/router/interceptor/check_signature.go
@@ -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
}
diff --git a/internal/router/middleware/middlerware.go b/internal/router/interceptor/interceptor.go
similarity index 54%
rename from internal/router/middleware/middlerware.go
rename to internal/router/interceptor/interceptor.go
index 7b0fcf1..4f12616 100644
--- a/internal/router/middleware/middlerware.go
+++ b/internal/router/interceptor/interceptor.go
@@ -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() {}
diff --git a/internal/router/middleware/middle_disablelog.go b/internal/router/middleware/middle_disablelog.go
deleted file mode 100644
index 73035b8..0000000
--- a/internal/router/middleware/middle_disablelog.go
+++ /dev/null
@@ -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)
- }
-}
diff --git a/internal/router/middleware/middle_token.go b/internal/router/middleware/middle_token.go
deleted file mode 100644
index fa6d670..0000000
--- a/internal/router/middleware/middle_token.go
+++ /dev/null
@@ -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
-}
diff --git a/internal/router/router.go b/internal/router/router.go
index e740bdc..ea08bf3 100644
--- a/internal/router/router.go
+++ b/internal/router/router.go
@@ -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"
@@ -16,12 +16,12 @@ import (
)
type resource struct {
- mux core.Mux
- logger *zap.Logger
- db mysql.Repo
- cache redis.Repo
- middles middleware.Middleware
- cronServer cron.Server
+ mux core.Mux
+ logger *zap.Logger
+ db mysql.Repo
+ cache redis.Repo
+ interceptors interceptor.Interceptor
+ cronServer cron.Server
}
type Server struct {
@@ -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)
diff --git a/internal/router/router_api.go b/internal/router/router_api.go
index 1163e45..368f136 100644
--- a/internal/router/router_api.go
+++ b/internal/router/router_api.go
@@ -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)
diff --git a/internal/router/router_render.go b/internal/router/router_render.go
index bb0cc68..ff1cf03 100644
--- a/internal/router/router_render.go
+++ b/internal/router/router_render.go
@@ -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())
diff --git a/internal/router/router_socket.go b/internal/router/router_socket.go
index e51b361..1217766 100644
--- a/internal/router/router_socket.go
+++ b/internal/router/router_socket.go
@@ -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())
diff --git a/internal/services/admin/service_create.go b/internal/services/admin/service_create.go
index 7a71df5..bd5e8a6 100644
--- a/internal/services/admin/service_create.go
+++ b/internal/services/admin/service_create.go
@@ -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
diff --git a/internal/services/admin/service_createmenu.go b/internal/services/admin/service_createmenu.go
index 4210b99..0342639 100644
--- a/internal/services/admin/service_createmenu.go
+++ b/internal/services/admin/service_createmenu.go
@@ -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 {
diff --git a/internal/services/admin/service_delete.go b/internal/services/admin/service_delete.go
index 0d3438b..7afc9cc 100644
--- a/internal/services/admin/service_delete.go
+++ b/internal/services/admin/service_delete.go
@@ -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()
diff --git a/internal/services/admin/service_modifypassword.go b/internal/services/admin/service_modifypassword.go
index 6e3f473..be97c10 100644
--- a/internal/services/admin/service_modifypassword.go
+++ b/internal/services/admin/service_modifypassword.go
@@ -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()
diff --git a/internal/services/admin/service_modifypersonalinfo.go b/internal/services/admin/service_modifypersonalinfo.go
index fe79e13..b9d2998 100644
--- a/internal/services/admin/service_modifypersonalinfo.go
+++ b/internal/services/admin/service_modifypersonalinfo.go
@@ -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()
diff --git a/internal/services/admin/service_resetpassword.go b/internal/services/admin/service_resetpassword.go
index 0caa919..a1aac26 100644
--- a/internal/services/admin/service_resetpassword.go
+++ b/internal/services/admin/service_resetpassword.go
@@ -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()
diff --git a/internal/services/admin/service_updateused.go b/internal/services/admin/service_updateused.go
index a4c4743..3c5b675 100644
--- a/internal/services/admin/service_updateused.go
+++ b/internal/services/admin/service_updateused.go
@@ -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()
diff --git a/internal/services/authorized/service_create.go b/internal/services/authorized/service_create.go
index 6215ec6..e07b775 100644
--- a/internal/services/authorized/service_create.go
+++ b/internal/services/authorized/service_create.go
@@ -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
diff --git a/internal/services/authorized/service_createapi.go b/internal/services/authorized/service_createapi.go
index c6614f0..22cdcbd 100644
--- a/internal/services/authorized/service_createapi.go
+++ b/internal/services/authorized/service_createapi.go
@@ -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()))
diff --git a/internal/services/authorized/service_delete.go b/internal/services/authorized/service_delete.go
index 24385ae..3cf8d23 100644
--- a/internal/services/authorized/service_delete.go
+++ b/internal/services/authorized/service_delete.go
@@ -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()
diff --git a/internal/services/authorized/service_deleteapi.go b/internal/services/authorized/service_deleteapi.go
index 5b36aad..778c0ea 100644
--- a/internal/services/authorized/service_deleteapi.go
+++ b/internal/services/authorized/service_deleteapi.go
@@ -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()
diff --git a/internal/services/authorized/service_detailbykey.go b/internal/services/authorized/service_detailbykey.go
index 672f161..d20891f 100644
--- a/internal/services/authorized/service_detailbykey.go
+++ b/internal/services/authorized/service_detailbykey.go
@@ -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
}
diff --git a/internal/services/authorized/service_updateused.go b/internal/services/authorized/service_updateused.go
index ee60e37..6bbc158 100644
--- a/internal/services/authorized/service_updateused.go
+++ b/internal/services/authorized/service_updateused.go
@@ -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()
diff --git a/internal/services/cron/service_create.go b/internal/services/cron/service_create.go
index 58a5503..e7cc94a 100644
--- a/internal/services/cron/service_create.go
+++ b/internal/services/cron/service_create.go
@@ -38,7 +38,7 @@ func (s *service) Create(ctx core.Context, createData *CreateCronTaskData) (id i
model.NotifyKeyword = createData.NotifyKeyword
model.Remark = createData.Remark
model.IsUsed = createData.IsUsed
- model.CreatedUser = ctx.UserName()
+ model.CreatedUser = ctx.SessionUserInfo().UserName
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
if err != nil {
diff --git a/internal/services/cron/service_modify.go b/internal/services/cron/service_modify.go
index 04e8726..9561d17 100644
--- a/internal/services/cron/service_modify.go
+++ b/internal/services/cron/service_modify.go
@@ -41,7 +41,7 @@ func (s *service) Modify(ctx core.Context, id int32, modifyData *ModifyCronTaskD
"notify_keyword": modifyData.NotifyKeyword,
"remark": modifyData.Remark,
"is_used": modifyData.IsUsed,
- "updated_user": ctx.UserName(),
+ "updated_user": ctx.SessionUserInfo().UserName,
}
qb := cron_task.NewQueryBuilder()
diff --git a/internal/services/cron/service_updateused.go b/internal/services/cron/service_updateused.go
index 7e3a521..0c2510b 100644
--- a/internal/services/cron/service_updateused.go
+++ b/internal/services/cron/service_updateused.go
@@ -11,7 +11,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 := cron_task.NewQueryBuilder()
diff --git a/internal/services/menu/service_create.go b/internal/services/menu/service_create.go
index 21e4408..5582348 100644
--- a/internal/services/menu/service_create.go
+++ b/internal/services/menu/service_create.go
@@ -20,7 +20,7 @@ func (s *service) Create(ctx core.Context, menuData *CreateMenuData) (id int32,
model.Link = menuData.Link
model.Icon = menuData.Icon
model.Level = menuData.Level
- model.CreatedUser = ctx.UserName()
+ model.CreatedUser = ctx.SessionUserInfo().UserName
model.IsUsed = 1
model.IsDeleted = -1
diff --git a/internal/services/menu/service_createaction.go b/internal/services/menu/service_createaction.go
index 18809a8..5846863 100644
--- a/internal/services/menu/service_createaction.go
+++ b/internal/services/menu/service_createaction.go
@@ -16,7 +16,7 @@ func (s *service) CreateAction(ctx core.Context, menuActionData *CreateMenuActio
model.MenuId = menuActionData.MenuId
model.Method = menuActionData.Method
model.Api = menuActionData.API
- model.CreatedUser = ctx.UserName()
+ model.CreatedUser = ctx.SessionUserInfo().UserName
model.IsDeleted = -1
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
diff --git a/internal/services/menu/service_delete.go b/internal/services/menu/service_delete.go
index 55d1eb8..0581c01 100644
--- a/internal/services/menu/service_delete.go
+++ b/internal/services/menu/service_delete.go
@@ -9,7 +9,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 := menu.NewQueryBuilder()
diff --git a/internal/services/menu/service_deleteaction.go b/internal/services/menu/service_deleteaction.go
index 1f430bb..27bf220 100644
--- a/internal/services/menu/service_deleteaction.go
+++ b/internal/services/menu/service_deleteaction.go
@@ -21,7 +21,7 @@ func (s *service) DeleteAction(ctx core.Context, id int32) (err error) {
data := map[string]interface{}{
"is_deleted": 1,
- "updated_user": ctx.UserName(),
+ "updated_user": ctx.SessionUserInfo().UserName,
}
qb := menu_action.NewQueryBuilder()
diff --git a/internal/services/menu/service_modify.go b/internal/services/menu/service_modify.go
index f04afbe..2fd16b2 100644
--- a/internal/services/menu/service_modify.go
+++ b/internal/services/menu/service_modify.go
@@ -17,7 +17,7 @@ func (s *service) Modify(ctx core.Context, id int32, menuData *UpdateMenuData) (
"name": menuData.Name,
"link": menuData.Link,
"icon": menuData.Icon,
- "updated_user": ctx.UserName(),
+ "updated_user": ctx.SessionUserInfo().UserName,
}
qb := menu.NewQueryBuilder()
diff --git a/internal/services/menu/service_updatesort.go b/internal/services/menu/service_updatesort.go
index dc2e414..87bb52d 100644
--- a/internal/services/menu/service_updatesort.go
+++ b/internal/services/menu/service_updatesort.go
@@ -9,7 +9,7 @@ import (
func (s *service) UpdateSort(ctx core.Context, id int32, sort int32) (err error) {
data := map[string]interface{}{
"sort": sort,
- "updated_user": ctx.UserName(),
+ "updated_user": ctx.SessionUserInfo().UserName,
}
qb := menu.NewQueryBuilder()
diff --git a/internal/services/menu/service_updateused.go b/internal/services/menu/service_updateused.go
index a4a5948..44609a4 100644
--- a/internal/services/menu/service_updateused.go
+++ b/internal/services/menu/service_updateused.go
@@ -9,7 +9,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 := menu.NewQueryBuilder()
diff --git a/main.go b/main.go
index 8764fa6..ec1573b 100644
--- a/main.go
+++ b/main.go
@@ -27,8 +27,11 @@ import (
// @license.name MIT
// @license.url https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE
-// @host 127.0.0.1:9999
-// @BasePath
+// @securityDefinitions.apikey LoginToken
+// @in header
+// @name token
+
+// @BasePath /
func main() {
// 初始化 access logger
accessLogger, err := logger.NewJSONLogger(
diff --git a/pkg/p/print.go b/pkg/debugs/print.go
similarity index 98%
rename from pkg/p/print.go
rename to pkg/debugs/print.go
index 2bebf22..eb0a158 100644
--- a/pkg/p/print.go
+++ b/pkg/debugs/print.go
@@ -1,4 +1,4 @@
-package p
+package debugs
import (
"fmt"
diff --git a/pkg/errno/errno.go b/pkg/errno/errno.go
deleted file mode 100644
index c52f70c..0000000
--- a/pkg/errno/errno.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package errno
-
-import (
- "encoding/json"
-
- "github.com/xinliangnote/go-gin-api/pkg/errors"
-)
-
-var _ Error = (*err)(nil)
-
-type Error interface {
- // i 为了避免被其他包实现
- i()
- // WithErr 设置错误信息
- WithErr(err error) Error
- // GetBusinessCode 获取 Business Code
- GetBusinessCode() int
- // GetHttpCode 获取 HTTP Code
- GetHttpCode() int
- // GetMsg 获取 Msg
- GetMsg() string
- // GetErr 获取错误信息
- GetErr() error
- // ToString 返回 JSON 格式的错误详情
- ToString() string
-}
-
-type err struct {
- HttpCode int // HTTP Code
- BusinessCode int // Business Code
- Message string // 描述信息
- Err error // 错误信息
-}
-
-func NewError(httpCode, businessCode int, msg string) Error {
- return &err{
- HttpCode: httpCode,
- BusinessCode: businessCode,
- Message: msg,
- }
-}
-
-func (e *err) i() {}
-
-func (e *err) WithErr(err error) Error {
- e.Err = errors.WithStack(err)
- return e
-}
-
-func (e *err) GetHttpCode() int {
- return e.HttpCode
-}
-
-func (e *err) GetBusinessCode() int {
- return e.BusinessCode
-}
-
-func (e *err) GetMsg() string {
- return e.Message
-}
-
-func (e *err) GetErr() error {
- return e.Err
-}
-
-// ToString 返回 JSON 格式的错误详情
-func (e *err) ToString() string {
- err := &struct {
- HttpCode int `json:"http_code"`
- BusinessCode int `json:"business_code"`
- Message string `json:"message"`
- }{
- HttpCode: e.HttpCode,
- BusinessCode: e.BusinessCode,
- Message: e.Message,
- }
-
- raw, _ := json.Marshal(err)
- return string(raw)
-}
diff --git a/pkg/trace/README.md b/pkg/trace/README.md
deleted file mode 100644
index 167349d..0000000
--- a/pkg/trace/README.md
+++ /dev/null
@@ -1,81 +0,0 @@
-## trace
-
-一个用于开发调试的辅助工具。
-
-可以实时显示当前页面的操作的请求信息、运行情况、SQL执行、错误提示等。
-
-- `trace.go` 主入口文件;
-- `dialog.go` 处理 third_party_requests 记录;
-- `debug.go` 处理 debug 记录;
-
-#### 数据格式
-
-##### trace_id
-
-当前 trace 的 ID,例如:938ff86be98439c6c1a7,便于搜索使用。
-
-##### request
-
-请求信息,会包括:
-
-- ttl 请求超时时间,例如:2s 或 un-limit
-- method 请求方式,例如:GET 或 POST
-- decoded_url 请求地址
-- header 请求头信息
-- body 请求体信息
-
-##### response
-
-- header 响应头信息
-- body 响应提信息
-- business_code 业务码,例如:10010
-- business_code_msg 业务码信息,例如:签名错误
-- http_code HTTP 状态码,例如:200
-- http_code_msg HTTP 状态码信息,例如:OK
-- cost_seconds 耗费时长:单位秒,比如 0.001105661
-
-##### third_party_requests
-
-每一个第三方 http 请求都会生成如下的一组数据,多个请求会生成多组数据。
-
-- request,同上 request 结构一致
-- response,同上 response 结构一致
-- success,是否成功,true 或 false
-- cost_seconds,耗费时长:单位秒
-
-注意:response 中的 business_code、business_code_msg 为空,因为各个第三方返回结构不同,这两个字段为空。
-
-##### sqls
-
-执行的 SQL 信息,多个 SQL 会记录多组数据。
-
-- timestamp,时间,格式:2006-01-02 15:04:05
-- stack,文件地址和行号
-- cost_seconds,执行时长,单位:秒
-- sql,SQL 语句
-- rows_affected,影响行数
-
-##### debugs
-
-- key 打印的标示
-- value 打印的值
-
-```cassandraql
-// 调试时,使用这个方法:
-p.Print("key", "value", p.WithTrace(c.Trace()))
-```
-
-只有参数中增加了 `p.WithTrace(c.Trace())`,才会记录到 `debugs` 中。
-
-##### success
-
-是否成功,true 或 false
-
-```cassandraql
-success = !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK
-```
-
-##### cost_seconds
-
-耗费时长:单位秒,比如 0.001105661
-