package utils
import (
"bytes"
"crypto/md5"
"database/sql"
"encoding/hex"
"fmt"
"html/template"
"math"
"mime/quotedprintable"
"net/http"
"net/smtp"
"os"
"regexp"
"strconv"
"strings"
"time"
"golang-fave/engine/assets"
"golang-fave/engine/consts"
)
func Trim(str string) string {
return strings.TrimSpace(str)
}
func IsFileExists(filename string) bool {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
if err == nil {
return true
}
}
return false
}
func IsRegularFileExists(filename string) bool {
if st, err := os.Stat(filename); !os.IsNotExist(err) {
if err == nil {
if !st.Mode().IsDir() {
return true
}
}
}
return false
}
func IsDir(filename string) bool {
if st, err := os.Stat(filename); !os.IsNotExist(err) {
if err == nil {
if st.Mode().IsDir() {
return true
}
}
}
return false
}
func IsDirExists(path string) bool {
if IsFileExists(path) && IsDir(path) {
return true
}
return false
}
func IsNumeric(str string) bool {
if _, err := strconv.Atoi(str); err == nil {
return true
}
return false
}
func IsFloat(str string) bool {
if _, err := strconv.ParseFloat(str, 64); err == nil {
return true
}
return false
}
func IsValidMobile(str string) bool {
regexpeChars := regexp.MustCompile(`^\+([0-9]{7,18})$`)
return regexpeChars.MatchString(str)
}
func IsValidEmail(email string) bool {
regexpe := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
return regexpe.MatchString(email)
}
func IsValidAlias(alias string) bool {
// Control panel
regexpeCP := regexp.MustCompile(`^\/cp\/`)
if alias == "/cp" || regexpeCP.MatchString(alias) {
return false
}
// Blog module
regexpeBlog := regexp.MustCompile(`^\/blog\/`)
if alias == "/blog" || regexpeBlog.MatchString(alias) {
return false
}
// Shop module
regexpeShop := regexp.MustCompile(`^\/shop\/`)
if alias == "/shop" || regexpeShop.MatchString(alias) {
return false
}
// API module
regexpeApi := regexp.MustCompile(`^\/api\/`)
if alias == "/api" || regexpeApi.MatchString(alias) {
return false
}
regexpeSlash := regexp.MustCompile(`[\/]{2,}`)
regexpeChars := regexp.MustCompile(`^\/([a-zA-Z0-9\/\-_\.]+)\/?$`)
return (!regexpeSlash.MatchString(alias) && regexpeChars.MatchString(alias)) || alias == "/"
}
func IsValidSingleAlias(alias string) bool {
regexpeChars := regexp.MustCompile(`^([a-zA-Z0-9\-_]{1,})$`)
return regexpeChars.MatchString(alias)
}
func FixPath(path string) string {
newPath := strings.TrimSpace(path)
if len(newPath) <= 0 {
return newPath
}
if newPath[len(newPath)-1] == '/' || newPath[len(newPath)-1] == '\\' {
newPath = newPath[0 : len(newPath)-1]
}
return newPath
}
func ExtractHostPort(host string, https bool) (string, string) {
h := host
p := "80"
if https {
p = "443"
}
i := strings.Index(h, ":")
if i > -1 {
p = h[i+1:]
h = h[0:i]
}
return h, p
}
func GetFileSize(filename string) int64 {
if st, err := os.Stat(filename); !os.IsNotExist(err) {
if err == nil {
if !st.Mode().IsDir() {
return st.Size()
}
}
}
return 0
}
func GetAssetsUrl(filename string) string {
return "/" + filename + "?v=" + consts.ServerVersion
}
func GetTmplSystemData(cpmod, cpsubmod string) consts.TmplSystem {
return consts.TmplSystem{
CpSubModule: cpsubmod,
InfoVersion: consts.ServerVersion,
PathCssBootstrap: GetAssetsUrl(consts.AssetsBootstrapCss),
PathCssCpCodeMirror: GetAssetsUrl(consts.AssetsCpCodeMirrorCss),
PathCssCpStyles: GetAssetsUrl(consts.AssetsCpStylesCss),
PathCssCpWysiwygPell: GetAssetsUrl(consts.AssetsCpWysiwygPellCss),
PathCssLightGallery: GetAssetsUrl(consts.AssetsLightGalleryCss),
PathCssStyles: GetAssetsUrl(consts.AssetsSysStylesCss),
PathIcoFav: GetAssetsUrl(consts.AssetsSysFaveIco),
PathJsBootstrap: GetAssetsUrl(consts.AssetsBootstrapJs),
PathJsCpCodeMirror: GetAssetsUrl(consts.AssetsCpCodeMirrorJs),
PathJsCpScripts: GetAssetsUrl(consts.AssetsCpScriptsJs),
PathJsCpWysiwygPell: GetAssetsUrl(consts.AssetsCpWysiwygPellJs),
PathJsJquery: GetAssetsUrl(consts.AssetsJqueryJs),
PathJsLightGallery: GetAssetsUrl(consts.AssetsLightGalleryJs),
PathJsPopper: GetAssetsUrl(consts.AssetsPopperJs),
PathSvgLogo: GetAssetsUrl(consts.AssetsSysLogoSvg),
PathThemeScripts: "/assets/theme/scripts.js?v=" + consts.ServerVersion,
PathThemeStyles: "/assets/theme/styles.css?v=" + consts.ServerVersion,
CpModule: cpmod,
}
}
func GetTmplError(err error) consts.TmplError {
return consts.TmplError{
ErrorMessage: err.Error(),
}
}
func GetMd5(str string) string {
hasher := md5.New()
hasher.Write([]byte(str))
return hex.EncodeToString(hasher.Sum(nil))
}
func GetCurrentUnixTimestamp() int64 {
return int64(time.Now().Unix())
}
func SystemRenderTemplate(w http.ResponseWriter, c []byte, d interface{}, cpmod, cpsubmod string) {
tmpl, err := template.New("template").Parse(string(c))
if err != nil {
SystemErrorPageEngine(w, err)
return
}
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Content-Type", "text/html")
tmpl.Execute(w, consts.TmplData{
System: GetTmplSystemData(cpmod, cpsubmod),
Data: d,
})
}
func SystemErrorPageEngine(w http.ResponseWriter, err error) {
if tmpl, e := template.New("template").Parse(string(assets.TmplPageErrorEngine)); e == nil {
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Content-Type", "text/html")
tmpl.Execute(w, consts.TmplData{
System: GetTmplSystemData("error", "engine"),
Data: GetTmplError(err),
})
return
}
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Content-Type", "text/html")
w.Write([]byte("
Critical engine error
"))
w.Write([]byte("" + err.Error() + "
"))
}
func SystemErrorPageTemplate(w http.ResponseWriter, err error) {
if tmpl, e := template.New("template").Parse(string(assets.TmplPageErrorTmpl)); e == nil {
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Content-Type", "text/html")
tmpl.Execute(w, consts.TmplData{
System: GetTmplSystemData("error", "template"),
Data: GetTmplError(err),
})
return
}
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Content-Type", "text/html")
w.Write([]byte("Critical engine error
"))
w.Write([]byte("" + err.Error() + "
"))
}
func SystemErrorPage404(w http.ResponseWriter) {
tmpl, err := template.New("template").Parse(string(assets.TmplPageError404))
if err != nil {
SystemErrorPageEngine(w, err)
return
}
w.WriteHeader(http.StatusNotFound)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Content-Type", "text/html")
tmpl.Execute(w, consts.TmplData{
System: GetTmplSystemData("error", "404"),
Data: nil,
})
}
func UrlToArray(url string) []string {
url_buff := url
// Remove GET parameters
i := strings.Index(url_buff, "?")
if i > -1 {
url_buff = url_buff[:i]
}
// Cut slashes
if len(url_buff) >= 1 && url_buff[:1] == "/" {
url_buff = url_buff[1:]
}
if len(url_buff) >= 1 && url_buff[len(url_buff)-1:] == "/" {
url_buff = url_buff[:len(url_buff)-1]
}
// Explode
if url_buff == "" {
return []string{}
} else {
return strings.Split(url_buff, "/")
}
}
func IntToStr(num int) string {
return fmt.Sprintf("%d", num)
}
func Int64ToStr(num int64) string {
return fmt.Sprintf("%d", num)
}
func StrToInt(str string) int {
num, err := strconv.Atoi(str)
if err == nil {
return num
}
return 0
}
func Float64ToStr(num float64) string {
return fmt.Sprintf("%.2f", num)
}
func Float64ToStrF(num float64, format string) string {
return fmt.Sprintf(format, num)
}
func StrToFloat64(str string) float64 {
num, err := strconv.ParseFloat(str, 64)
if err == nil {
return num
}
return 0
}
func GenerateAlias(str string) string {
if str == "" {
return ""
}
strc := []rune(str)
lat := []string{"EH", "I", "i", "#", "eh", "A", "B", "V", "G", "D", "E", "JO", "ZH", "Z", "I", "JJ", "K", "L", "M", "N", "O", "P", "R", "S", "T", "U", "F", "KH", "C", "CH", "SH", "SHH", "'", "Y", "", "EH", "YU", "YA", "a", "b", "v", "g", "d", "e", "jo", "zh", "z", "i", "jj", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "f", "kh", "c", "ch", "sh", "shh", "", "y", "", "eh", "yu", "ya", "", "", "-", "-", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "-", "-", ":", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Z", "X", "C", "V", "B", "N", "M"}
cyr := []string{"Є", "І", "і", "№", "є", "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", "З", "И", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы", "Ь", "Э", "Ю", "Я", "а", "б", "в", "г", "д", "е", "ё", "ж", "з", "и", "й", "к", "л", "м", "н", "о", "п", "р", "с", "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "ъ", "ы", "ь", "э", "ю", "я", "«", "»", "—", " ", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "", "", "a", "s", "d", "f", "g", "h", "j", "k", "l", "", "", "z", "x", "c", "v", "b", "n", "m", "", "", "", "(", ")", "", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Z", "X", "C", "V", "B", "N", "M"}
var alias string = ""
for i := 0; i < len(strc); i++ {
for j := 0; j < len(cyr); j++ {
if string(strc[i]) == cyr[j] {
alias += lat[j]
}
}
}
alias = strings.ToLower(alias)
// Cut repeated chars "-"
if reg, err := regexp.Compile(`[\-]+`); err == nil {
alias = strings.Trim(reg.ReplaceAllString(alias, "-"), "-")
}
alias = "/" + alias + "/"
// Cut repeated chars "/"
if reg, err := regexp.Compile("[/]+"); err == nil {
alias = reg.ReplaceAllString(alias, "/")
}
return alias
}
func GenerateSingleAlias(str string) string {
alias := GenerateAlias(str)
if len(alias) > 1 && alias[0] == '/' {
alias = alias[1:]
}
if len(alias) > 1 && alias[len(alias)-1] == '/' {
alias = alias[:len(alias)-1]
}
return alias
}
func UnixTimestampToMySqlDateTime(sec int64) string {
return time.Unix(sec, 0).Format("2006-01-02 15:04:05")
}
func UnixTimestampToFormat(sec int64, format string) string {
return time.Unix(sec, 0).Format(format)
}
func ExtractGetParams(str string) string {
i := strings.Index(str, "?")
if i == -1 {
return ""
}
return "?" + str[i+1:]
}
func JavaScriptVarValue(str string) string {
return strings.Replace(
strings.Replace(str, `'`, `’`, -1),
`"`,
`”`,
-1,
)
}
func InArrayInt(slice []int, value int) bool {
for _, item := range slice {
if item == value {
return true
}
}
return false
}
func InArrayString(slice []string, value string) bool {
for _, item := range slice {
if item == value {
return true
}
}
return false
}
func GetPostArrayInt(name string, r *http.Request) []int {
var ids []int
if arr, ok := r.PostForm[name]; ok {
for _, el := range arr {
if IsNumeric(el) {
if !InArrayInt(ids, StrToInt(el)) {
ids = append(ids, StrToInt(el))
}
}
}
}
return ids
}
func GetPostArrayString(name string, r *http.Request) []string {
var ids []string
if arr, ok := r.PostForm[name]; ok {
for _, el := range arr {
if !InArrayString(ids, el) {
ids = append(ids, el)
}
}
}
return ids
}
func ArrayOfIntToArrayOfString(arr []int) []string {
var res []string
for _, el := range arr {
res = append(res, IntToStr(el))
}
return res
}
func ArrayOfStringToArrayOfInt(arr []string) []int {
var res []int
for _, el := range arr {
if IsNumeric(el) {
res = append(res, StrToInt(el))
}
}
return res
}
func TemplateAdditionalFuncs() template.FuncMap {
return template.FuncMap{
"plus": func(a, b int) int {
return a + b
},
"minus": func(a, b int) int {
return a - b
},
"multiply": func(a, b int) int {
return a * b
},
"divide": func(a, b int) int {
return a / b
},
"repeat": func(a string, n int) template.HTML {
out := ""
for i := 1; i <= n; i++ {
out += a
}
return template.HTML(out)
},
}
}
func SqlNullStringToString(arr *[]sql.NullString) *[]string {
values := make([]string, len(*arr))
for key, value := range *arr {
values[key] = value.String
}
return &values
}
func GetImagePlaceholderSrc() string {
return "/" + consts.AssetsSysPlaceholderPng
}
func FormatProductPrice(price float64, format, round int) string {
p := price
if round == 1 {
p = math.Ceil(p)
} else if round == 2 {
p = math.Floor(p)
}
if format == 1 {
return Float64ToStrF(p, "%.1f")
} else if format == 2 {
return Float64ToStrF(p, "%.2f")
} else if format == 3 {
return Float64ToStrF(p, "%.3f")
} else if format == 4 {
return Float64ToStrF(p, "%.4f")
}
return Float64ToStrF(p, "%.0f")
}
func SMTPSend(host, port, user, pass, subject, msg string, receivers []string) error {
header := make(map[string]string)
header["From"] = user
header["To"] = strings.Join(receivers, ", ")
header["Subject"] = subject
header["MIME-Version"] = "1.0"
header["Content-Type"] = fmt.Sprintf("%s; charset=\"utf-8\"", "text/html")
header["Content-Transfer-Encoding"] = "quoted-printable"
header["Content-Disposition"] = "inline"
message := ""
for key, value := range header {
message += fmt.Sprintf("%s: %s\r\n", key, value)
}
var encodedMessage bytes.Buffer
finalMessage := quotedprintable.NewWriter(&encodedMessage)
finalMessage.Write([]byte(msg))
finalMessage.Close()
message += "\r\n" + encodedMessage.String()
return smtp.SendMail(
host+":"+port,
smtp.PlainAuth("", user, pass, host),
user,
receivers,
[]byte(message),
)
}
func SafeFilePath(path string) string {
result := path
if reg, err := regexp.Compile(`([/]+\.\.)|(\.\.[/]+)`); err == nil {
result = reg.ReplaceAllString(result, "/")
}
if reg, err := regexp.Compile(`([/]+[\.]+[/]+)`); err == nil {
result = reg.ReplaceAllString(result, "/")
}
if reg, err := regexp.Compile("([/]+)"); err == nil {
result = reg.ReplaceAllString(result, "/")
}
return result
}
func IsValidTemplateFileName(str string) bool {
regexpeChars := regexp.MustCompile(`^[0-9A-Za-z-]+$`)
return regexpeChars.MatchString(str)
}