utils.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. package utils
  2. import (
  3. "crypto/md5"
  4. "database/sql"
  5. "encoding/hex"
  6. "fmt"
  7. "html/template"
  8. "math"
  9. "net/http"
  10. "os"
  11. "regexp"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "unicode/utf16"
  16. "golang-fave/assets"
  17. "golang-fave/consts"
  18. )
  19. func IsFileExists(filename string) bool {
  20. if _, err := os.Stat(filename); !os.IsNotExist(err) {
  21. if err == nil {
  22. return true
  23. }
  24. }
  25. return false
  26. }
  27. func IsDir(filename string) bool {
  28. if st, err := os.Stat(filename); !os.IsNotExist(err) {
  29. if err == nil {
  30. if st.Mode().IsDir() {
  31. return true
  32. }
  33. }
  34. }
  35. return false
  36. }
  37. func IsDirExists(path string) bool {
  38. if IsFileExists(path) && IsDir(path) {
  39. return true
  40. }
  41. return false
  42. }
  43. func IsNumeric(str string) bool {
  44. if _, err := strconv.Atoi(str); err == nil {
  45. return true
  46. }
  47. return false
  48. }
  49. func IsFloat(str string) bool {
  50. if _, err := strconv.ParseFloat(str, 64); err == nil {
  51. return true
  52. }
  53. return false
  54. }
  55. func IsValidEmail(email string) bool {
  56. regexpe := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
  57. return regexpe.MatchString(email)
  58. }
  59. func IsValidAlias(alias string) bool {
  60. // Control panel
  61. regexpeCP := regexp.MustCompile(`^\/cp\/`)
  62. if alias == "/cp" || regexpeCP.MatchString(alias) {
  63. return false
  64. }
  65. // Blog module
  66. regexpeBlog := regexp.MustCompile(`^\/blog\/`)
  67. if alias == "/blog" || regexpeBlog.MatchString(alias) {
  68. return false
  69. }
  70. // Shop module
  71. regexpeShop := regexp.MustCompile(`^\/shop\/`)
  72. if alias == "/shop" || regexpeShop.MatchString(alias) {
  73. return false
  74. }
  75. // API module
  76. regexpeApi := regexp.MustCompile(`^\/api\/`)
  77. if alias == "/api" || regexpeApi.MatchString(alias) {
  78. return false
  79. }
  80. regexpeSlash := regexp.MustCompile(`[\/]{2,}`)
  81. regexpeChars := regexp.MustCompile(`^\/([a-zA-Z0-9\/\-_\.]+)\/?$`)
  82. return (!regexpeSlash.MatchString(alias) && regexpeChars.MatchString(alias)) || alias == "/"
  83. }
  84. func IsValidSingleAlias(alias string) bool {
  85. regexpeChars := regexp.MustCompile(`^([a-zA-Z0-9\-_]{1,})$`)
  86. return regexpeChars.MatchString(alias)
  87. }
  88. func FixPath(path string) string {
  89. newPath := strings.TrimSpace(path)
  90. if len(newPath) <= 0 {
  91. return newPath
  92. }
  93. if newPath[len(newPath)-1] == '/' || newPath[len(newPath)-1] == '\\' {
  94. newPath = newPath[0 : len(newPath)-1]
  95. }
  96. return newPath
  97. }
  98. func ExtractHostPort(host string, https bool) (string, string) {
  99. h := host
  100. p := "80"
  101. if https {
  102. p = "443"
  103. }
  104. i := strings.Index(h, ":")
  105. if i > -1 {
  106. p = h[i+1:]
  107. h = h[0:i]
  108. }
  109. return h, p
  110. }
  111. func GetAssetsUrl(filename string) string {
  112. return "/" + filename + "?v=" + consts.ServerVersion
  113. }
  114. func GetTmplSystemData(cpmod, cpsubmod string) consts.TmplSystem {
  115. return consts.TmplSystem{
  116. CpSubModule: cpsubmod,
  117. InfoVersion: consts.ServerVersion,
  118. PathCssBootstrap: GetAssetsUrl(consts.AssetsBootstrapCss),
  119. PathCssCpCodeMirror: GetAssetsUrl(consts.AssetsCpCodeMirrorCss),
  120. PathCssCpStyles: GetAssetsUrl(consts.AssetsCpStylesCss),
  121. PathCssCpWysiwygPell: GetAssetsUrl(consts.AssetsCpWysiwygPellCss),
  122. PathCssLightGallery: GetAssetsUrl(consts.AssetsLightGalleryCss),
  123. PathCssStyles: GetAssetsUrl(consts.AssetsSysStylesCss),
  124. PathIcoFav: GetAssetsUrl(consts.AssetsSysFaveIco),
  125. PathJsBootstrap: GetAssetsUrl(consts.AssetsBootstrapJs),
  126. PathJsCpCodeMirror: GetAssetsUrl(consts.AssetsCpCodeMirrorJs),
  127. PathJsCpScripts: GetAssetsUrl(consts.AssetsCpScriptsJs),
  128. PathJsCpWysiwygPell: GetAssetsUrl(consts.AssetsCpWysiwygPellJs),
  129. PathJsJquery: GetAssetsUrl(consts.AssetsJqueryJs),
  130. PathJsLightGallery: GetAssetsUrl(consts.AssetsLightGalleryJs),
  131. PathJsPopper: GetAssetsUrl(consts.AssetsPopperJs),
  132. PathSvgLogo: GetAssetsUrl(consts.AssetsSysLogoSvg),
  133. PathThemeScripts: "/assets/theme/scripts.js?v=" + consts.ServerVersion,
  134. PathThemeStyles: "/assets/theme/styles.css?v=" + consts.ServerVersion,
  135. CpModule: cpmod,
  136. }
  137. }
  138. func GetTmplError(err error) consts.TmplError {
  139. return consts.TmplError{
  140. ErrorMessage: err.Error(),
  141. }
  142. }
  143. func GetMd5(str string) string {
  144. hasher := md5.New()
  145. hasher.Write([]byte(str))
  146. return hex.EncodeToString(hasher.Sum(nil))
  147. }
  148. func GetCurrentUnixTimestamp() int64 {
  149. return int64(time.Now().Unix())
  150. }
  151. func SystemRenderTemplate(w http.ResponseWriter, c []byte, d interface{}, cpmod, cpsubmod string) {
  152. tmpl, err := template.New("template").Parse(string(c))
  153. if err != nil {
  154. SystemErrorPageEngine(w, err)
  155. return
  156. }
  157. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  158. w.Header().Set("Content-Type", "text/html")
  159. tmpl.Execute(w, consts.TmplData{
  160. System: GetTmplSystemData(cpmod, cpsubmod),
  161. Data: d,
  162. })
  163. }
  164. func SystemErrorPageEngine(w http.ResponseWriter, err error) {
  165. if tmpl, e := template.New("template").Parse(string(assets.TmplPageErrorEngine)); e == nil {
  166. w.WriteHeader(http.StatusInternalServerError)
  167. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  168. w.Header().Set("Content-Type", "text/html")
  169. tmpl.Execute(w, consts.TmplData{
  170. System: GetTmplSystemData("error", "engine"),
  171. Data: GetTmplError(err),
  172. })
  173. return
  174. }
  175. w.WriteHeader(http.StatusInternalServerError)
  176. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  177. w.Header().Set("Content-Type", "text/html")
  178. w.Write([]byte("<h1>Critical engine error</h1>"))
  179. w.Write([]byte("<h2>" + err.Error() + "</h2>"))
  180. }
  181. func SystemErrorPageTemplate(w http.ResponseWriter, err error) {
  182. if tmpl, e := template.New("template").Parse(string(assets.TmplPageErrorTmpl)); e == nil {
  183. w.WriteHeader(http.StatusInternalServerError)
  184. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  185. w.Header().Set("Content-Type", "text/html")
  186. tmpl.Execute(w, consts.TmplData{
  187. System: GetTmplSystemData("error", "template"),
  188. Data: GetTmplError(err),
  189. })
  190. return
  191. }
  192. w.WriteHeader(http.StatusInternalServerError)
  193. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  194. w.Header().Set("Content-Type", "text/html")
  195. w.Write([]byte("<h1>Critical engine error</h1>"))
  196. w.Write([]byte("<h2>" + err.Error() + "</h2>"))
  197. }
  198. func SystemErrorPage404(w http.ResponseWriter) {
  199. tmpl, err := template.New("template").Parse(string(assets.TmplPageError404))
  200. if err != nil {
  201. SystemErrorPageEngine(w, err)
  202. return
  203. }
  204. w.WriteHeader(http.StatusNotFound)
  205. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  206. w.Header().Set("Content-Type", "text/html")
  207. tmpl.Execute(w, consts.TmplData{
  208. System: GetTmplSystemData("error", "404"),
  209. Data: nil,
  210. })
  211. }
  212. func UrlToArray(url string) []string {
  213. url_buff := url
  214. // Remove GET parameters
  215. i := strings.Index(url_buff, "?")
  216. if i > -1 {
  217. url_buff = url_buff[:i]
  218. }
  219. // Cut slashes
  220. if len(url_buff) >= 1 && url_buff[:1] == "/" {
  221. url_buff = url_buff[1:]
  222. }
  223. if len(url_buff) >= 1 && url_buff[len(url_buff)-1:] == "/" {
  224. url_buff = url_buff[:len(url_buff)-1]
  225. }
  226. // Explode
  227. if url_buff == "" {
  228. return []string{}
  229. } else {
  230. return strings.Split(url_buff, "/")
  231. }
  232. }
  233. func IntToStr(num int) string {
  234. return fmt.Sprintf("%d", num)
  235. }
  236. func Int64ToStr(num int64) string {
  237. return fmt.Sprintf("%d", num)
  238. }
  239. func StrToInt(str string) int {
  240. num, err := strconv.Atoi(str)
  241. if err == nil {
  242. return num
  243. }
  244. return 0
  245. }
  246. func Float64ToStr(num float64) string {
  247. return fmt.Sprintf("%.2f", num)
  248. }
  249. func Float64ToStrF(num float64, format string) string {
  250. return fmt.Sprintf(format, num)
  251. }
  252. func StrToFloat64(str string) float64 {
  253. num, err := strconv.ParseFloat(str, 64)
  254. if err == nil {
  255. return num
  256. }
  257. return 0
  258. }
  259. func GenerateAlias(str string) string {
  260. if str == "" {
  261. return ""
  262. }
  263. strc := utf16.Encode([]rune(str))
  264. 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"}
  265. 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"}
  266. var alias string = ""
  267. for i := 0; i < len(strc); i++ {
  268. for j := 0; j < len(cyr); j++ {
  269. if string(strc[i]) == cyr[j] {
  270. alias += lat[j]
  271. }
  272. }
  273. }
  274. alias = strings.ToLower(alias)
  275. // Cut repeated chars "-"
  276. if reg, err := regexp.Compile("[\\-]+"); err == nil {
  277. alias = strings.Trim(reg.ReplaceAllString(alias, "-"), "-")
  278. }
  279. alias = "/" + alias + "/"
  280. // Cut repeated chars "/"
  281. if reg, err := regexp.Compile("[/]+"); err == nil {
  282. alias = reg.ReplaceAllString(alias, "/")
  283. }
  284. return alias
  285. }
  286. func GenerateSingleAlias(str string) string {
  287. alias := GenerateAlias(str)
  288. if len(alias) > 1 && alias[0] == '/' {
  289. alias = alias[1:]
  290. }
  291. if len(alias) > 1 && alias[len(alias)-1] == '/' {
  292. alias = alias[:len(alias)-1]
  293. }
  294. return alias
  295. }
  296. func UnixTimestampToMySqlDateTime(sec int64) string {
  297. return time.Unix(sec, 0).Format("2006-01-02 15:04:05")
  298. }
  299. func UnixTimestampToFormat(sec int64, format string) string {
  300. return time.Unix(sec, 0).Format(format)
  301. }
  302. func ExtractGetParams(str string) string {
  303. i := strings.Index(str, "?")
  304. if i == -1 {
  305. return ""
  306. }
  307. return "?" + str[i+1:]
  308. }
  309. func JavaScriptVarValue(str string) string {
  310. return strings.Replace(
  311. strings.Replace(str, `'`, `&rsquo;`, -1),
  312. `"`,
  313. `&rdquo;`,
  314. -1,
  315. )
  316. }
  317. func InArrayInt(slice []int, value int) bool {
  318. for _, item := range slice {
  319. if item == value {
  320. return true
  321. }
  322. }
  323. return false
  324. }
  325. func InArrayString(slice []string, value string) bool {
  326. for _, item := range slice {
  327. if item == value {
  328. return true
  329. }
  330. }
  331. return false
  332. }
  333. func GetPostArrayInt(name string, r *http.Request) []int {
  334. var ids []int
  335. if arr, ok := r.PostForm[name]; ok {
  336. for _, el := range arr {
  337. if IsNumeric(el) {
  338. if !InArrayInt(ids, StrToInt(el)) {
  339. ids = append(ids, StrToInt(el))
  340. }
  341. }
  342. }
  343. }
  344. return ids
  345. }
  346. func GetPostArrayString(name string, r *http.Request) []string {
  347. var ids []string
  348. if arr, ok := r.PostForm[name]; ok {
  349. for _, el := range arr {
  350. if !InArrayString(ids, el) {
  351. ids = append(ids, el)
  352. }
  353. }
  354. }
  355. return ids
  356. }
  357. func ArrayOfIntToArrayOfString(arr []int) []string {
  358. var res []string
  359. for _, el := range arr {
  360. res = append(res, IntToStr(el))
  361. }
  362. return res
  363. }
  364. func ArrayOfStringToArrayOfInt(arr []string) []int {
  365. var res []int
  366. for _, el := range arr {
  367. if IsNumeric(el) {
  368. res = append(res, StrToInt(el))
  369. }
  370. }
  371. return res
  372. }
  373. func TemplateAdditionalFuncs() template.FuncMap {
  374. return template.FuncMap{
  375. "plus": func(a, b int) int {
  376. return a + b
  377. },
  378. "minus": func(a, b int) int {
  379. return a - b
  380. },
  381. "multiply": func(a, b int) int {
  382. return a * b
  383. },
  384. "divide": func(a, b int) int {
  385. return a / b
  386. },
  387. "repeat": func(a string, n int) template.HTML {
  388. out := ""
  389. for i := 1; i <= n; i++ {
  390. out += a
  391. }
  392. return template.HTML(out)
  393. },
  394. }
  395. }
  396. func SqlNullStringToString(arr *[]sql.NullString) *[]string {
  397. values := make([]string, len(*arr))
  398. for key, value := range *arr {
  399. values[key] = value.String
  400. }
  401. return &values
  402. }
  403. func GetImagePlaceholderSrc() string {
  404. return "/" + consts.AssetsSysPlaceholderPng
  405. }
  406. func FormatProductPrice(price float64, format, round int) string {
  407. p := price
  408. if round == 1 {
  409. p = math.Ceil(p)
  410. } else if round == 2 {
  411. p = math.Floor(p)
  412. }
  413. if format == 1 {
  414. return Float64ToStrF(p, "%.1f")
  415. } else if format == 2 {
  416. return Float64ToStrF(p, "%.2f")
  417. } else if format == 3 {
  418. return Float64ToStrF(p, "%.3f")
  419. } else if format == 4 {
  420. return Float64ToStrF(p, "%.4f")
  421. }
  422. return Float64ToStrF(p, "%.0f")
  423. }