包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、 antdesign(管理后台)、landingpage(营销落地页)、 数据库 SQL 和配置文件。
100 lines
2.8 KiB
Go
100 lines
2.8 KiB
Go
// Common tools and helper functions
|
|
package common
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gin-gonic/gin/binding"
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
|
|
|
// A helper function to generate random string
|
|
func RandString(n int) string {
|
|
b := make([]rune, n)
|
|
for i := range b {
|
|
randIdx, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
b[i] = letters[randIdx.Int64()]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// A helper function to generate random int
|
|
func RandInt() int {
|
|
randNum, err := rand.Int(rand.Reader, big.NewInt(1000000))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return int(randNum.Int64())
|
|
}
|
|
|
|
// Keep this two config private, it should not expose to open source
|
|
const JWTSecret = "A String Very Very Very Strong!!@##$!@#$" // #nosec G101
|
|
const RandomPassword = "A String Very Very Very Random!!@##$!@#4" // #nosec G101
|
|
|
|
// A Util function to generate jwt_token which can be used in the request header
|
|
func GenToken(id uint) string {
|
|
jwt_token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
"id": id,
|
|
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
|
})
|
|
// Sign and get the complete encoded token as a string
|
|
token, err := jwt_token.SignedString([]byte(JWTSecret))
|
|
if err != nil {
|
|
fmt.Printf("failed to sign JWT token for id %d: %v\n", id, err)
|
|
return ""
|
|
}
|
|
return token
|
|
}
|
|
|
|
// My own Error type that will help return my customized Error info
|
|
//
|
|
// {"database": {"hello":"no such table", error: "not_exists"}}
|
|
type CommonError struct {
|
|
Errors map[string]interface{} `json:"errors"`
|
|
}
|
|
|
|
// To handle the error returned by c.Bind in gin framework
|
|
// https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go
|
|
func NewValidatorError(err error) CommonError {
|
|
res := CommonError{}
|
|
res.Errors = make(map[string]interface{})
|
|
errs := err.(validator.ValidationErrors)
|
|
for _, v := range errs {
|
|
// can translate each error one at a time.
|
|
//fmt.Println("gg",v.NameNamespace)
|
|
if v.Param() != "" {
|
|
res.Errors[v.Field()] = fmt.Sprintf("{%v: %v}", v.Tag(), v.Param())
|
|
} else {
|
|
res.Errors[v.Field()] = fmt.Sprintf("{key: %v}", v.Tag())
|
|
}
|
|
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Wrap the error info in an object
|
|
func NewError(key string, err error) CommonError {
|
|
res := CommonError{}
|
|
res.Errors = make(map[string]interface{})
|
|
res.Errors[key] = err.Error()
|
|
return res
|
|
}
|
|
|
|
// Changed the c.MustBindWith() -> c.ShouldBindWith().
|
|
// I don't want to auto return 400 when error happened.
|
|
// origin function is here: https://github.com/gin-gonic/gin/blob/master/context.go
|
|
func Bind(c *gin.Context, obj interface{}) error {
|
|
b := binding.Default(c.Request.Method, c.ContentType())
|
|
return c.ShouldBindWith(obj, b)
|
|
}
|