feat(*): go 后端项目脚手架
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.idea
|
||||
data
|
||||
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## Go + Gorm + Gin 后端开发脚手架
|
||||
|
||||
### 支持库
|
||||
- 数据库
|
||||
- 配置文件
|
||||
- 日志系统
|
||||
- `JWT`等工具类
|
||||
|
||||
21
cmd/cmd.go
Normal file
21
cmd/cmd.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zhilv666/navsite/internal/router"
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"github.com/zhilv666/navsite/pkg/db"
|
||||
"github.com/zhilv666/navsite/pkg/logger"
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
conf := config.NewConfig()
|
||||
|
||||
logger.Init(conf.Log)
|
||||
|
||||
db.InitDB(conf.Database, logger.GetLogger())
|
||||
|
||||
r := router.SetupRouter()
|
||||
r.Run(fmt.Sprintf(":%d", conf.Server.Port))
|
||||
}
|
||||
21
config.yaml
Normal file
21
config.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
server:
|
||||
debug: true
|
||||
port: 8080
|
||||
log:
|
||||
level: debug
|
||||
filepath: data\log.log
|
||||
max_size_mb: 10
|
||||
max_age_day: 7
|
||||
backups: 3
|
||||
compress: true
|
||||
database:
|
||||
driver: sqlite
|
||||
user: ""
|
||||
password: ""
|
||||
host: ""
|
||||
port: 0
|
||||
db_name: ""
|
||||
sqlite_db_path: data\sqlite.db
|
||||
jwt:
|
||||
secret_key: r0jkncyd46ptISEe
|
||||
expire_duration_hour: 2ns
|
||||
291
docs/docs.go
Normal file
291
docs/docs.go
Normal file
@@ -0,0 +1,291 @@
|
||||
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplate = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"termsOfService": "http://kmux.cn",
|
||||
"contact": {
|
||||
"name": "zhilv",
|
||||
"url": "www.kmux.cn",
|
||||
"email": "zhilv666@qq.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/api/v1/auth/login": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "用户登录",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "登录参数",
|
||||
"name": "login",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Req"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "登录成功",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-handler_LoginResp"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "登录失败",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/auth/register": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "用户注册",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "注册参数",
|
||||
"name": "register",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Req"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "注册成功",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-handler_Req"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "注册失败",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/user/{id}": {
|
||||
"get": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "获取指定 ID 用户",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "用户 ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "获取成功",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-model_User"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "获取失败",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"common.Response-any": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.Response-handler_LoginResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/handler.LoginResp"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.Response-handler_Req": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/handler.Req"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.Response-model_User": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.User"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.LoginResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...zYyfQ.bQeIyXvkOExxD4DAy5Eyjgwj9FbjE-AO6FCLF-YFGVA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Req": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"otp_code": {
|
||||
"type": "string",
|
||||
"example": "123456"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "123456"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.User": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"description": "禁用标志",
|
||||
"type": "boolean"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_admin": {
|
||||
"description": "true = 管理员",
|
||||
"type": "boolean"
|
||||
},
|
||||
"points": {
|
||||
"description": "积分",
|
||||
"type": "integer"
|
||||
},
|
||||
"sso_id": {
|
||||
"description": "OAuth2 唯一标识",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "邮箱注册",
|
||||
"type": "string"
|
||||
},
|
||||
"verified": {
|
||||
"description": "是否通过邮箱验证/管理员审核",
|
||||
"type": "boolean"
|
||||
},
|
||||
"verify_at": {
|
||||
"description": "验证时间",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "1.0",
|
||||
Host: "localhost:8080",
|
||||
BasePath: "/api/v1",
|
||||
Schemes: []string{},
|
||||
Title: "我的用户管理平台 API",
|
||||
Description: "这是一个基于 Gin 的用户管理平台后端 API 文档",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
LeftDelim: "{{",
|
||||
RightDelim: "}}",
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
||||
267
docs/swagger.json
Normal file
267
docs/swagger.json
Normal file
@@ -0,0 +1,267 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "这是一个基于 Gin 的用户管理平台后端 API 文档",
|
||||
"title": "我的用户管理平台 API",
|
||||
"termsOfService": "http://kmux.cn",
|
||||
"contact": {
|
||||
"name": "zhilv",
|
||||
"url": "www.kmux.cn",
|
||||
"email": "zhilv666@qq.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
},
|
||||
"version": "1.0"
|
||||
},
|
||||
"host": "localhost:8080",
|
||||
"basePath": "/api/v1",
|
||||
"paths": {
|
||||
"/api/v1/auth/login": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "用户登录",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "登录参数",
|
||||
"name": "login",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Req"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "登录成功",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-handler_LoginResp"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "登录失败",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/auth/register": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "用户注册",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "注册参数",
|
||||
"name": "register",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Req"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "注册成功",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-handler_Req"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "注册失败",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/user/{id}": {
|
||||
"get": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "获取指定 ID 用户",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "用户 ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "获取成功",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-model_User"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "获取失败",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/common.Response-any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"common.Response-any": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.Response-handler_LoginResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/handler.LoginResp"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.Response-handler_Req": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/handler.Req"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.Response-model_User": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.User"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.LoginResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...zYyfQ.bQeIyXvkOExxD4DAy5Eyjgwj9FbjE-AO6FCLF-YFGVA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Req": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"otp_code": {
|
||||
"type": "string",
|
||||
"example": "123456"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "123456"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.User": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"description": "禁用标志",
|
||||
"type": "boolean"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_admin": {
|
||||
"description": "true = 管理员",
|
||||
"type": "boolean"
|
||||
},
|
||||
"points": {
|
||||
"description": "积分",
|
||||
"type": "integer"
|
||||
},
|
||||
"sso_id": {
|
||||
"description": "OAuth2 唯一标识",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "邮箱注册",
|
||||
"type": "string"
|
||||
},
|
||||
"verified": {
|
||||
"description": "是否通过邮箱验证/管理员审核",
|
||||
"type": "boolean"
|
||||
},
|
||||
"verify_at": {
|
||||
"description": "验证时间",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
docs/swagger.yaml
Normal file
181
docs/swagger.yaml
Normal file
@@ -0,0 +1,181 @@
|
||||
basePath: /api/v1
|
||||
definitions:
|
||||
common.Response-any:
|
||||
properties:
|
||||
code:
|
||||
example: 0
|
||||
type: integer
|
||||
data: {}
|
||||
msg:
|
||||
example: success
|
||||
type: string
|
||||
type: object
|
||||
common.Response-handler_LoginResp:
|
||||
properties:
|
||||
code:
|
||||
example: 0
|
||||
type: integer
|
||||
data:
|
||||
$ref: '#/definitions/handler.LoginResp'
|
||||
msg:
|
||||
example: success
|
||||
type: string
|
||||
type: object
|
||||
common.Response-handler_Req:
|
||||
properties:
|
||||
code:
|
||||
example: 0
|
||||
type: integer
|
||||
data:
|
||||
$ref: '#/definitions/handler.Req'
|
||||
msg:
|
||||
example: success
|
||||
type: string
|
||||
type: object
|
||||
common.Response-model_User:
|
||||
properties:
|
||||
code:
|
||||
example: 0
|
||||
type: integer
|
||||
data:
|
||||
$ref: '#/definitions/model.User'
|
||||
msg:
|
||||
example: success
|
||||
type: string
|
||||
type: object
|
||||
handler.LoginResp:
|
||||
properties:
|
||||
token:
|
||||
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...zYyfQ.bQeIyXvkOExxD4DAy5Eyjgwj9FbjE-AO6FCLF-YFGVA
|
||||
type: string
|
||||
type: object
|
||||
handler.Req:
|
||||
properties:
|
||||
otp_code:
|
||||
example: "123456"
|
||||
type: string
|
||||
password:
|
||||
example: "123456"
|
||||
type: string
|
||||
username:
|
||||
example: admin
|
||||
type: string
|
||||
required:
|
||||
- password
|
||||
- username
|
||||
type: object
|
||||
model.User:
|
||||
properties:
|
||||
created_at:
|
||||
type: string
|
||||
disabled:
|
||||
description: 禁用标志
|
||||
type: boolean
|
||||
email:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
is_admin:
|
||||
description: true = 管理员
|
||||
type: boolean
|
||||
points:
|
||||
description: 积分
|
||||
type: integer
|
||||
sso_id:
|
||||
description: OAuth2 唯一标识
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
username:
|
||||
description: 邮箱注册
|
||||
type: string
|
||||
verified:
|
||||
description: 是否通过邮箱验证/管理员审核
|
||||
type: boolean
|
||||
verify_at:
|
||||
description: 验证时间
|
||||
type: string
|
||||
type: object
|
||||
host: localhost:8080
|
||||
info:
|
||||
contact:
|
||||
email: zhilv666@qq.com
|
||||
name: zhilv
|
||||
url: www.kmux.cn
|
||||
description: 这是一个基于 Gin 的用户管理平台后端 API 文档
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
termsOfService: http://kmux.cn
|
||||
title: 我的用户管理平台 API
|
||||
version: "1.0"
|
||||
paths:
|
||||
/api/v1/auth/login:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: 登录参数
|
||||
in: body
|
||||
name: login
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Req'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 登录成功
|
||||
schema:
|
||||
$ref: '#/definitions/common.Response-handler_LoginResp'
|
||||
"400":
|
||||
description: 登录失败
|
||||
schema:
|
||||
$ref: '#/definitions/common.Response-any'
|
||||
summary: 用户登录
|
||||
/api/v1/auth/register:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: 注册参数
|
||||
in: body
|
||||
name: register
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Req'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 注册成功
|
||||
schema:
|
||||
$ref: '#/definitions/common.Response-handler_Req'
|
||||
"400":
|
||||
description: 注册失败
|
||||
schema:
|
||||
$ref: '#/definitions/common.Response-any'
|
||||
summary: 用户注册
|
||||
/api/v1/user/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: 用户 ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 获取成功
|
||||
schema:
|
||||
$ref: '#/definitions/common.Response-model_User'
|
||||
"400":
|
||||
description: 获取失败
|
||||
schema:
|
||||
$ref: '#/definitions/common.Response-any'
|
||||
summary: 获取指定 ID 用户
|
||||
swagger: "2.0"
|
||||
109
go.mod
Normal file
109
go.mod
Normal file
@@ -0,0 +1,109 @@
|
||||
module github.com/zhilv666/navsite
|
||||
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.9.0
|
||||
github.com/gin-gonic/gin v1.11.0
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/spf13/viper v1.21.0
|
||||
go.uber.org/zap v1.27.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/driver/postgres v1.6.0
|
||||
gorm.io/driver/sqlserver v1.6.1
|
||||
gorm.io/gorm v1.31.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic v1.14.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.4.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.2 // indirect
|
||||
github.com/go-openapi/spec v0.22.0 // indirect
|
||||
github.com/go-openapi/swag v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/conv v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/loading v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.8.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.55.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/swaggo/files v1.0.1 // indirect
|
||||
github.com/swaggo/gin-swagger v1.6.1 // indirect
|
||||
github.com/swaggo/swag v1.16.6 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
github.com/urfave/cli/v2 v2.27.7 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
||||
430
go.sum
Normal file
430
go.sum
Normal file
@@ -0,0 +1,430 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28=
|
||||
github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
|
||||
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
|
||||
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
|
||||
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
|
||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
|
||||
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
||||
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
|
||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
|
||||
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
|
||||
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
|
||||
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
|
||||
github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0Tw=
|
||||
github.com/go-openapi/spec v0.22.0/go.mod h1:K0FhKxkez8YNS94XzF8YKEMULbFrRw4m15i2YUht4L0=
|
||||
github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8=
|
||||
github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo=
|
||||
github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0=
|
||||
github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs=
|
||||
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
|
||||
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo=
|
||||
github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw=
|
||||
github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc=
|
||||
github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw=
|
||||
github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg=
|
||||
github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA=
|
||||
github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8=
|
||||
github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/microsoft/go-mssqldb v1.8.2 h1:236sewazvC8FvG6Dr3bszrVhMkAl4KYImryLkRMCd0I=
|
||||
github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||
github.com/swaggo/gin-swagger v1.6.1 h1:Ri06G4gc9N4t4k8hekMigJ9zKTFSlqj/9paAQCQs7cY=
|
||||
github.com/swaggo/gin-swagger v1.6.1/go.mod h1:LQ+hJStHakCWRiK/YNYtJOu4mR2FP+pxLnILT/qNiTw=
|
||||
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
|
||||
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
|
||||
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
|
||||
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
|
||||
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
|
||||
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
|
||||
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
|
||||
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||
gorm.io/driver/sqlserver v1.6.1 h1:XWISFsu2I2pqd1KJhhTZNJMx1jNQ+zVL/Q8ovDcUjtY=
|
||||
gorm.io/driver/sqlserver v1.6.1/go.mod h1:VZeNn7hqX1aXoN5TPAFGWvxWG90xtA8erGn2gQmpc6U=
|
||||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
|
||||
gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
|
||||
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
|
||||
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
25
internal/api/api.go
Normal file
25
internal/api/api.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerfiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
docs "github.com/zhilv666/navsite/docs"
|
||||
"github.com/zhilv666/navsite/internal/api/handler"
|
||||
"github.com/zhilv666/navsite/internal/model"
|
||||
)
|
||||
|
||||
func RegisterRouter(r *gin.Engine) {
|
||||
model.Init()
|
||||
docs.SwaggerInfo.BasePath = "/"
|
||||
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
|
||||
|
||||
v1 := r.Group("/api/v1")
|
||||
{
|
||||
handler.RegisterRouterAuth(v1.Group("/auth"))
|
||||
handler.RegisterRouterUser(v1.Group("/user"))
|
||||
handler.RegisterRouterCateage(v1.Group("/cateage"))
|
||||
v1.GET("/proxy", handler.Proxy)
|
||||
}
|
||||
|
||||
}
|
||||
102
internal/api/handler/auth.go
Normal file
102
internal/api/handler/auth.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/zhilv666/navsite/internal/model"
|
||||
"github.com/zhilv666/navsite/internal/service"
|
||||
"github.com/zhilv666/navsite/pkg/common"
|
||||
"github.com/zhilv666/navsite/pkg/utils"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Req struct {
|
||||
Username string `json:"username" binding:"required" example:"admin"`
|
||||
Password string `json:"password" binding:"required" example:"123456"`
|
||||
OtpCode string `json:"otp_code" example:"123456"`
|
||||
}
|
||||
|
||||
type LoginResp struct {
|
||||
Token string `json:"token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...zYyfQ.bQeIyXvkOExxD4DAy5Eyjgwj9FbjE-AO6FCLF-YFGVA"`
|
||||
}
|
||||
|
||||
// login
|
||||
// @Summary 用户登录
|
||||
// @Tag Auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param login body Req true "登录参数"
|
||||
// @Success 200 {object} common.Response[LoginResp] "登录成功"
|
||||
// @Failure 400 {object} common.Response[any] "登录失败"
|
||||
// @Router /api/v1/auth/login [post]
|
||||
func login(c *gin.Context) {
|
||||
var req Req
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
user, err := service.GetUserByName(req.Username)
|
||||
if err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
if user == nil {
|
||||
common.Fail(c, "账号或密码不正确")
|
||||
return
|
||||
}
|
||||
if len(req.Password) < 32 {
|
||||
req.Password = common.Sha1(req.Password)
|
||||
}
|
||||
if user.Password != req.Password {
|
||||
common.Fail(c, "账号或密码不正确")
|
||||
return
|
||||
}
|
||||
token := utils.GenerateJwtToken(user.ID, user.Email, user.SsoID)
|
||||
common.Succ(c, LoginResp{Token: token})
|
||||
}
|
||||
|
||||
// register
|
||||
// @Summary 用户注册
|
||||
// @Tag Auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param register body Req true "注册参数"
|
||||
// @Success 200 {object} common.Response[Req] "注册成功"
|
||||
// @Failure 400 {object} common.Response[any] "注册失败"
|
||||
// @Router /api/v1/auth/register [post]
|
||||
func register(c *gin.Context) {
|
||||
var req Req
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
user, err := service.GetUserByName(req.Username)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
} else {
|
||||
common.Fail(c, "查询用户失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
if user != nil {
|
||||
common.Fail(c, "该账号已注册")
|
||||
return
|
||||
}
|
||||
if len(req.Password) < 32 {
|
||||
req.Password = common.Sha1(req.Password)
|
||||
}
|
||||
err = service.AddUser(&model.User{
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
})
|
||||
if err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
common.Ok(c, "账号注册成功")
|
||||
}
|
||||
|
||||
func RegisterRouterAuth(g *gin.RouterGroup) {
|
||||
g.POST("/login", login)
|
||||
g.POST("/register", register)
|
||||
}
|
||||
20
internal/api/handler/cateage.go
Normal file
20
internal/api/handler/cateage.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/zhilv666/navsite/internal/service"
|
||||
"github.com/zhilv666/navsite/pkg/common"
|
||||
)
|
||||
|
||||
func GetAllCateageWithSites(c *gin.Context) {
|
||||
cateagies, err := service.GetAllCateageWithSites()
|
||||
if err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
common.Succ(c, cateagies)
|
||||
}
|
||||
|
||||
func RegisterRouterCateage(g *gin.RouterGroup) {
|
||||
g.GET("/", GetAllCateageWithSites)
|
||||
}
|
||||
42
internal/api/handler/proxy.go
Normal file
42
internal/api/handler/proxy.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/zhilv666/navsite/pkg/common"
|
||||
)
|
||||
|
||||
func Proxy(c *gin.Context) {
|
||||
_url := c.Query("url")
|
||||
if _url == "" {
|
||||
common.Fail(c, "missing url")
|
||||
return
|
||||
}
|
||||
// 请求目标 URL
|
||||
resp, err := http.Get(_url)
|
||||
if err != nil {
|
||||
common.Fail(c, "unable to fetch image")
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 检查 Content-Type 是否为图片
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if !strings.HasPrefix(contentType, "image/") {
|
||||
common.Fail(c, "not an image file")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置响应 Content-Type
|
||||
c.Writer.Header().Set("Content-Type", contentType)
|
||||
|
||||
// 将图片数据直接写入响应
|
||||
_, err = io.Copy(c.Writer, resp.Body)
|
||||
if err != nil {
|
||||
common.Fail(c, "failed to write image")
|
||||
return
|
||||
}
|
||||
}
|
||||
35
internal/api/handler/user.go
Normal file
35
internal/api/handler/user.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/zhilv666/navsite/internal/service"
|
||||
"github.com/zhilv666/navsite/pkg/common"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// getUserByID
|
||||
// @Summary 获取指定 ID 用户
|
||||
// @Tag User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "用户 ID"
|
||||
// @Success 200 {object} common.Response[model.User] "获取成功"
|
||||
// @Failure 400 {object} common.Response[any] "获取失败"
|
||||
// @Router /api/v1/user/{id} [get]
|
||||
func getUserByID(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
idInt, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
}
|
||||
user, err := service.GetUserByID(uint(idInt))
|
||||
if err != nil {
|
||||
common.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
common.Succ(c, user)
|
||||
}
|
||||
|
||||
func RegisterRouterUser(g *gin.RouterGroup) {
|
||||
g.GET(":id", getUserByID)
|
||||
}
|
||||
16
internal/model/cateage.go
Normal file
16
internal/model/cateage.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cateage struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"-"`
|
||||
|
||||
AnchorId string `gorm:"size:100;not null;unique" json:"anchor_id"`
|
||||
Name string `gorm:"size:100;not null;unique" json:"name"`
|
||||
Sites []Site `gorm:"foreignKey:CateageID" json:"sites"` // 方便获取分类下所有网站
|
||||
}
|
||||
16
internal/model/model.go
Normal file
16
internal/model/model.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/zhilv666/navsite/pkg/db"
|
||||
"github.com/zhilv666/navsite/pkg/logger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
err := db.GetDB().AutoMigrate(
|
||||
new(User), new(Cateage), new(Site),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("database migrate error", zap.Stack("migrate"))
|
||||
}
|
||||
}
|
||||
18
internal/model/site.go
Normal file
18
internal/model/site.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Site struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"-"`
|
||||
|
||||
Name string `gorm:"size:100;not null;unique" json:"name"`
|
||||
Describe string `gorm:"size:100" json:"describe"`
|
||||
CateageID uint `gorm:"not null;index" json:"cateage_id"`
|
||||
Cateage Cateage `gorm:"foreignKey:CateageID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"cateage"` // 外键关联
|
||||
Url string `gorm:"size:500;not null" json:"url"`
|
||||
Cors bool `gorm:"default:false" json:"cors"`
|
||||
Icon string `gorm:"size:500;default:'https://cos.kmux.cn/md/20251115174627218.png'" json:"icon"`
|
||||
}
|
||||
23
internal/model/user.go
Normal file
23
internal/model/user.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"-"`
|
||||
|
||||
Username string `gorm:"uniqueIndex;size:50;not null" json:"username"` // 邮箱注册
|
||||
Email string `gorm:"uniqueIndex;size:100;not null" json:"email"`
|
||||
Password string `json:"-" gorm:"size:100;not null"` // SHA1 密码
|
||||
Salt string `json:"-" gorm:"size:32;not null"` // 密码盐
|
||||
IsAdmin bool `json:"is_admin"` // true = 管理员
|
||||
Disabled bool `json:"disabled" gorm:"default:false"` // 禁用标志
|
||||
SsoID string `json:"sso_id" gorm:"size:100;unique"` // OAuth2 唯一标识
|
||||
Verified bool `json:"verified" gorm:"default:false"` // 是否通过邮箱验证/管理员审核
|
||||
VerifyAt *time.Time `json:"verify_at,omitempty"` // 验证时间
|
||||
Points int `json:"points" gorm:"default:0"` // 积分
|
||||
}
|
||||
14
internal/router/router.go
Normal file
14
internal/router/router.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/zhilv666/navsite/internal/api"
|
||||
)
|
||||
|
||||
func SetupRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
|
||||
api.RegisterRouter(r)
|
||||
|
||||
return r
|
||||
}
|
||||
14
internal/service/cateage.go
Normal file
14
internal/service/cateage.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zhilv666/navsite/internal/model"
|
||||
)
|
||||
|
||||
func GetAllCateageWithSites() ([]model.Cateage, error) {
|
||||
var cateagies []model.Cateage
|
||||
if err := DB().Preload("Sites").Find(&cateagies).Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed get cateagies")
|
||||
}
|
||||
return cateagies, nil
|
||||
}
|
||||
18
internal/service/service.go
Normal file
18
internal/service/service.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"github.com/zhilv666/navsite/pkg/db"
|
||||
"github.com/zhilv666/navsite/pkg/logger"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func DB() *gorm.DB {
|
||||
_db := db.GetDB()
|
||||
if _db == nil {
|
||||
db.InitDB(config.GetConfig().Database, logger.GetLogger())
|
||||
return db.GetDB()
|
||||
}
|
||||
|
||||
return _db
|
||||
}
|
||||
46
internal/service/user.go
Normal file
46
internal/service/user.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/zhilv666/navsite/internal/model"
|
||||
)
|
||||
|
||||
func GetUserByID(id uint) (*model.User, error) {
|
||||
var user model.User
|
||||
if err := DB().First(&user, id).Error; err != nil {
|
||||
return nil, errors.Wrapf(err, "failed get old user")
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func GetUserByName(username string) (*model.User, error) {
|
||||
user := model.User{Username: username}
|
||||
if err := DB().Where(user).First(&user).Error; err != nil {
|
||||
return nil, errors.Wrapf(err, "failed get old user")
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func GetUsers(pageIndex, pageSize int) (users []*model.User, count int64, err error) {
|
||||
userDB := DB().Model(&model.User{})
|
||||
if err := userDB.Count(&count).Error; err != nil {
|
||||
return nil, 0, errors.Wrapf(err, "failed get counts")
|
||||
}
|
||||
if err := userDB.Order(columnName("id")).Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&users).Error; err != nil {
|
||||
return nil, 0, errors.Wrapf(err, "failed get users")
|
||||
}
|
||||
return users, count, nil
|
||||
}
|
||||
|
||||
func AddUser(user *model.User) error {
|
||||
return errors.WithStack(DB().Create(&user).Error)
|
||||
}
|
||||
|
||||
func UpdateUser(user *model.User) error {
|
||||
return errors.WithStack(DB().Save(&user).Error)
|
||||
}
|
||||
|
||||
func DeleteUser(id uint) error {
|
||||
return errors.WithStack(DB().Delete(&model.User{}, id).Error)
|
||||
}
|
||||
19
internal/service/utils.go
Normal file
19
internal/service/utils.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func columnName(name string) string {
|
||||
if config.GetConfig().Database.Driver == "postgres" {
|
||||
return fmt.Sprintf(`"%s"`, name)
|
||||
}
|
||||
return fmt.Sprintf("`%s`", name)
|
||||
}
|
||||
|
||||
func addStorageOrder(db *gorm.DB) *gorm.DB {
|
||||
return DB().Order(fmt.Sprintf("%s, %s", columnName("order"), columnName("id")))
|
||||
}
|
||||
21
main.go
Normal file
21
main.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import "github.com/zhilv666/navsite/cmd"
|
||||
|
||||
// @title 我的用户管理平台 API
|
||||
// @version 1.0
|
||||
// @description 这是一个基于 Gin 的用户管理平台后端 API 文档
|
||||
// @termsOfService http://kmux.cn
|
||||
|
||||
// @contact.name zhilv
|
||||
// @contact.url www.kmux.cn
|
||||
// @contact.email zhilv666@qq.com
|
||||
|
||||
// @license.name MIT
|
||||
// @license.url https://opensource.org/licenses/MIT
|
||||
|
||||
// @host localhost:8080
|
||||
// @BasePath /api/v1
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
18
pkg/common/rand.go
Normal file
18
pkg/common/rand.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Rand 生成指定长度的随机字符串,字符集为 [0-9a-zA-Z]
|
||||
func Rand(length int) string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[seededRand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
35
pkg/common/response.go
Normal file
35
pkg/common/response.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Response[T any] struct {
|
||||
Code int `json:"code" example:"0"`
|
||||
Msg string `json:"msg" example:"success"`
|
||||
Data T `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func Succ(c *gin.Context, data interface{}) {
|
||||
c.JSON(http.StatusOK, Response[interface{}]{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
func Ok(c *gin.Context, msg string) {
|
||||
c.JSON(http.StatusOK, Response[interface{}]{
|
||||
Code: 0,
|
||||
Msg: msg,
|
||||
})
|
||||
}
|
||||
|
||||
func Fail(c *gin.Context, msg string) {
|
||||
c.JSON(http.StatusBadRequest, Response[interface{}]{
|
||||
Code: -1,
|
||||
Msg: msg,
|
||||
})
|
||||
}
|
||||
10
pkg/common/sha1.go
Normal file
10
pkg/common/sha1.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func Sha1(pwd string) string {
|
||||
return hex.EncodeToString(sha1.New().Sum([]byte(pwd)))
|
||||
}
|
||||
130
pkg/config/config.go
Normal file
130
pkg/config/config.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zhilv666/navsite/pkg/consts"
|
||||
)
|
||||
|
||||
var (
|
||||
globalViper *viper.Viper
|
||||
globalViperOnce sync.Once
|
||||
configMu sync.RWMutex
|
||||
cachedConfig *Config
|
||||
)
|
||||
|
||||
// NewConfig 初始化配置
|
||||
func NewConfig() *Config {
|
||||
globalViperOnce.Do(func() {
|
||||
globalViper = viper.New()
|
||||
})
|
||||
|
||||
configPath := loadConfigFile()
|
||||
if configPath == "" {
|
||||
log.Println("⚠️ 未找到配置文件,使用默认配置并导出为 config.yaml")
|
||||
cachedConfig = DefaultConfig()
|
||||
exportConfig(cachedConfig, "yaml")
|
||||
return cachedConfig
|
||||
}
|
||||
|
||||
conf, err := parseConfig()
|
||||
if err != nil {
|
||||
log.Printf("⚠️ 解析配置失败,使用默认配置并导出为 config.yaml: %v", err)
|
||||
conf = DefaultConfig()
|
||||
exportConfig(conf, "yaml")
|
||||
}
|
||||
|
||||
cachedConfig = conf
|
||||
return conf
|
||||
}
|
||||
|
||||
// loadConfigFile 加载配置文件
|
||||
func loadConfigFile() string {
|
||||
files := []string{
|
||||
fmt.Sprintf("%s.yaml", consts.ConfigName),
|
||||
fmt.Sprintf("%s.yml", consts.ConfigName),
|
||||
fmt.Sprintf("%s.json", consts.ConfigName),
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if _, err := os.Stat(file); err == nil {
|
||||
ext := filepath.Ext(file)[1:]
|
||||
globalViper.SetConfigFile(file)
|
||||
globalViper.SetConfigType(ext)
|
||||
globalViper.AddConfigPath(".")
|
||||
|
||||
if err := globalViper.ReadInConfig(); err != nil {
|
||||
log.Printf("⚠️ 读取配置文件 %s 失败: %v", file, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("✅ 成功加载配置文件: %s", file)
|
||||
return file
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// parseConfig 将配置解析为结构体
|
||||
func parseConfig() (*Config, error) {
|
||||
configMu.Lock()
|
||||
defer configMu.Unlock()
|
||||
|
||||
var conf Config
|
||||
if err := globalViper.Unmarshal(&conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &conf, nil
|
||||
}
|
||||
|
||||
// exportConfig 导出配置文件(默认保存为 config.yaml)
|
||||
func exportConfig(conf *Config, format string) {
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
|
||||
switch format {
|
||||
case "json":
|
||||
data, err = json.MarshalIndent(conf, "", " ")
|
||||
case "yaml", "yml", "":
|
||||
format = "yaml"
|
||||
data, err = yaml.Marshal(conf)
|
||||
default:
|
||||
log.Printf("⚠️ 不支持的导出格式: %s", format)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("⚠️ 导出 %s 格式配置失败: %v", format, err)
|
||||
return
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("%s.%s", consts.ConfigName, format)
|
||||
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||
log.Printf("⚠️ 写入配置文件 %s 失败: %v", filename, err)
|
||||
} else {
|
||||
log.Printf("✅ 已导出配置文件: %s", filename)
|
||||
}
|
||||
|
||||
log.Printf("📋 当前 %s 配置:\n%s", format, data)
|
||||
}
|
||||
|
||||
// GetConfig 获取当前配置(线程安全)
|
||||
func GetConfig() *Config {
|
||||
configMu.RLock()
|
||||
defer configMu.RUnlock()
|
||||
|
||||
if cachedConfig == nil {
|
||||
return DefaultConfig()
|
||||
}
|
||||
conf := *cachedConfig
|
||||
return &conf
|
||||
}
|
||||
76
pkg/config/types.go
Normal file
76
pkg/config/types.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/zhilv666/navsite/pkg/common"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Debug bool `mapstructure:"debug"`
|
||||
Port int `mapstructure:"port"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Level string `mapstructure:"level"`
|
||||
Filepath string `mapstructure:"filepath"`
|
||||
MaxSizeMB int `mapstructure:"max_size_mb"` // 单个日志文件最大(MB)
|
||||
MaxAgeDay int `mapstructure:"max_age_day"` // 日志文件最大保存天数
|
||||
Backups int `mapstructure:"backups"` // 保留的旧文件个数
|
||||
Compress bool `mapstructure:"compress"` // 是否压缩
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
Driver string `mapstructure:"driver"`
|
||||
User string `mapstructure:"user"`
|
||||
Password string `mapstructure:"password"`
|
||||
Host string `mapstructure:"host"`
|
||||
Port int `mapstructure:"port"`
|
||||
DbName string `mapstructure:"db_name"`
|
||||
SqliteDbPath string `mapstructure:"sqlite_db_path"`
|
||||
}
|
||||
|
||||
type JWT struct {
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
ExpireDurationHour time.Duration `mapstructure:"expire_duration_hour"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Server Server `mapstructure:"server"`
|
||||
Log Log `mapstructure:"log"`
|
||||
Database Database `mapstructure:"database"`
|
||||
JWT JWT `mapstructure:"jwt"`
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
logPath := filepath.Join("data", "log.log")
|
||||
dbPath := filepath.Join("data", "sqlite.db")
|
||||
return &Config{
|
||||
Server: Server{
|
||||
Debug: true,
|
||||
Port: 8080,
|
||||
},
|
||||
Log: Log{
|
||||
Level: "debug",
|
||||
Filepath: logPath,
|
||||
MaxSizeMB: 10,
|
||||
MaxAgeDay: 7,
|
||||
Backups: 3,
|
||||
Compress: true,
|
||||
},
|
||||
Database: Database{
|
||||
Driver: "sqlite",
|
||||
User: "",
|
||||
Password: "",
|
||||
Host: "",
|
||||
Port: 0,
|
||||
DbName: "",
|
||||
SqliteDbPath: dbPath,
|
||||
},
|
||||
JWT: JWT{
|
||||
SecretKey: common.Rand(16),
|
||||
ExpireDurationHour: 24,
|
||||
},
|
||||
}
|
||||
}
|
||||
29
pkg/consts/consts.go
Normal file
29
pkg/consts/consts.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package consts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 通用系统级常量
|
||||
const (
|
||||
AppName = "NavSite"
|
||||
AppAuthor = "zhilv666"
|
||||
AppVersion = "1.0.0"
|
||||
)
|
||||
|
||||
// 默认服务端口
|
||||
const DefaultPort = 8080
|
||||
|
||||
// 通用时间格式
|
||||
const (
|
||||
TimeFormatDate = "2006-01-02"
|
||||
TimeFormatDateTime = "2006-01-02 15:04:05"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fmt.Printf("🚀 启动 %s v%s by %s\n",
|
||||
AppName,
|
||||
AppVersion,
|
||||
AppAuthor,
|
||||
)
|
||||
}
|
||||
6
pkg/consts/paths.go
Normal file
6
pkg/consts/paths.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package consts
|
||||
|
||||
// 项目路径与文件定义
|
||||
var (
|
||||
ConfigName = "config"
|
||||
)
|
||||
6
pkg/consts/version.go
Normal file
6
pkg/consts/version.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package consts
|
||||
|
||||
var (
|
||||
BuildTime string
|
||||
GitCommit string
|
||||
)
|
||||
25
pkg/db/connect.go
Normal file
25
pkg/db/connect.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/driver/sqlserver"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func connectMySQL(dsn string) gorm.Dialector {
|
||||
return mysql.Open(dsn)
|
||||
}
|
||||
|
||||
func connectSQLite(filepath string) gorm.Dialector {
|
||||
return sqlite.Open(filepath + "?cache=shared&_fk=1&_driver=modernc.org/sqlite")
|
||||
}
|
||||
|
||||
func connectPostgres(dsn string) gorm.Dialector {
|
||||
return postgres.Open(dsn)
|
||||
}
|
||||
|
||||
func connectSQLServer(dsn string) gorm.Dialector {
|
||||
return sqlserver.Open(dsn)
|
||||
}
|
||||
64
pkg/db/db.go
Normal file
64
pkg/db/db.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func init() {
|
||||
if _, err := os.Stat("./data"); os.IsNotExist(err) {
|
||||
_ = os.Mkdir("./data", os.ModePerm)
|
||||
}
|
||||
}
|
||||
|
||||
func GetDB() *gorm.DB {
|
||||
if db == nil {
|
||||
panic("数据库未初始化,请先调用 db.InitDB()")
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func InitDB(cfg config.Database, log *zap.Logger) {
|
||||
go func() {
|
||||
if err := recover(); err != nil {
|
||||
panic(fmt.Sprintf("Init DB Error: %v", err))
|
||||
}
|
||||
}()
|
||||
|
||||
var dsn string
|
||||
var dialector gorm.Dialector
|
||||
|
||||
switch cfg.Driver {
|
||||
case "mysql":
|
||||
dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DbName)
|
||||
dialector = connectMySQL(dsn)
|
||||
case "postgres":
|
||||
dsn = fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s sslmode=disable",
|
||||
cfg.Host, cfg.Port, cfg.User, cfg.DbName, cfg.Password)
|
||||
dialector = connectPostgres(dsn)
|
||||
case "sqlserver":
|
||||
dsn = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s",
|
||||
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DbName)
|
||||
dialector = connectSQLServer(dsn)
|
||||
case "sqlite", "sqlite3":
|
||||
fmt.Println(cfg.SqliteDbPath)
|
||||
dialector = connectSQLite(cfg.SqliteDbPath)
|
||||
default:
|
||||
panic(fmt.Errorf("unsupport database driver: %s", cfg.Driver))
|
||||
}
|
||||
var err error
|
||||
db, err = gorm.Open(dialector, &gorm.Config{
|
||||
Logger: NewZapGormLogger(log).LogMode(logger.Info),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
81
pkg/db/gorm_logger.go
Normal file
81
pkg/db/gorm_logger.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/utils"
|
||||
)
|
||||
|
||||
type ZapGormLogger struct {
|
||||
ZapLogger *zap.Logger
|
||||
LogLevel logger.LogLevel
|
||||
SlowThreshold time.Duration
|
||||
}
|
||||
|
||||
func NewZapGormLogger(zapLogger *zap.Logger) *ZapGormLogger {
|
||||
return &ZapGormLogger{
|
||||
ZapLogger: zapLogger,
|
||||
LogLevel: logger.Info,
|
||||
SlowThreshold: time.Second, // 1s 慢查询阈值
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ZapGormLogger) LogMode(level logger.LogLevel) logger.Interface {
|
||||
newlogger := *l
|
||||
newlogger.LogLevel = level
|
||||
return &newlogger
|
||||
}
|
||||
|
||||
func (l *ZapGormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.LogLevel >= logger.Info {
|
||||
l.ZapLogger.Sugar().Infof(msg, data...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ZapGormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.LogLevel >= logger.Warn {
|
||||
l.ZapLogger.Sugar().Warnf(msg, data...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ZapGormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.LogLevel >= logger.Error {
|
||||
l.ZapLogger.Sugar().Errorf(msg, data...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ZapGormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
|
||||
if l.LogLevel <= logger.Silent {
|
||||
return
|
||||
}
|
||||
elapsed := time.Since(begin)
|
||||
sql, rows := fc()
|
||||
|
||||
switch {
|
||||
case err != nil && l.LogLevel >= logger.Error:
|
||||
l.ZapLogger.Error("SQL Error",
|
||||
zap.Error(err),
|
||||
zap.String("sql", sql),
|
||||
zap.Int64("rows", rows),
|
||||
zap.Duration("elapsed", elapsed),
|
||||
zap.String("file", utils.FileWithLineNum()),
|
||||
)
|
||||
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= logger.Warn:
|
||||
l.ZapLogger.Warn("Slow SQL",
|
||||
zap.Duration("elapsed", elapsed),
|
||||
zap.String("sql", sql),
|
||||
zap.Int64("rows", rows),
|
||||
zap.String("file", utils.FileWithLineNum()),
|
||||
)
|
||||
case l.LogLevel >= logger.Info:
|
||||
l.ZapLogger.Info("SQL",
|
||||
zap.String("sql", sql),
|
||||
zap.Int64("rows", rows),
|
||||
zap.Duration("elapsed", elapsed),
|
||||
zap.String("file", utils.FileWithLineNum()),
|
||||
)
|
||||
}
|
||||
}
|
||||
27
pkg/logger/func.go
Normal file
27
pkg/logger/func.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package logger
|
||||
|
||||
import "go.uber.org/zap"
|
||||
|
||||
func GetLogger() *zap.Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
func Debug(msg string, fields ...zap.Field) {
|
||||
logger.Debug(msg, fields...)
|
||||
}
|
||||
|
||||
func Info(msg string, fields ...zap.Field) {
|
||||
logger.Info(msg, fields...)
|
||||
}
|
||||
|
||||
func Warn(msg string, fields ...zap.Field) {
|
||||
logger.Warn(msg, fields...)
|
||||
}
|
||||
|
||||
func Error(msg string, fields ...zap.Field) {
|
||||
logger.Error(msg, fields...)
|
||||
}
|
||||
|
||||
func Sync() {
|
||||
_ = logger.Sync()
|
||||
}
|
||||
87
pkg/logger/logger.go
Normal file
87
pkg/logger/logger.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"github.com/zhilv666/navsite/pkg/consts"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var logger *zap.Logger
|
||||
|
||||
func Init(log config.Log) {
|
||||
var zapLevel zapcore.Level
|
||||
|
||||
// 日志等级解析
|
||||
switch log.Level {
|
||||
case "debug":
|
||||
zapLevel = zap.DebugLevel
|
||||
case "info":
|
||||
zapLevel = zap.InfoLevel
|
||||
case "warning":
|
||||
zapLevel = zap.WarnLevel
|
||||
case "error":
|
||||
zapLevel = zap.ErrorLevel
|
||||
default:
|
||||
zapLevel = zap.InfoLevel
|
||||
}
|
||||
|
||||
// lumberjack 日志切割配置
|
||||
writeSyncer := zapcore.AddSync(&lumberjack.Logger{
|
||||
Filename: log.Filepath,
|
||||
MaxSize: log.MaxSizeMB,
|
||||
MaxBackups: log.Backups,
|
||||
MaxAge: log.MaxAgeDay,
|
||||
Compress: log.Compress,
|
||||
})
|
||||
|
||||
// 日志编码格式
|
||||
encoderConfigColor := zapcore.EncoderConfig{
|
||||
TimeKey: "time",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "msg",
|
||||
StacktraceKey: "Stacktrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.CapitalColorLevelEncoder, // 彩色等级输出(终端)
|
||||
// EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
EncodeTime: timeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
}
|
||||
|
||||
encoderConfig := zapcore.EncoderConfig{
|
||||
TimeKey: "time",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "msg",
|
||||
StacktraceKey: "Stacktrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
// EncodeLevel: zapcore.CapitalColorLevelEncoder, // 彩色等级输出(终端)
|
||||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
EncodeTime: timeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
}
|
||||
|
||||
encoderConsole := zapcore.NewConsoleEncoder(encoderConfigColor)
|
||||
encoderJson := zapcore.NewJSONEncoder(encoderConfig)
|
||||
|
||||
core := zapcore.NewTee(
|
||||
zapcore.NewCore(encoderJson, writeSyncer, zapLevel),
|
||||
zapcore.NewCore(encoderConsole, zapcore.AddSync(os.Stdout), zapLevel))
|
||||
|
||||
logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
|
||||
zap.ReplaceGlobals(logger)
|
||||
}
|
||||
|
||||
// 时间格式
|
||||
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||
enc.AppendString(t.Format(consts.TimeFormatDateTime))
|
||||
}
|
||||
81
pkg/utils/jwt.go
Normal file
81
pkg/utils/jwt.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"github.com/zhilv666/navsite/pkg/logger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type MyCustomClaims struct {
|
||||
ID uint `json:"id"`
|
||||
Email string `json:"Email"`
|
||||
SsoID string `json:"sso_id"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// GenerateJwtToken 生成 JWT Token
|
||||
func GenerateJwtToken(id uint, email, sso_id string) string {
|
||||
jwtConf := config.GetConfig().JWT
|
||||
claims := MyCustomClaims{
|
||||
id,
|
||||
email,
|
||||
sso_id,
|
||||
jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(jwtConf.ExpireDurationHour * time.Hour)),
|
||||
},
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
ss, err := token.SignedString([]byte(jwtConf.SecretKey))
|
||||
if err != nil {
|
||||
logger.Error("generate jwt token error", zap.String("jwt", err.Error()))
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
// ParseJwtToken 解析 JWT 并返回自定义 Claims,同时返回错误信息
|
||||
func ParseJwtToken(tokenString string) (*MyCustomClaims, error) {
|
||||
jwtConf := config.GetConfig().JWT
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (any, error) {
|
||||
return []byte(jwtConf.SecretKey), nil
|
||||
}, jwt.WithLeeway(5*time.Second))
|
||||
|
||||
if err != nil {
|
||||
logger.Error("parse jwt token error", zap.String("jwt", err.Error()))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(*MyCustomClaims)
|
||||
if !ok || !token.Valid {
|
||||
logger.Error("invalid jwt claims")
|
||||
return nil, errors.New("jwt token invalid")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// ValidJwtToken 验证 JWT Token
|
||||
func ValidJwtToken(tokenString string) bool {
|
||||
jwtConf := config.GetConfig().JWT
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (any, error) {
|
||||
return []byte(jwtConf.SecretKey), nil
|
||||
}, jwt.WithLeeway(5*time.Second))
|
||||
|
||||
if err != nil {
|
||||
logger.Error("parse jwt token error", zap.String("jwt", err.Error()))
|
||||
return false
|
||||
}
|
||||
|
||||
_, ok := token.Claims.(*MyCustomClaims)
|
||||
if !ok || !token.Valid {
|
||||
logger.Error("invalid jwt claims")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
25
pkg/utils/utils_test.go
Normal file
25
pkg/utils/utils_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package utils_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zhilv666/navsite/pkg/config"
|
||||
"github.com/zhilv666/navsite/pkg/logger"
|
||||
"github.com/zhilv666/navsite/pkg/utils"
|
||||
)
|
||||
|
||||
func TestJwt(t *testing.T) {
|
||||
conf := config.NewConfig()
|
||||
logger.Init(conf.Log)
|
||||
toekn := utils.GenerateJwtToken(11, "zhilv666@qq.com", "")
|
||||
t.Log("jwt token: ", toekn)
|
||||
|
||||
claimas, err := utils.ParseJwtToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTEsIkVtYWlsIjoiemhpbHY2NjZAcXEuY29tIiwic3NvX2lkIjoiIiwiZXhwIjoxNzYyMDkxNzYyfQ.bQeIyXvkOExxD4DAy5Eyjgwj9FbjE-AO6FCLF-YFGVA")
|
||||
if err != nil {
|
||||
t.Log("parse jwt token err")
|
||||
return
|
||||
}
|
||||
t.Log(claimas)
|
||||
|
||||
t.Log(utils.ValidJwtToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTEsIkVtYWlsIjoiemhpbHY2NjZAcXEuY29tIiwic3NvX2lkIjoiIiwiZXhwIjoxNzYyMDkyNTIxfQ.QynKGZmUSOXGgVVsqf-IMYBb11UPC6DT56p1UaNgHC0"))
|
||||
}
|
||||
Reference in New Issue
Block a user