aboutsummaryrefslogblamecommitdiff
path: root/api/api.go
blob: e01181123633e4a7112dd1124375ae8d7f5e680b (plain) (tree)
1
2
3
4
5
6
7
8
9








                                  
                 








                                                

                    
                                                  












                                                                  








                                                                                                                





















                                    











                                              
                                         


                                             

































































































                                                                                                                                         
package api

import (
	"net/http"
	"unicode"

	"github.com/gin-gonic/gin"
)

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        ErrorCode
	UserMessage string
	err         error
}

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 ErrorCode) bool {
	if err == nil {
		return false
	}

	if apiError, ok := err.(*Error); !ok {
		return false
	} else {
		return apiError.Code == code
	}
}

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  ErrorCode `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())

	if r.ErrorCode != 0 {
		r.Code = ToSnake(r.ErrorCode.String())
	}

	return r
}

func ErrorResponse(code ErrorCode, 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.Code, 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.Code, err.UserMessage), c)
		c.Error(err)
		return
	}

	if out, err := query.Run(); err != nil {
		WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
		c.Error(err)
	} else {
		WriteJsonResponse(SuccessResponse(out), c)
	}
}