wrapper.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. package wrapper
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "html/template"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "golang-fave/cblocks"
  14. "golang-fave/consts"
  15. "golang-fave/engine/mysqlpool"
  16. "golang-fave/engine/sqlw"
  17. "golang-fave/engine/wrapper/config"
  18. "golang-fave/logger"
  19. "golang-fave/utils"
  20. "github.com/vladimirok5959/golang-server-sessions/session"
  21. )
  22. type Tx = sqlw.Tx
  23. var ErrNoRows = sqlw.ErrNoRows
  24. type Wrapper struct {
  25. l *logger.Logger
  26. W http.ResponseWriter
  27. R *http.Request
  28. S *session.Session
  29. c *cblocks.CacheBlocks
  30. Host string
  31. Port string
  32. CurrHost string
  33. DConfig string
  34. DHtdocs string
  35. DLogs string
  36. DTemplate string
  37. DTmp string
  38. IsBackend bool
  39. ConfMysqlExists bool
  40. UrlArgs []string
  41. CurrModule string
  42. CurrSubModule string
  43. MSPool *mysqlpool.MySqlPool
  44. Config *config.Config
  45. DB *sqlw.DB
  46. User *utils.MySql_user
  47. }
  48. func New(l *logger.Logger, w http.ResponseWriter, r *http.Request, s *session.Session, c *cblocks.CacheBlocks, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp string, mp *mysqlpool.MySqlPool) *Wrapper {
  49. conf := config.ConfigNew()
  50. if err := conf.ConfigRead(dirConfig + string(os.PathSeparator) + "config.json"); err != nil {
  51. l.Log("Host config file: %s", r, true, err.Error())
  52. }
  53. return &Wrapper{
  54. l: l,
  55. W: w,
  56. R: r,
  57. S: s,
  58. c: c,
  59. Host: host,
  60. Port: port,
  61. CurrHost: chost,
  62. DConfig: dirConfig,
  63. DHtdocs: dirHtdocs,
  64. DLogs: dirLogs,
  65. DTemplate: dirTemplate,
  66. DTmp: dirTmp,
  67. UrlArgs: []string{},
  68. CurrModule: "",
  69. CurrSubModule: "",
  70. MSPool: mp,
  71. Config: conf,
  72. }
  73. }
  74. func (this *Wrapper) LogAccess(msg string, vars ...interface{}) {
  75. this.l.Log(msg, this.R, false, vars...)
  76. }
  77. func (this *Wrapper) LogError(msg string, vars ...interface{}) {
  78. this.l.Log(msg, this.R, true, vars...)
  79. }
  80. func (this *Wrapper) LogCpError(err *error) *error {
  81. if *err != nil {
  82. this.LogError("%s", *err)
  83. }
  84. return err
  85. }
  86. func (this *Wrapper) dbReconnect() error {
  87. if !utils.IsMySqlConfigExists(this.DConfig + string(os.PathSeparator) + "mysql.json") {
  88. return errors.New("can't read database configuration file")
  89. }
  90. mc, err := utils.MySqlConfigRead(this.DConfig + string(os.PathSeparator) + "mysql.json")
  91. if err != nil {
  92. return err
  93. }
  94. this.DB, err = sqlw.Open("mysql", mc.User+":"+mc.Password+"@tcp("+mc.Host+":"+mc.Port+")/"+mc.Name)
  95. if err != nil {
  96. return err
  97. }
  98. this.MSPool.Set(this.CurrHost, this.DB)
  99. return nil
  100. }
  101. func (this *Wrapper) UseDatabase() error {
  102. this.DB = this.MSPool.Get(this.CurrHost)
  103. if this.DB == nil {
  104. if err := this.dbReconnect(); err != nil {
  105. return err
  106. }
  107. }
  108. if err := this.DB.Ping(); err != nil {
  109. this.DB.Close()
  110. if err := this.dbReconnect(); err != nil {
  111. return err
  112. }
  113. if err := this.DB.Ping(); err != nil {
  114. this.DB.Close()
  115. return err
  116. }
  117. }
  118. // Max 60 minutes and max 4 connection per host
  119. this.DB.SetConnMaxLifetime(time.Minute * 60)
  120. this.DB.SetMaxIdleConns(4)
  121. this.DB.SetMaxOpenConns(4)
  122. return nil
  123. }
  124. func (this *Wrapper) LoadSessionUser() bool {
  125. if this.S.GetInt("UserId", 0) <= 0 {
  126. return false
  127. }
  128. if this.DB == nil {
  129. return false
  130. }
  131. user := &utils.MySql_user{}
  132. err := this.DB.QueryRow(`
  133. SELECT
  134. id,
  135. first_name,
  136. last_name,
  137. email,
  138. password,
  139. admin,
  140. active
  141. FROM
  142. users
  143. WHERE
  144. id = ?
  145. LIMIT 1;`,
  146. this.S.GetInt("UserId", 0),
  147. ).Scan(
  148. &user.A_id,
  149. &user.A_first_name,
  150. &user.A_last_name,
  151. &user.A_email,
  152. &user.A_password,
  153. &user.A_admin,
  154. &user.A_active,
  155. )
  156. if *this.LogCpError(&err) != nil {
  157. return false
  158. }
  159. if user.A_id != this.S.GetInt("UserId", 0) {
  160. return false
  161. }
  162. this.User = user
  163. return true
  164. }
  165. func (this *Wrapper) Write(data string) {
  166. this.W.Write([]byte(data))
  167. }
  168. func (this *Wrapper) MsgSuccess(msg string) {
  169. this.Write(fmt.Sprintf(
  170. `fave.ShowMsgSuccess('Success!', '%s', false);`,
  171. utils.JavaScriptVarValue(msg)))
  172. }
  173. func (this *Wrapper) MsgError(msg string) {
  174. this.Write(fmt.Sprintf(
  175. `fave.ShowMsgError('Error!', '%s', true);`,
  176. utils.JavaScriptVarValue(msg)))
  177. }
  178. func (this *Wrapper) RenderToString(tcont []byte, data interface{}) string {
  179. tmpl, err := template.New("template").Parse(string(tcont))
  180. if err != nil {
  181. return err.Error()
  182. }
  183. var tpl bytes.Buffer
  184. if err := tmpl.Execute(&tpl, data); err != nil {
  185. return err.Error()
  186. }
  187. return tpl.String()
  188. }
  189. func (this *Wrapper) RenderFrontEnd(tname string, data interface{}, status int) {
  190. tmpl, err := template.New(tname+".html").Funcs(utils.TemplateAdditionalFuncs()).ParseFiles(
  191. this.DTemplate+string(os.PathSeparator)+tname+".html",
  192. this.DTemplate+string(os.PathSeparator)+"header.html",
  193. this.DTemplate+string(os.PathSeparator)+"sidebar-left.html",
  194. this.DTemplate+string(os.PathSeparator)+"sidebar-right.html",
  195. this.DTemplate+string(os.PathSeparator)+"footer.html",
  196. )
  197. if err != nil {
  198. utils.SystemErrorPageTemplate(this.W, err)
  199. return
  200. }
  201. var tpl bytes.Buffer
  202. err = tmpl.Execute(&tpl, consts.TmplData{
  203. System: utils.GetTmplSystemData("", ""),
  204. Data: data,
  205. })
  206. if err != nil {
  207. utils.SystemErrorPageTemplate(this.W, err)
  208. return
  209. }
  210. this.W.WriteHeader(status)
  211. this.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  212. this.W.Header().Set("Content-Type", "text/html; charset=utf-8")
  213. this.W.Write(tpl.Bytes())
  214. }
  215. func (this *Wrapper) RenderBackEnd(tcont []byte, data interface{}) {
  216. tmpl, err := template.New("template").Parse(string(tcont))
  217. if err != nil {
  218. utils.SystemErrorPageEngine(this.W, err)
  219. return
  220. }
  221. this.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  222. this.W.Header().Set("Content-Type", "text/html; charset=utf-8")
  223. var tpl bytes.Buffer
  224. err = tmpl.Execute(this.W, consts.TmplData{
  225. System: utils.GetTmplSystemData(this.CurrModule, this.CurrSubModule),
  226. Data: data,
  227. })
  228. if err != nil {
  229. utils.SystemErrorPageEngine(this.W, err)
  230. return
  231. }
  232. this.W.Write(tpl.Bytes())
  233. }
  234. func (this *Wrapper) GetCurrentPage(max int) int {
  235. curr := 1
  236. page := this.R.URL.Query().Get("p")
  237. if page != "" {
  238. if i, err := strconv.Atoi(page); err == nil {
  239. if i < 1 {
  240. curr = 1
  241. } else if i > max {
  242. curr = max
  243. } else {
  244. curr = i
  245. }
  246. }
  247. }
  248. return curr
  249. }
  250. func (this *Wrapper) ConfigSave() error {
  251. return this.Config.ConfigWrite(this.DConfig + string(os.PathSeparator) + "config.json")
  252. }
  253. func (this *Wrapper) SendEmail(email, subject, message string) error {
  254. if _, err := this.DB.Exec(
  255. `INSERT INTO notify_mail SET
  256. id = NULL,
  257. email = ?,
  258. subject = ?,
  259. message = ?,
  260. error = '',
  261. datetime = ?,
  262. status = 2
  263. ;`,
  264. email,
  265. subject,
  266. message,
  267. utils.UnixTimestampToMySqlDateTime(utils.GetCurrentUnixTimestamp()),
  268. ); err != nil {
  269. return err
  270. }
  271. return nil
  272. }
  273. func (this *Wrapper) RecreateProductXmlFile() error {
  274. trigger := strings.Join([]string{this.DTmp, "trigger.xml.run"}, string(os.PathSeparator))
  275. if !utils.IsFileExists(trigger) {
  276. if _, err := os.Create(trigger); err != nil {
  277. return err
  278. }
  279. }
  280. return nil
  281. }
  282. func (this *Wrapper) RecreateProductImgFiles() error {
  283. trigger := strings.Join([]string{this.DTmp, "trigger.img.run"}, string(os.PathSeparator))
  284. if !utils.IsFileExists(trigger) {
  285. if _, err := os.Create(trigger); err != nil {
  286. return err
  287. }
  288. }
  289. return nil
  290. }
  291. func (this *Wrapper) RemoveProductImageThumbnails(product_id, filename string) error {
  292. pattern := this.DHtdocs + string(os.PathSeparator) + strings.Join([]string{"products", "images", product_id, filename}, string(os.PathSeparator))
  293. if files, err := filepath.Glob(pattern); err != nil {
  294. return err
  295. } else {
  296. for _, file := range files {
  297. if err := os.Remove(file); err != nil {
  298. return errors.New(fmt.Sprintf("[upload delete] Thumbnail file (%s) delete error: %s", file, err.Error()))
  299. }
  300. }
  301. }
  302. return this.RecreateProductImgFiles()
  303. }