package api import ( "net/http" "unicode" "github.com/gin-gonic/gin" "github.com/jloup/utils" ) var CONFIG Config var MAIL_CONFIG MailConfig type MailConfig struct { IsEnabled bool SmtpAddress string `toml:"smtp_address"` AddressFrom string `toml:"address_from"` Login string `toml:"login"` Password string `toml:"password"` } type Config struct { Domain string `toml:"domain"` JwtSecret string `toml:"jwt_secret"` PasswordResetSecret string `toml:"password_reset_secret"` FreeSMSUser string `toml:"free_sms_user"` FreeSMSPass string `toml:"free_sms_pass"` } func SetConfig(config Config) { CONFIG = config JWT_SECRET = []byte(config.JwtSecret) PASSWORD_RESET_SECRET = []byte(config.PasswordResetSecret) } func SetMailConfig(config MailConfig) { MAIL_CONFIG = config if config.Login != "" && config.AddressFrom != "" && config.Password != "" && config.SmtpAddress != "" { MAIL_CONFIG.IsEnabled = true ConfigureMailTemplateEngine() } } type Error struct { Code utils.Flag UserMessage string err error } func (e Error) FlagString() string { return e.Code.String() } func (e Error) Flag() utils.Flag { return e.Code } func (e Error) Msg() string { return e.UserMessage } func (e Error) ErrorWithCode(f utils.Flag) utils.ErrorFlagged { if utils.Intersect(e.Code, f) { return e } return nil } func (e Error) Err() error { if e.err != nil { return e } return nil } func (e Error) Error() string { if e.err != nil { return e.err.Error() } return "" } func ErrorIs(err error, code utils.Flag) bool { if err == nil { return false } if apiError, ok := err.(*Error); !ok { return false } else { return utils.Intersect(apiError.Code, code) && apiError.Code.String() == code.String() } } func NewInternalError(err error) *Error { if apiError, ok := err.(*Error); ok { return apiError } return &Error{InternalError, "internal error", err} } func ToSnake(in string) string { runes := []rune(in) length := len(runes) var out []rune for i := 0; i < length; i++ { if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) { out = append(out, '_') } out = append(out, unicode.ToLower(runes[i])) } return string(out) } type Response struct { StatusCode Status `json:"-"` ErrorCode utils.Flag `json:"-"` Status string `json:"status"` Code string `json:"code,omitempty"` Response interface{} `json:"response,omitempty"` Message string `json:"message,omitempty"` } func (r Response) populateStatus() Response { r.Status = ToSnake(r.StatusCode.String()) r.Code = ToSnake(r.ErrorCode.String()) return r } func ErrorResponse(code utils.Flag, message string) Response { return Response{ StatusCode: NOK, ErrorCode: code, Message: message, } } func SuccessResponse(data interface{}) Response { return Response{ StatusCode: OK, Response: data, } } func WriteJsonResponse(response Response, c *gin.Context) { response = response.populateStatus() c.JSON(StatusToHttpCode(response.StatusCode, response.ErrorCode), response) } func WriteBinary(contentType string, b []byte, c *gin.Context) { c.Data(http.StatusOK, contentType, b) } type Middleware func(*gin.Context) *Error func M(handler Middleware) gin.HandlerFunc { return func(c *gin.Context) { err := handler(c) if err != nil { WriteJsonResponse(ErrorResponse(err.Flag(), err.UserMessage), c) c.Error(err) c.Abort() } else { c.Next() } } } type Query interface { ValidateParams() *Error Run() (interface{}, *Error) } func RunQuery(query Query, c *gin.Context) { if err := query.ValidateParams(); err != nil { WriteJsonResponse(ErrorResponse(err.Flag(), err.UserMessage), c) c.Error(err) return } if out, err := query.Run(); err != nil { WriteJsonResponse(ErrorResponse(err.Flag(), err.UserMessage), c) c.Error(err) } else { WriteJsonResponse(SuccessResponse(out), c) } }