æ·feat: commplete init process
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/astaxie/beego/validation"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"message-nest/pkg/e"
|
||||
"message-nest/pkg/util"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BindAndValid binds and validates data
|
||||
func BindAndValid(c *gin.Context, form interface{}) (int, int) {
|
||||
err := c.Bind(form)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, e.INVALID_PARAMS
|
||||
}
|
||||
|
||||
valid := validation.Validation{}
|
||||
check, err := valid.Valid(form)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, e.ERROR
|
||||
}
|
||||
if !check {
|
||||
MarkErrors(valid.Errors)
|
||||
return http.StatusBadRequest, e.INVALID_PARAMS
|
||||
}
|
||||
|
||||
return http.StatusOK, e.SUCCESS
|
||||
}
|
||||
|
||||
func CommonPlaygroundValid(obj interface{}) (int, string) {
|
||||
if err := util.CustomerValidate.Struct(obj); err != nil {
|
||||
errs := err.(validator.ValidationErrors)
|
||||
errMsg := BuildValidationErrors(errs)
|
||||
return http.StatusBadRequest, errMsg
|
||||
}
|
||||
return http.StatusOK, ""
|
||||
}
|
||||
|
||||
func BindJsonAndPlayValid(c *gin.Context, req interface{}) (int, string) {
|
||||
err := c.ShouldBindJSON(req)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err.Error()
|
||||
} else {
|
||||
return CommonPlaygroundValid(req)
|
||||
}
|
||||
}
|
||||
|
||||
func BuildValidationErrors(errors []validator.FieldError) string {
|
||||
var errorMsgBuilder strings.Builder
|
||||
for i, err := range errors {
|
||||
if i > 0 {
|
||||
errorMsgBuilder.WriteString("; ")
|
||||
}
|
||||
message := err.Translate(util.Trans)
|
||||
errorMsgBuilder.WriteString(fmt.Sprintf("%s", message))
|
||||
}
|
||||
return errorMsgBuilder.String()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/astaxie/beego/validation"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"message-nest/pkg/logging"
|
||||
)
|
||||
|
||||
// MarkErrors logs error logs
|
||||
func MarkErrors(errors []*validation.Error) {
|
||||
for _, err := range errors {
|
||||
logging.Logger.Error(err.Key, err.Message)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 从请求中获取当前用户
|
||||
func GetCurrentUserName(c *gin.Context) string {
|
||||
userName, ok := c.Get("currentUserName")
|
||||
if !ok {
|
||||
return ""
|
||||
} else {
|
||||
return fmt.Sprintf("%s", userName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
||||
"message-nest/pkg/e"
|
||||
)
|
||||
|
||||
type Gin struct {
|
||||
C *gin.Context
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// Response setting gin.JSON
|
||||
func (g *Gin) Response(httpCode, errCode int, data interface{}) {
|
||||
g.C.JSON(httpCode, Response{
|
||||
Code: errCode,
|
||||
Msg: e.GetMsg(errCode),
|
||||
Data: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Gin) CResponse(errCode int, Msg string, data interface{}) {
|
||||
g.C.JSON(http.StatusOK, Response{
|
||||
Code: errCode,
|
||||
Msg: Msg,
|
||||
Data: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package e
|
||||
|
||||
const (
|
||||
SUCCESS = 200
|
||||
ERROR = 500
|
||||
INVALID_PARAMS = 400
|
||||
|
||||
ERROR_EXIST_TAG = 10001
|
||||
ERROR_EXIST_TAG_FAIL = 10002
|
||||
ERROR_NOT_EXIST_TAG = 10003
|
||||
ERROR_GET_TAGS_FAIL = 10004
|
||||
ERROR_COUNT_TAG_FAIL = 10005
|
||||
ERROR_ADD_TAG_FAIL = 10006
|
||||
ERROR_EDIT_TAG_FAIL = 10007
|
||||
ERROR_DELETE_TAG_FAIL = 10008
|
||||
ERROR_EXPORT_TAG_FAIL = 10009
|
||||
ERROR_IMPORT_TAG_FAIL = 10010
|
||||
|
||||
ERROR_NOT_EXIST_ARTICLE = 10011
|
||||
ERROR_CHECK_EXIST_ARTICLE_FAIL = 10012
|
||||
ERROR_ADD_ARTICLE_FAIL = 10013
|
||||
ERROR_DELETE_ARTICLE_FAIL = 10014
|
||||
ERROR_EDIT_ARTICLE_FAIL = 10015
|
||||
ERROR_COUNT_ARTICLE_FAIL = 10016
|
||||
ERROR_GET_ARTICLES_FAIL = 10017
|
||||
ERROR_GET_ARTICLE_FAIL = 10018
|
||||
ERROR_GEN_ARTICLE_POSTER_FAIL = 10019
|
||||
|
||||
ERROR_AUTH_CHECK_TOKEN_FAIL = 20001
|
||||
ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002
|
||||
ERROR_AUTH_TOKEN = 20003
|
||||
ERROR_AUTH = 20004
|
||||
ERROR_AUTH_NO_TOKEN = 20005
|
||||
|
||||
ERROR_UPLOAD_SAVE_IMAGE_FAIL = 30001
|
||||
ERROR_UPLOAD_CHECK_IMAGE_FAIL = 30002
|
||||
ERROR_UPLOAD_CHECK_IMAGE_FORMAT = 30003
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
package e
|
||||
|
||||
var MsgFlags = map[int]string{
|
||||
SUCCESS: "ok",
|
||||
ERROR: "fail",
|
||||
INVALID_PARAMS: "请求参数错误",
|
||||
ERROR_EXIST_TAG: "已存在该标签名称",
|
||||
ERROR_EXIST_TAG_FAIL: "获取已存在标签失败",
|
||||
ERROR_NOT_EXIST_TAG: "该标签不存在",
|
||||
ERROR_GET_TAGS_FAIL: "获取所有标签失败",
|
||||
ERROR_COUNT_TAG_FAIL: "统计标签失败",
|
||||
ERROR_ADD_TAG_FAIL: "新增标签失败",
|
||||
ERROR_EDIT_TAG_FAIL: "修改标签失败",
|
||||
ERROR_DELETE_TAG_FAIL: "删除标签失败",
|
||||
ERROR_EXPORT_TAG_FAIL: "导出标签失败",
|
||||
ERROR_IMPORT_TAG_FAIL: "导入标签失败",
|
||||
ERROR_NOT_EXIST_ARTICLE: "该文章不存在",
|
||||
ERROR_ADD_ARTICLE_FAIL: "新增文章失败",
|
||||
ERROR_DELETE_ARTICLE_FAIL: "删除文章失败",
|
||||
ERROR_CHECK_EXIST_ARTICLE_FAIL: "检查文章是否存在失败",
|
||||
ERROR_EDIT_ARTICLE_FAIL: "修改文章失败",
|
||||
ERROR_COUNT_ARTICLE_FAIL: "统计文章失败",
|
||||
ERROR_GET_ARTICLES_FAIL: "获取多个文章失败",
|
||||
ERROR_GET_ARTICLE_FAIL: "获取单个文章失败",
|
||||
ERROR_GEN_ARTICLE_POSTER_FAIL: "生成文章海报失败",
|
||||
ERROR_AUTH_CHECK_TOKEN_FAIL: "Token鉴权失败",
|
||||
ERROR_AUTH_CHECK_TOKEN_TIMEOUT: "Token已超时",
|
||||
ERROR_AUTH_TOKEN: "Token生成失败",
|
||||
ERROR_AUTH_NO_TOKEN: "Token缺失",
|
||||
ERROR_AUTH: "Token错误",
|
||||
ERROR_UPLOAD_SAVE_IMAGE_FAIL: "保存图片失败",
|
||||
ERROR_UPLOAD_CHECK_IMAGE_FAIL: "检查图片失败",
|
||||
ERROR_UPLOAD_CHECK_IMAGE_FORMAT: "校验图片错误,图片格式或大小有问题",
|
||||
}
|
||||
|
||||
// GetMsg get error information based on Code
|
||||
func GetMsg(code int) string {
|
||||
msg, ok := MsgFlags[code]
|
||||
if ok {
|
||||
return msg
|
||||
}
|
||||
|
||||
return MsgFlags[ERROR]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"os"
|
||||
)
|
||||
|
||||
var Logger = logrus.New()
|
||||
|
||||
func Setup() {
|
||||
Logger := logrus.New()
|
||||
Logger.SetFormatter(&logrus.JSONFormatter{})
|
||||
Logger.SetOutput(os.Stdout)
|
||||
Logger.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package message
|
||||
|
||||
type DTalkMessage struct {
|
||||
WebhookUrl string
|
||||
}
|
||||
|
||||
func (d *DTalkMessage) send(content string) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/gomail.v2"
|
||||
)
|
||||
|
||||
type EmailMessage struct {
|
||||
Server string
|
||||
Port int
|
||||
Account string
|
||||
Passwd string
|
||||
GM *gomail.Dialer
|
||||
}
|
||||
|
||||
func (e *EmailMessage) Init(host string, port int, account string, passwd string) {
|
||||
e.Server = host
|
||||
e.Port = port
|
||||
e.Account = account
|
||||
e.Passwd = passwd
|
||||
e.GM = gomail.NewDialer(host, port, account, passwd)
|
||||
}
|
||||
|
||||
func (e *EmailMessage) SendTextMessage(toEmail string, title string, content string) string {
|
||||
m := gomail.NewMessage()
|
||||
m.SetHeader("From", e.Account)
|
||||
m.SetHeader("To", toEmail)
|
||||
m.SetHeader("Subject", title)
|
||||
m.SetBody("text/html", content)
|
||||
|
||||
if err := e.GM.DialAndSend(m); err != nil {
|
||||
return fmt.Sprintf("邮件发送失败: %s", err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *EmailMessage) SendHtmlMessage(toEmail string, title string, content string) string {
|
||||
return e.SendTextMessage(toEmail, title, content)
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/go-ini/ini"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
JwtSecret string
|
||||
PageSize int
|
||||
PrefixUrl string
|
||||
|
||||
RuntimeRootPath string
|
||||
|
||||
ImageSavePath string
|
||||
ImageMaxSize int
|
||||
ImageAllowExts []string
|
||||
|
||||
ExportSavePath string
|
||||
QrCodeSavePath string
|
||||
FontSavePath string
|
||||
|
||||
LogSavePath string
|
||||
LogSaveName string
|
||||
LogFileExt string
|
||||
TimeFormat string
|
||||
|
||||
LogKeepNum int
|
||||
CleanTaskLogID string
|
||||
}
|
||||
|
||||
var AppSetting = &App{}
|
||||
|
||||
type Server struct {
|
||||
RunMode string
|
||||
HttpPort int
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
}
|
||||
|
||||
var ServerSetting = &Server{}
|
||||
|
||||
type Database struct {
|
||||
Type string
|
||||
User string
|
||||
Password string
|
||||
Host string
|
||||
Name string
|
||||
TablePrefix string
|
||||
}
|
||||
|
||||
var DatabaseSetting = &Database{}
|
||||
|
||||
type Redis struct {
|
||||
Host string
|
||||
Password string
|
||||
MaxIdle int
|
||||
MaxActive int
|
||||
IdleTimeout time.Duration
|
||||
}
|
||||
|
||||
var RedisSetting = &Redis{}
|
||||
|
||||
var cfg *ini.File
|
||||
|
||||
// Setup initialize the configuration instance
|
||||
func Setup() {
|
||||
var err error
|
||||
cfg, err = ini.Load("conf/app.ini")
|
||||
if err != nil {
|
||||
log.Fatalf("setting.Setup, fail to parse 'conf/app.ini': %v", err)
|
||||
}
|
||||
|
||||
mapTo("app", AppSetting)
|
||||
mapTo("server", ServerSetting)
|
||||
mapTo("database", DatabaseSetting)
|
||||
mapTo("redis", RedisSetting)
|
||||
|
||||
AppSetting.ImageMaxSize = AppSetting.ImageMaxSize * 1024 * 1024
|
||||
ServerSetting.ReadTimeout = ServerSetting.ReadTimeout * time.Second
|
||||
ServerSetting.WriteTimeout = ServerSetting.WriteTimeout * time.Second
|
||||
RedisSetting.IdleTimeout = RedisSetting.IdleTimeout * time.Second
|
||||
|
||||
// 默认值
|
||||
AppSetting.LogKeepNum = 1000
|
||||
AppSetting.CleanTaskLogID = "00000000-0000-0000-0000-000000000001"
|
||||
}
|
||||
|
||||
// mapTo map section
|
||||
func mapTo(section string, v interface{}) {
|
||||
err := cfg.Section(section).MapTo(v)
|
||||
if err != nil {
|
||||
log.Fatalf("Cfg.MapTo %s err: %v", section, err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"message-nest/pkg/setting"
|
||||
)
|
||||
|
||||
var InsTableName string
|
||||
var WayTableName string
|
||||
var LogsTableName string
|
||||
var TasksTableName string
|
||||
|
||||
func Setup() {
|
||||
InsTableName = fmt.Sprintf("%ssend_tasks_ins", setting.DatabaseSetting.TablePrefix)
|
||||
WayTableName = fmt.Sprintf("%ssend_ways", setting.DatabaseSetting.TablePrefix)
|
||||
LogsTableName = fmt.Sprintf("%ssend_tasks_logs", setting.DatabaseSetting.TablePrefix)
|
||||
TasksTableName = fmt.Sprintf("%ssend_tasks", setting.DatabaseSetting.TablePrefix)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TimeStampToYmdMHD(stamp int) string {
|
||||
timestamp := int64(stamp)
|
||||
timeObj := time.Unix(timestamp, 0)
|
||||
formattedTime := timeObj.Format("2006-01-02 15:04:05")
|
||||
return formattedTime
|
||||
}
|
||||
|
||||
func GetNowTimeStampToYmdMHD() string {
|
||||
now := time.Now().Unix()
|
||||
timeObj := time.Unix(now, 0)
|
||||
formattedTime := timeObj.Format("2006-01-02 15:04:05")
|
||||
return formattedTime
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
var jwtSecret []byte
|
||||
|
||||
type Claims struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
// GenerateToken generate tokens used for auth
|
||||
func GenerateToken(username, password string) (string, error) {
|
||||
nowTime := time.Now()
|
||||
expireTime := nowTime.Add(7 * 24 * time.Hour)
|
||||
|
||||
claims := Claims{
|
||||
username,
|
||||
EncodeMD5(password),
|
||||
jwt.StandardClaims{
|
||||
ExpiresAt: expireTime.Unix(),
|
||||
Issuer: "message-nest",
|
||||
},
|
||||
}
|
||||
|
||||
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
token, err := tokenClaims.SignedString(jwtSecret)
|
||||
|
||||
return token, err
|
||||
}
|
||||
|
||||
// ParseToken parsing token
|
||||
func ParseToken(token string) (*Claims, error) {
|
||||
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwtSecret, nil
|
||||
})
|
||||
|
||||
if tokenClaims != nil {
|
||||
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// EncodeMD5 md5 encryption
|
||||
func EncodeMD5(value string) string {
|
||||
m := md5.New()
|
||||
m.Write([]byte(value))
|
||||
|
||||
return hex.EncodeToString(m.Sum(nil))
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/unknwon/com"
|
||||
|
||||
"message-nest/pkg/setting"
|
||||
)
|
||||
|
||||
// GetPage get page parameters
|
||||
func GetPage(c *gin.Context) int {
|
||||
result := 0
|
||||
page := com.StrTo(c.Query("page")).MustInt()
|
||||
if page > 0 {
|
||||
result = (page - 1) * setting.AppSetting.PageSize
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func GetPageSize(c *gin.Context) (int, int) {
|
||||
result := 0
|
||||
page := com.StrTo(c.Query("page")).MustInt()
|
||||
size := com.StrTo(c.Query("size")).MustInt()
|
||||
if page > 0 {
|
||||
result = (page - 1) * size
|
||||
}
|
||||
return result, size
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const timeFormat = "2006-01-02 15:04:05"
|
||||
const timezone = "Asia/Shanghai"
|
||||
|
||||
// 全局定义
|
||||
type Time time.Time
|
||||
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
b := make([]byte, 0, len(timeFormat)+2)
|
||||
b = append(b, '"')
|
||||
b = time.Time(t).AppendFormat(b, timeFormat)
|
||||
b = append(b, '"')
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||
now, err := time.ParseInLocation(`"`+timeFormat+`"`, string(data), time.Local)
|
||||
*t = Time(now)
|
||||
return
|
||||
}
|
||||
|
||||
func (t Time) String() string {
|
||||
return time.Time(t).Format(timeFormat)
|
||||
}
|
||||
|
||||
func (t Time) local() time.Time {
|
||||
loc, _ := time.LoadLocation(timezone)
|
||||
return time.Time(t).In(loc)
|
||||
}
|
||||
|
||||
func (t Time) Value() (driver.Value, error) {
|
||||
var zeroTime time.Time
|
||||
var ti = time.Time(t)
|
||||
if ti.UnixNano() == zeroTime.UnixNano() {
|
||||
return nil, nil
|
||||
}
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
func (t *Time) Scan(v interface{}) error {
|
||||
value, ok := v.(time.Time)
|
||||
if ok {
|
||||
*t = Time(value)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("can not convert %v to timestamp", v)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/go-playground/locales/en"
|
||||
"github.com/go-playground/locales/zh"
|
||||
"github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
zh_trans "github.com/go-playground/validator/v10/translations/zh"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//var trans ut.Translator
|
||||
|
||||
func TransInit() (trans ut.Translator, validate *validator.Validate) {
|
||||
// 创建翻译器
|
||||
zhTrans := zh.New() // 中文转换器
|
||||
enTrans := en.New() // 因为转换器
|
||||
|
||||
uni := ut.New(zhTrans, zhTrans, enTrans) // 创建一个通用转换器
|
||||
|
||||
curLocales := "zh" // 设置当前语言类型
|
||||
trans, _ = uni.GetTranslator(curLocales) // 获取对应语言的转换器
|
||||
|
||||
validate = validator.New() // 创建验证器
|
||||
_ = zh_trans.RegisterDefaultTranslations(validate, trans)
|
||||
|
||||
//switch curLocales {
|
||||
//case "zh":
|
||||
// // 内置tag注册 中文翻译器
|
||||
// _ = zh_trans.RegisterDefaultTranslations(validate, trans)
|
||||
//case "en":
|
||||
// // 内置tag注册 英文翻译器
|
||||
// _ = en_trans.RegisterDefaultTranslations(validate, trans)
|
||||
//}
|
||||
|
||||
// 注册 RegisterTagNameFunc
|
||||
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
|
||||
name := strings.SplitN(field.Tag.Get("label"), ",", 2)[0]
|
||||
if name == "-" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return name
|
||||
})
|
||||
return trans, validate
|
||||
}
|
||||
|
||||
var Trans, CustomerValidate = TransInit()
|
||||
@@ -0,0 +1,10 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"message-nest/pkg/setting"
|
||||
)
|
||||
|
||||
// Setup Initialize the util
|
||||
func Setup() {
|
||||
jwtSecret = []byte(setting.AppSetting.JwtSecret)
|
||||
}
|
||||
Reference in New Issue
Block a user