update new route middlewares
This commit is contained in:
parent
77cc488d89
commit
b3a93abfb9
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
static/bundle.go
|
||||||
|
spec.json
|
2
Makefile
2
Makefile
@ -24,7 +24,7 @@ clean:
|
|||||||
generate-spec:
|
generate-spec:
|
||||||
swagger generate spec -m --compact -o spec.json
|
swagger generate spec -m --compact -o spec.json
|
||||||
|
|
||||||
build-static:
|
bundle-static:
|
||||||
go-bindata -fs -pkg static -ignore .git -o static/bundle.go public/ schema/ spec.json
|
go-bindata -fs -pkg static -ignore .git -o static/bundle.go public/ schema/ spec.json
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
2
go.mod
2
go.mod
@ -5,6 +5,7 @@ go 1.14
|
|||||||
require (
|
require (
|
||||||
git.trj.tw/golang/argparse v1.0.1
|
git.trj.tw/golang/argparse v1.0.1
|
||||||
git.trj.tw/golang/config-loader v1.0.1
|
git.trj.tw/golang/config-loader v1.0.1
|
||||||
|
github.com/gabriel-vasile/mimetype v1.1.1
|
||||||
github.com/gin-gonic/gin v1.6.3
|
github.com/gin-gonic/gin v1.6.3
|
||||||
github.com/go-playground/validator/v10 v10.3.0 // indirect
|
github.com/go-playground/validator/v10 v10.3.0 // indirect
|
||||||
github.com/go-redis/redis v6.15.9+incompatible
|
github.com/go-redis/redis v6.15.9+incompatible
|
||||||
@ -16,4 +17,5 @@ require (
|
|||||||
github.com/onsi/ginkgo v1.14.0 // indirect
|
github.com/onsi/ginkgo v1.14.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200805065543-0cf7623e9dbd // indirect
|
golang.org/x/sys v0.0.0-20200805065543-0cf7623e9dbd // indirect
|
||||||
google.golang.org/protobuf v1.25.0 // indirect
|
google.golang.org/protobuf v1.25.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -17,6 +17,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.1.1 h1:qbN9MPuRf3bstHu9zkI9jDWNfH//9+9kHxr9oRBBBOA=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.1.1/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
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-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||||
|
@ -27,6 +27,28 @@ func (e *APIError) Error() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *APIError) SetCode(code response.MessageCode) *APIError {
|
||||||
|
e = &APIError{
|
||||||
|
status: e.status,
|
||||||
|
code: &code,
|
||||||
|
message: e.message,
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIError) SetMessage(s string) *APIError {
|
||||||
|
e = &APIError{
|
||||||
|
status: e.status,
|
||||||
|
code: e.code,
|
||||||
|
message: s,
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIError) Code() *response.MessageCode { return e.code }
|
||||||
|
func (e *APIError) Status() response.RespType { return e.status }
|
||||||
|
|
||||||
func New(status response.RespType, code ...response.MessageCode) *APIError {
|
func New(status response.RespType, code ...response.MessageCode) *APIError {
|
||||||
e := &APIError{
|
e := &APIError{
|
||||||
status: status,
|
status: status,
|
||||||
|
BIN
public/swagger/favicon-16x16.png
Normal file
BIN
public/swagger/favicon-16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 665 B |
BIN
public/swagger/favicon-32x32.png
Normal file
BIN
public/swagger/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 628 B |
61
public/swagger/index.html
Normal file
61
public/swagger/index.html
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
html
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after
|
||||||
|
{
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
margin:0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||||
|
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
docExpansion: 'none',
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
})
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
68
public/swagger/oauth2-redirect.html
Normal file
68
public/swagger/oauth2-redirect.html
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<title>Swagger UI: OAuth2 Redirect</title>
|
||||||
|
<body onload="run()">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
function run () {
|
||||||
|
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||||
|
var sentState = oauth2.state;
|
||||||
|
var redirectUrl = oauth2.redirectUrl;
|
||||||
|
var isValid, qp, arr;
|
||||||
|
|
||||||
|
if (/code|token|error/.test(window.location.hash)) {
|
||||||
|
qp = window.location.hash.substring(1);
|
||||||
|
} else {
|
||||||
|
qp = location.search.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arr = qp.split("&")
|
||||||
|
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||||
|
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||||
|
function (key, value) {
|
||||||
|
return key === "" ? value : decodeURIComponent(value)
|
||||||
|
}
|
||||||
|
) : {}
|
||||||
|
|
||||||
|
isValid = qp.state === sentState
|
||||||
|
|
||||||
|
if ((
|
||||||
|
oauth2.auth.schema.get("flow") === "accessCode"||
|
||||||
|
oauth2.auth.schema.get("flow") === "authorizationCode"
|
||||||
|
) && !oauth2.auth.code) {
|
||||||
|
if (!isValid) {
|
||||||
|
oauth2.errCb({
|
||||||
|
authId: oauth2.auth.name,
|
||||||
|
source: "auth",
|
||||||
|
level: "warning",
|
||||||
|
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qp.code) {
|
||||||
|
delete oauth2.state;
|
||||||
|
oauth2.auth.code = qp.code;
|
||||||
|
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||||
|
} else {
|
||||||
|
let oauthErrorMsg
|
||||||
|
if (qp.error) {
|
||||||
|
oauthErrorMsg = "["+qp.error+"]: " +
|
||||||
|
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||||
|
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
oauth2.errCb({
|
||||||
|
authId: oauth2.auth.name,
|
||||||
|
source: "auth",
|
||||||
|
level: "error",
|
||||||
|
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||||
|
}
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
</script>
|
92
public/swagger/swagger-ui-bundle.js
Normal file
92
public/swagger/swagger-ui-bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
public/swagger/swagger-ui-bundle.js.map
Normal file
1
public/swagger/swagger-ui-bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
9
public/swagger/swagger-ui-es-bundle-core.js
Normal file
9
public/swagger/swagger-ui-es-bundle-core.js
Normal file
File diff suppressed because one or more lines are too long
1
public/swagger/swagger-ui-es-bundle-core.js.map
Normal file
1
public/swagger/swagger-ui-es-bundle-core.js.map
Normal file
File diff suppressed because one or more lines are too long
92
public/swagger/swagger-ui-es-bundle.js
Normal file
92
public/swagger/swagger-ui-es-bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
public/swagger/swagger-ui-es-bundle.js.map
Normal file
1
public/swagger/swagger-ui-es-bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
22
public/swagger/swagger-ui-standalone-preset.js
Normal file
22
public/swagger/swagger-ui-standalone-preset.js
Normal file
File diff suppressed because one or more lines are too long
1
public/swagger/swagger-ui-standalone-preset.js.map
Normal file
1
public/swagger/swagger-ui-standalone-preset.js.map
Normal file
File diff suppressed because one or more lines are too long
4
public/swagger/swagger-ui.css
Normal file
4
public/swagger/swagger-ui.css
Normal file
File diff suppressed because one or more lines are too long
1
public/swagger/swagger-ui.css.map
Normal file
1
public/swagger/swagger-ui.css.map
Normal file
File diff suppressed because one or more lines are too long
9
public/swagger/swagger-ui.js
Normal file
9
public/swagger/swagger-ui.js
Normal file
File diff suppressed because one or more lines are too long
1
public/swagger/swagger-ui.js.map
Normal file
1
public/swagger/swagger-ui.js.map
Normal file
File diff suppressed because one or more lines are too long
9
router/controller/health.go
Normal file
9
router/controller/health.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import "go-api/pkg/context"
|
||||||
|
|
||||||
|
func Health() context.CustomHandler {
|
||||||
|
return func(c *context.C) {
|
||||||
|
c.String(200, "ok")
|
||||||
|
}
|
||||||
|
}
|
14
router/middleware/cors.go
Normal file
14
router/middleware/cors.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-contrib/cors"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Cors() gin.HandlerFunc {
|
||||||
|
corsOpts := cors.DefaultConfig()
|
||||||
|
corsOpts.AllowCredentials = true
|
||||||
|
corsOpts.AllowOriginFunc = func(origin string) bool { return origin != "" }
|
||||||
|
|
||||||
|
return cors.New(corsOpts)
|
||||||
|
}
|
53
router/middleware/panicCatch.go
Normal file
53
router/middleware/panicCatch.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-api/pkg/context"
|
||||||
|
apierr "go-api/pkg/errors"
|
||||||
|
"go-api/pkg/response"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ServerPanicCatch() context.CustomHandler {
|
||||||
|
return func(c *context.C) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
// show error Stack
|
||||||
|
// *****
|
||||||
|
builder := &strings.Builder{}
|
||||||
|
fmt.Printf("[Server Error Catch]\n")
|
||||||
|
|
||||||
|
pc := make([]uintptr, 10)
|
||||||
|
n := runtime.Callers(1, pc)
|
||||||
|
frames := runtime.CallersFrames(pc[:n])
|
||||||
|
for {
|
||||||
|
frame, more := frames.Next()
|
||||||
|
builder.WriteString(fmt.Sprintf("%s:%d %s\n", frame.File, frame.Line, frame.Function))
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// *****
|
||||||
|
|
||||||
|
var e *apierr.APIError
|
||||||
|
if convertedErr, ok := err.(*apierr.APIError); ok {
|
||||||
|
e = convertedErr
|
||||||
|
} else {
|
||||||
|
e = apierr.ErrInternalError
|
||||||
|
}
|
||||||
|
|
||||||
|
code := make([]response.MessageCode, 0)
|
||||||
|
if c := e.Code(); c != nil {
|
||||||
|
code = append(code, *c)
|
||||||
|
}
|
||||||
|
resp := response.Get(e.Status(), code...)
|
||||||
|
|
||||||
|
c.AbortWithStatusJSON(resp.Status, resp.Body)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
85
router/middleware/swaggerServe.go
Normal file
85
router/middleware/swaggerServe.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go-api/static"
|
||||||
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SwaggerOptions struct {
|
||||||
|
Root string
|
||||||
|
}
|
||||||
|
|
||||||
|
var regex = regexp.MustCompile(`(src|href)="./`)
|
||||||
|
var specRegex = regexp.MustCompile(`url:.+`)
|
||||||
|
|
||||||
|
func SwaggerSpecServe() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
b, err := static.GetSpec()
|
||||||
|
if err != nil {
|
||||||
|
c.String(http.StatusNotFound, "not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var j map[string]interface{}
|
||||||
|
if err := json.Unmarshal(b, &j); err != nil {
|
||||||
|
c.String(http.StatusInternalServerError, "internal error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := j["host"]; ok {
|
||||||
|
j["host"] = c.Request.Host
|
||||||
|
}
|
||||||
|
if xfp := c.Request.Header.Get(textproto.CanonicalMIMEHeaderKey("X-Forwarded-Proto")); xfp != "" && xfp == "https" {
|
||||||
|
j["schemes"] = []string{xfp}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SwaggerServe(prefix string, opts *SwaggerOptions) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
fp := c.Request.URL.Path
|
||||||
|
|
||||||
|
if prefix != "" {
|
||||||
|
if !strings.HasPrefix(fp, prefix) {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if fp = strings.Replace(fp, prefix, "", 1); fp == "" {
|
||||||
|
fp = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of slash replace to index.html file
|
||||||
|
if strings.HasSuffix(fp, "/") {
|
||||||
|
fp += "index.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, mime, err := static.GetWebFile(fp); err == nil {
|
||||||
|
// 如果是 index.html 要更新內部的連結 轉換成絕對路徑
|
||||||
|
if fp == "/index.html" {
|
||||||
|
replPrefix := prefix
|
||||||
|
if !strings.HasSuffix(replPrefix, "/") {
|
||||||
|
replPrefix += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
b = regex.ReplaceAll(b, []byte(fmt.Sprintf(`$1="%s`, replPrefix)))
|
||||||
|
b = specRegex.ReplaceAll(b, []byte(fmt.Sprintf(`url: '%s.json',`, prefix)))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Writer.Header().Set(textproto.CanonicalMIMEHeaderKey("Content-Type"), mime)
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
c.Writer.Write(b)
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,42 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"go-api/pkg/context"
|
||||||
|
"go-api/router/controller"
|
||||||
|
"go-api/router/middleware"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var patch = context.PatchContext
|
||||||
|
|
||||||
|
// New web server engine
|
||||||
func New() *gin.Engine {
|
func New() *gin.Engine {
|
||||||
e := gin.New()
|
e := gin.New()
|
||||||
|
|
||||||
e.Use(gin.Logger())
|
e.Use(gin.Logger())
|
||||||
e.Use(gin.Recovery())
|
e.Use(gin.Recovery())
|
||||||
|
e.Use(middleware.Cors())
|
||||||
|
|
||||||
|
// if in release mode dont serve swagger api docs
|
||||||
|
if os.Getenv("RELEASE") != "1" {
|
||||||
|
// serve static swagger ui
|
||||||
|
e.Use(middleware.SwaggerServe("/api-docs", nil))
|
||||||
|
}
|
||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRoute setup all routes
|
||||||
func SetRoute(e *gin.Engine) {
|
func SetRoute(e *gin.Engine) {
|
||||||
e.GET("/", func(c *gin.Context) {
|
e.GET("/", patch(controller.Health()))
|
||||||
c.String(http.StatusOK, "ok")
|
|
||||||
})
|
// if in release mode dont serve swagger api docs
|
||||||
|
if os.Getenv("RELEASE") != "1" {
|
||||||
|
e.GET("/api-docs.json", middleware.SwaggerSpecServe())
|
||||||
|
}
|
||||||
|
|
||||||
|
api := e.Group("/api", patch(middleware.ServerPanicCatch()))
|
||||||
|
_ = api
|
||||||
}
|
}
|
||||||
|
1
schema/mail.sql
Normal file
1
schema/mail.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
-- empty
|
3
schema/version.yml
Normal file
3
schema/version.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
versions:
|
||||||
|
- file: 'main.sql'
|
||||||
|
version: 1
|
62
static/static.go
Normal file
62
static/static.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gabriel-vasile/mimetype"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version db version info
|
||||||
|
type Version struct {
|
||||||
|
File string `yaml:"file"`
|
||||||
|
Version uint `yaml:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBVersion all versions
|
||||||
|
type DBVersion struct {
|
||||||
|
Versions []Version `yaml:"versions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBVersions() (*DBVersion, error) {
|
||||||
|
b, err := Asset("schema/version.yml")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ver := &DBVersion{}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(b, ver); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ver, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSQL(s string) ([]byte, error) {
|
||||||
|
return Asset(path.Join("schema", s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSpec() ([]byte, error) {
|
||||||
|
return Asset("spec.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWebFile(fp string) (body []byte, mime string, err error) {
|
||||||
|
p := filepath.Join("public", fp)
|
||||||
|
b, err := Asset(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
mt := mimetype.Detect(b)
|
||||||
|
mime = mt.String()
|
||||||
|
if strings.HasSuffix(fp, ".css") {
|
||||||
|
mime = "text/css"
|
||||||
|
} else if strings.HasSuffix(fp, ".js") {
|
||||||
|
mime = "text/javascript"
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, mime, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user