Compare commits

...

No commits in common. "8c7a1f39fd3a891d650daf1bfbb3e39f04c8c01c" and "04d2b39b429177420123ddfe15858147c49b6724" have entirely different histories.

21 changed files with 145 additions and 813 deletions

265
.gitignore vendored
View File

@ -1,137 +1,162 @@
# ---> Go # ---> Python
# Binaries for programs and plugins # Byte-compiled / optimized / DLL files
*.exe __pycache__/
*.exe~ *.py[cod]
*.dll *$py.class
# C extensions
*.so *.so
*.dylib
# Test binary, built with `go test -c` # Distribution / packaging
*.test .Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Output of the go coverage tool, specifically when used with LiteIDE # PyInstaller
*.out # Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Dependency directories (remove the comment below to include it) # Installer logs
# vendor/ pip-log.txt
pip-delete-this-directory.txt
# ---> Node # Unit test / coverage reports
# Logs htmlcov/
logs .tox/
*.log .nox/
npm-debug.log* .coverage
yarn-debug.log* .coverage.*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env.production
# parcel-bundler cache (https://parceljs.org/)
.cache .cache
.parcel-cache nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Next.js build output # Translations
.next *.mo
out *.pot
# Nuxt.js build / generate output # Django stuff:
.nuxt *.log
dist local_settings.py
db.sqlite3
db.sqlite3-journal
# Gatsby files # Flask stuff:
.cache/ instance/
# Comment in the public line in if your project uses Gatsby and not Next.js .webassets-cache
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output # Scrapy stuff:
.vuepress/dist .scrapy
# Serverless directories # Sphinx documentation
.serverless/ docs/_build/
# FuseBox cache # PyBuilder
.fusebox/ .pybuilder/
target/
# DynamoDB Local files # Jupyter Notebook
.dynamodb/ .ipynb_checkpoints
# TernJS port file # IPython
.tern-port profile_default/
ipython_config.py
# Stores VSCode versions used for testing VSCode extensions # pyenv
.vscode-test # For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# yarn v2 # pipenv
.yarn/cache # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
.yarn/unplugged # However, in case of collaboration, if having platform-specific dependencies or dependencies
.yarn/build-state.yml # having no cross-platform support, pipenv may install dependencies that don't work, or not
.yarn/install-state.gz # install all needed dependencies.
.pnp.* #Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

View File

@ -1,3 +1,2 @@
# biblio # biblio
书库

View File

@ -1,11 +0,0 @@
package apiserver
import (
"biblio.bing89.com/auth"
"biblio.bing89.com/conf"
)
type APIServer struct {
Conf *conf.Configuration
authManager auth.AuthManager
}

View File

@ -1 +0,0 @@
package apiserver

View File

@ -1 +0,0 @@
package apiserver

View File

@ -1 +0,0 @@
package apiserver

View File

@ -1,48 +0,0 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
)
type AuthenticationRequest struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Token string `json:"token,omitempty"`
Captcha string `json:"captcha,omitempty"`
Phone string `json:"phone,omitempty"`
IP string `json:"ip,omitempty"`
}
type AuthenticationResponse struct {
Token string `json:"token,omitempty"`
UID uint64 `json:"uid,omitempty"`
Username string `json:"username,omitempty"`
Nickname string `json:"nickname,omitempty"`
Avatar string `json:"avatar,omitempty"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
CreatedAt uint `json:"created_at,omitempty"`
UpdatedAt uint `json:"updated_at,omitempty"`
Code int `json:"-"`
}
// type IdentifyResult struct {
// KubernetesToken string
// Cert string
// }
// 验证账号密码的方法这里想把这一块单独剥离出去这样不同的auth就更加抽象化
type IdentifyFunc func(*AuthenticationRequest) (*AuthenticationResponse, error)
type AuthManager interface {
Login(IdentifyFunc, *AuthenticationRequest) (*AuthenticationResponse, error)
Logout(*AuthenticationRequest) error
Refresh(*AuthenticationRequest) (string, error)
MiddleWare() gin.HandlerFunc
// InitAuthRoute(IdentifyFunc, *gin.RouterGroup)
ExpireAt(uint64, time.Time) error
Expire(uint64, time.Duration) error
TTL(uint64) (time.Duration, error)
}

View File

@ -1,53 +0,0 @@
package jwt
import (
"fmt"
"time"
gojwt "github.com/golang-jwt/jwt"
)
type TokenClaim struct {
User string `json:"-"`
UserID uint64 `json:"userId"`
gojwt.StandardClaims
Expiration time.Duration `json:"-"`
}
func ParseTokenClaim(token string, secret string) (*TokenClaim, error) {
tokenClaims, err := gojwt.ParseWithClaims(token, &TokenClaim{}, func(token *gojwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*TokenClaim); ok {
return claims, nil
}
}
//
return nil, err
}
func NewTokenClaim(user string, expiration time.Duration, uid uint64) (*TokenClaim, error) {
if int64(expiration) < 0 {
return nil, fmt.Errorf("expired at invalid")
}
claim := TokenClaim{
User: user,
StandardClaims: gojwt.StandardClaims{
// ExpiresAt: time.Now().Add(expiration).Unix(),
},
UserID: uid,
}
return &claim, nil
}
func (t *TokenClaim) InValid() bool {
return t.Valid() != nil
}
func (t *TokenClaim) String(secret string) (string, error) {
tokenClaims := gojwt.NewWithClaims(gojwt.SigningMethodHS256, t)
token, err := tokenClaims.SignedString([]byte(secret))
return token, err
}

View File

@ -1,185 +0,0 @@
package jwt
import (
"errors"
"fmt"
"strconv"
"time"
"biblio.bing89.com/auth"
"biblio.bing89.com/auth/jwt/store"
"biblio.bing89.com/code"
"biblio.bing89.com/utils/ginhelper"
"github.com/gin-gonic/gin"
)
type manager struct {
store store.ClaimStore
term time.Duration
signedSecret string
}
func NewManager(store store.ClaimStore, term time.Duration, secret string) auth.AuthManager {
return &manager{
store: store,
term: term,
signedSecret: secret,
}
}
func (m *manager) Login(identifyFunc auth.IdentifyFunc, data *auth.AuthenticationRequest) (*auth.AuthenticationResponse, error) {
// if _, err := m.IsLogined(data.Username); err == nil {
// return nil, fmt.Errorf("user is already logined")
// }
resp, err := identifyFunc(data)
if err != nil {
return nil, err
}
tokenClaim, err := m.IsLogined(resp.UID)
if err == nil && tokenClaim != nil { //已登录
//刷新过期时间
err = m.Expire(tokenClaim.UserID, m.term)
tokenString, err1 := tokenClaim.String(m.signedSecret)
if err != nil || tokenString == "" {
return nil, fmt.Errorf("get token string failed:%v", err1)
}
resp.Token = tokenString
if err != nil {
return resp, fmt.Errorf("update token expiration failed:%v", err)
}
return resp, nil
}
//未登录
tokenClaim, err = NewTokenClaim(data.Username, m.term, resp.UID)
if err != nil {
return nil, fmt.Errorf("generate token failed:%v", err)
}
tokenString, err := tokenClaim.String(m.signedSecret)
if err != nil {
return nil, fmt.Errorf("get token string failed:%v", err)
}
//存储登录状态
err = m.StoreLoginState(resp.UID, tokenClaim)
if err != nil {
return nil, fmt.Errorf("StoreLoginState failed:%v", err)
}
resp.Token = tokenString
return resp, nil
}
func (m *manager) Logout(data *auth.AuthenticationRequest) error {
//解析token确认有logout权限
claim, err := ParseTokenClaim(data.Token, m.signedSecret)
if err != nil {
return err
}
if c, err := m.IsLogined(claim.UserID); err == nil {
err = m.DeleteToken(c)
return err
}
return fmt.Errorf("user not login or token invalid")
}
func (m *manager) Refresh(data *auth.AuthenticationRequest) (string, error) {
cliam, err := ParseTokenClaim(data.Token, m.signedSecret)
if err != nil {
return "", err
}
//已过期
if cliam.Valid() != nil {
return "", fmt.Errorf("cannot use an invalid token to refresh: %v", err)
}
//找不到登陆状态
if _, err := m.IsLogined(cliam.UserID); err != nil {
return "", fmt.Errorf("token invalid, user maybe not login")
}
//重置有效期
cliam.ExpiresAt = time.Now().Add(m.term).Unix()
err = m.StoreLoginState(cliam.UserID, cliam)
if err != nil {
return "", err
}
tokenStr, err := cliam.String(m.signedSecret)
return tokenStr, err
}
//中间件
//ERR_NOT_AUTH
func (m *manager) MiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Token")
if tokenString == "" {
ginhelper.Error(c, code.CodeNoAuth, errors.New("token is empty"))
return
}
tokenClaim, err := ParseTokenClaim(tokenString, m.signedSecret)
if err != nil {
ginhelper.Error(c, code.CodeNoAuth,err)
return
}
if err := m.TokenValid(tokenClaim.UserID, tokenString); err != nil {
ginhelper.Error(c, code.CodeNoAuth, err)
return
}
c.Set("uid", strconv.FormatUint(tokenClaim.UserID, 10))
c.Next()
}
}
//存储登录状态
func (m *manager) StoreLoginState(user uint64, claim *TokenClaim) error {
//储存登录状态
str, err := claim.String(m.signedSecret)
if err != nil {
return err
}
return m.store.Set(user, str, m.term)
}
//获取token
//是否已登录
func (m *manager) IsLogined(user uint64) (*TokenClaim, error) {
token, err := m.store.Get(user)
if err != nil {
return nil, err
}
return ParseTokenClaim(token, m.signedSecret)
}
//删除token
func (m *manager) DeleteToken(claim *TokenClaim) error {
return m.store.Delete(claim.UserID)
}
func (m *manager) Close() error {
return m.store.Close()
}
func (m *manager) TokenValid(uid uint64, token string) error {
t, err := m.store.Get(uid)
if err != nil {
return fmt.Errorf("get token failed: %v", err)
}
if t != token {
return fmt.Errorf("token is invalid")
}
return nil
}
func (m *manager) ExpireAt(uid uint64, t time.Time) error {
err := m.store.ExpireAt(uid, t)
return err
}
func (m *manager) Expire(uid uint64, t time.Duration) error {
err := m.store.Expire(uid, t)
return err
}
func (m *manager) TTL(uid uint64) (time.Duration, error) {
return m.store.TTL(uid)
}

View File

@ -1,74 +0,0 @@
package store
import (
"context"
"strconv"
"time"
"github.com/go-redis/redis/v8"
)
type ClaimStore interface {
Get(uint64) (string, error)
Set(uint64, string, time.Duration) error
Delete(uint64) error
Close() error
ExpireAt(uint64, time.Time) error
Expire(uint64, time.Duration) error
TTL(uint64) (time.Duration, error)
}
type redisStore struct {
host string
password string
db int
client *redis.Client
}
func NewRedis(host string, password string, db int) (ClaimStore, error) {
r := redisStore{
host: host,
password: password,
db: db,
}
r.client = redis.NewClient(&redis.Options{Addr: host, Password: password, DB: db})
return &r, nil
}
func (r *redisStore) Get(key uint64) (string, error) {
val, err := r.client.Get(context.Background(), r.key(key)).Result()
return val, err
}
func (r *redisStore) Set(key uint64, val string, expiration time.Duration) error {
err := r.client.SetEX(context.Background(), r.key(key), val, expiration).Err()
return err
}
func (r *redisStore) Delete(key uint64) error {
err := r.client.Del(context.Background(), r.key(key)).Err()
return err
}
func (r *redisStore) Close() error {
return r.client.Close()
}
func (r *redisStore) key(key uint64) string {
return "auth_token:" + strconv.FormatUint(key, 10)
}
func (r *redisStore) ExpireAt(key uint64, t time.Time) error {
err := r.client.ExpireAt(context.Background(), r.key(key), t).Err()
return err
}
func (r *redisStore) Expire(key uint64, term time.Duration) error {
err := r.client.Expire(context.Background(), r.key(key), term).Err()
return err
}
func (r *redisStore) TTL(key uint64) (time.Duration, error) {
expire, err := r.client.TTL(context.Background(), r.key(key)).Result()
return expire, err
}

View File

@ -1,16 +0,0 @@
package code
const (
CodeArgsInvalid = iota + 400000
)
const (
CodeDatabase = iota + 400100
)
const (
CodeNoAuth = iota + 403000
CodeAuthFailed
CodePasswordInvalid
CodeUserNotExist
)

View File

@ -1,29 +0,0 @@
package conf
import (
"errors"
"os"
"gopkg.in/yaml.v2"
)
type Configuration struct {
ApiVersion string `json:"apiVersion" yaml:"apiVersion"`
Port int `json:"port" yaml:"port"`
MySQL MySQL `json:"mysql" yaml:"mysql"`
Redis Redis `json:"redis" yaml:"redis"`
}
func NewConfiguration(file string)(*Configuration, error){
if file == "" {
return nil ,errors.New("file not exist")
}
data, err := os.ReadFile(file)
if err != nil {
return nil, err
}
c := &Configuration{}
err = yaml.Unmarshal(data, c)
return c, err
}

View File

@ -1,9 +0,0 @@
package conf
type MySQL struct {
Host string `json:"host" yaml:"host"`
Port int `json:"port" yaml:"port"`
Database string `json:"database" yaml:"database"`
Username string `json:"username" yaml:"username"`
Password string `json:"password" yaml:"password"`
}

View File

@ -1,8 +0,0 @@
package conf
type Redis struct {
Host string `json:"host" yaml:"host"`
Port int `json:"port" yaml:"port"`
Database int `json:"database" yaml:"database"`
Password string `json:"password" yaml:"password"`
}

35
go.mod
View File

@ -1,35 +0,0 @@
module biblio.bing89.com
go 1.19
require (
github.com/gin-gonic/gin v1.8.1
github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt v3.2.2+incompatible
gorm.io/gorm v1.23.10
)
require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.10.0 // indirect
github.com/goccy/go-json v0.9.7 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

109
go.sum
View File

@ -1,109 +0,0 @@
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
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.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
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/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
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/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.23.10 h1:4Ne9ZbzID9GUxRkllxN4WjJKpsHx8YbKvekVdgyWh24=
gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=

View File

@ -1 +0,0 @@
package main

View File

@ -1,25 +0,0 @@
package types
import "gorm.io/gorm"
/*
drop table if exists books;
create table if not exists books (
id int unsigned auto_increment primary key,
name varchar(32) not null comment '',
category int unsigned default 0 comment '',
avatar varchar(128) default '' comment '',
filename varchar(128) not null comment '',
created_at bigint default 0 comment '',
updated_at bigint default 0 comment '',
deleted_at bigint default 0 comment ''
);
*/
type Book struct {
gorm.Model
Name string `json:"name" gorm:"type:varchar(32)"`
Category uint `json:"category"`
Avatar string `json:"avatar" gorm:"type:varchar(128)"`
Filename string `json:"filename" gorm:"type:varchar(128)"`
}

View File

@ -1,27 +0,0 @@
package types
import "gorm.io/gorm"
/*
drop table if exists catecories;
create table if not exists categories (
id int unsigned auto_increment primary key,
name varchar(32) not null comment '',
description varchar(256) default '' comment '',
parent int unsigned default 0 comment '',
avatar varchar(128) default '' comment '',
created_at bigint default 0 comment '',
updated_at bigint default 0 comment '',
deleted_at bigint default 0 comment '',
unique(name,parent)
);
*/
type Category struct {
gorm.Model
Name string `json:"name" gorm:"type:varchar(32)"`
Parent uint `json:"category"`
Avatar string `json:"avatar" gorm:"type:varchar(128)"`
Description string `json:"description" gorm:"type:varchar(256)"`
}

View File

@ -1,27 +0,0 @@
package types
import "gorm.io/gorm"
/*
drop table if exists users;
create table if not exists users(
id int unsigned auto_increment primary key,
username varchar(32) not null comment '',
passwd varchar(128) not null comment '',
nikename varchar(32) default '' comment '',
phone char(11) default '' comment '',
email varchar(64) default '' comment '',
created_at bigint default 0 comment '',
updated_at bigint default 0 comment '',
deleted_at bigint default 0 comment '',
unique(username)
);
*/
type User struct {
gorm.Model
Name string `json:"name" gorm:"type:varchar(32);unique;not null"`
Password string `json:"-" gorm:"type:varchar(128);not null"`
Nickname string `json:"nickname" gorm:"type:varchar(32)"`
Phone string `json:"phone" gorm:"type:char(11)"`
Email string `json:"email" gorm:"type:varchar(64)"`
}

View File

@ -1,32 +0,0 @@
package ginhelper
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
const MessageSuccess="success"
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
func Success(c *gin.Context, data interface{}){
c.JSON(http.StatusOK, &Response{Code: 0,
Message: MessageSuccess,
Data: data,
})
}
func Error(c *gin.Context, code int, err error){
c.JSON(http.StatusOK, &Response{Code: code, Message: err.Error(), Data: nil})
}
func ErrorWithLog(c *gin.Context, code int, err error){
log.Println(err)
Error(c, code, err)
}