module_index.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. package modules
  2. import (
  3. "database/sql"
  4. _ "github.com/go-sql-driver/mysql"
  5. "fmt"
  6. "html"
  7. "os"
  8. "strconv"
  9. "golang-fave/assets"
  10. "golang-fave/consts"
  11. "golang-fave/engine/builder"
  12. "golang-fave/engine/fetdata"
  13. "golang-fave/engine/wrapper"
  14. "golang-fave/utils"
  15. )
  16. func (this *Modules) RegisterModule_Index() *Module {
  17. return this.newModule(MInfo{
  18. WantDB: true,
  19. Mount: "index",
  20. Name: "Pages",
  21. Order: 0,
  22. Icon: assets.SysSvgIconPage,
  23. Sub: &[]MISub{
  24. {Mount: "default", Name: "List of Pages", Show: true, Icon: assets.SysSvgIconList},
  25. {Mount: "add", Name: "Add New Page", Show: true, Icon: assets.SysSvgIconPlus},
  26. {Mount: "modify", Name: "Modify Page", Show: false},
  27. },
  28. }, func(wrap *wrapper.Wrapper) {
  29. // Front-end
  30. row := &utils.MySql_page{}
  31. err := wrap.DB.QueryRow(`
  32. SELECT
  33. id,
  34. user,
  35. name,
  36. alias,
  37. content,
  38. meta_title,
  39. meta_keywords,
  40. meta_description,
  41. UNIX_TIMESTAMP(datetime) as datetime,
  42. active
  43. FROM
  44. pages
  45. WHERE
  46. active = 1 and
  47. alias = ?
  48. LIMIT 1;`,
  49. wrap.R.URL.Path,
  50. ).Scan(
  51. &row.A_id,
  52. &row.A_user,
  53. &row.A_name,
  54. &row.A_alias,
  55. &row.A_content,
  56. &row.A_meta_title,
  57. &row.A_meta_keywords,
  58. &row.A_meta_description,
  59. &row.A_datetime,
  60. &row.A_active,
  61. )
  62. if err != nil && err != sql.ErrNoRows {
  63. // Error 500
  64. utils.SystemErrorPageEngine(wrap.W, err)
  65. return
  66. } else if err == sql.ErrNoRows {
  67. // Error 404
  68. utils.SystemErrorPage404(wrap.W)
  69. return
  70. }
  71. // Replace title with page name
  72. if row.A_meta_title == "" {
  73. row.A_meta_title = row.A_name
  74. }
  75. // Which template
  76. tmpl_name := "index"
  77. if wrap.R.URL.Path != "/" {
  78. tmpl_name = "page"
  79. }
  80. // Render template
  81. tmpl_data := fetdata.New(wrap, row)
  82. wrap.RenderFrontEnd(tmpl_name, tmpl_data)
  83. }, func(wrap *wrapper.Wrapper) (string, string, string) {
  84. content := ""
  85. sidebar := ""
  86. if wrap.CurrSubModule == "" || wrap.CurrSubModule == "default" {
  87. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  88. {Name: "List of Pages"},
  89. })
  90. content += builder.DataTable(wrap, "pages", "id", "DESC", &[]builder.DataTableRow{
  91. {
  92. DBField: "id",
  93. },
  94. {
  95. DBField: "name",
  96. NameInTable: "Page / Alias",
  97. CallBack: func(values *[]string) string {
  98. name := `<a href="/cp/` + wrap.CurrModule + `/modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + `</a>`
  99. alias := html.EscapeString((*values)[2])
  100. return `<div>` + name + `</div><div><small>` + alias + `</small></div>`
  101. },
  102. },
  103. {
  104. DBField: "alias",
  105. },
  106. {
  107. DBField: "datetime",
  108. DBExp: "UNIX_TIMESTAMP(`datetime`)",
  109. NameInTable: "Date / Time",
  110. CallBack: func(values *[]string) string {
  111. t := int64(utils.StrToInt((*values)[3]))
  112. return `<div>` + utils.UnixTimestampToFormat(t, "02.01.2006") + `</div>` +
  113. `<div><small>` + utils.UnixTimestampToFormat(t, "15:04:05") + `</small></div>`
  114. },
  115. },
  116. {
  117. DBField: "active",
  118. NameInTable: "Active",
  119. CallBack: func(values *[]string) string {
  120. return builder.CheckBox(utils.StrToInt((*values)[4]))
  121. },
  122. },
  123. }, func(values *[]string) string {
  124. return builder.DataTableAction(&[]builder.DataTableActionRow{
  125. {
  126. Icon: assets.SysSvgIconView,
  127. Href: (*values)[2],
  128. Hint: "View",
  129. Target: "_blank",
  130. },
  131. {
  132. Icon: assets.SysSvgIconEdit,
  133. Href: "/cp/" + wrap.CurrModule + "/modify/" + (*values)[0] + "/",
  134. Hint: "Edit",
  135. },
  136. {
  137. Icon: assets.SysSvgIconRemove,
  138. Href: "javascript:fave.ActionDataTableDelete(this,'index-delete','" +
  139. (*values)[0] + "','Are you sure want to delete page?');",
  140. Hint: "Delete",
  141. },
  142. })
  143. }, "/cp/"+wrap.CurrModule+"/")
  144. } else if wrap.CurrSubModule == "add" || wrap.CurrSubModule == "modify" {
  145. if wrap.CurrSubModule == "add" {
  146. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  147. {Name: "Add New Page"},
  148. })
  149. } else {
  150. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  151. {Name: "Modify Page"},
  152. })
  153. }
  154. data := utils.MySql_page{
  155. A_id: 0,
  156. A_user: 0,
  157. A_name: "",
  158. A_alias: "",
  159. A_content: "",
  160. A_meta_title: "",
  161. A_meta_keywords: "",
  162. A_meta_description: "",
  163. A_datetime: 0,
  164. A_active: 0,
  165. }
  166. if wrap.CurrSubModule == "modify" {
  167. if len(wrap.UrlArgs) != 3 {
  168. return "", "", ""
  169. }
  170. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  171. return "", "", ""
  172. }
  173. err := wrap.DB.QueryRow(`
  174. SELECT
  175. id,
  176. user,
  177. name,
  178. alias,
  179. content,
  180. meta_title,
  181. meta_keywords,
  182. meta_description,
  183. active
  184. FROM
  185. pages
  186. WHERE
  187. id = ?
  188. LIMIT 1;`,
  189. utils.StrToInt(wrap.UrlArgs[2]),
  190. ).Scan(
  191. &data.A_id,
  192. &data.A_user,
  193. &data.A_name,
  194. &data.A_alias,
  195. &data.A_content,
  196. &data.A_meta_title,
  197. &data.A_meta_keywords,
  198. &data.A_meta_description,
  199. &data.A_active,
  200. )
  201. if err != nil {
  202. return "", "", ""
  203. }
  204. }
  205. content += builder.DataForm(wrap, []builder.DataFormField{
  206. {
  207. Kind: builder.DFKHidden,
  208. Name: "action",
  209. Value: "index-modify",
  210. },
  211. {
  212. Kind: builder.DFKHidden,
  213. Name: "id",
  214. Value: utils.IntToStr(data.A_id),
  215. },
  216. {
  217. Kind: builder.DFKText,
  218. Caption: "Page Name",
  219. Name: "name",
  220. Value: data.A_name,
  221. },
  222. {
  223. Kind: builder.DFKText,
  224. Caption: "Page Alias",
  225. Name: "alias",
  226. Value: data.A_alias,
  227. Hint: "Example: /about-us/ or /about-us.html or /about/team.html",
  228. },
  229. {
  230. Kind: builder.DFKTextArea,
  231. Caption: "Page Content",
  232. Name: "content",
  233. Value: data.A_content,
  234. },
  235. {
  236. Kind: builder.DFKText,
  237. Caption: "Meta Title",
  238. Name: "meta_title",
  239. Value: data.A_meta_title,
  240. },
  241. {
  242. Kind: builder.DFKText,
  243. Caption: "Meta Keywords",
  244. Name: "meta_keywords",
  245. Value: data.A_meta_keywords,
  246. },
  247. {
  248. Kind: builder.DFKTextArea,
  249. Caption: "Meta Description",
  250. Name: "meta_description",
  251. Value: data.A_meta_description,
  252. },
  253. {
  254. Kind: builder.DFKCheckBox,
  255. Caption: "Active",
  256. Name: "active",
  257. Value: utils.IntToStr(data.A_active),
  258. },
  259. {
  260. Kind: builder.DFKMessage,
  261. },
  262. {
  263. Kind: builder.DFKSubmit,
  264. Value: "Add",
  265. Target: "add-edit-button",
  266. },
  267. })
  268. if wrap.CurrSubModule == "add" {
  269. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  270. } else {
  271. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  272. }
  273. }
  274. return this.getSidebarModules(wrap), content, sidebar
  275. })
  276. }
  277. func (this *Modules) RegisterAction_IndexModify() *Action {
  278. return this.newAction(AInfo{
  279. WantDB: true,
  280. Mount: "index-modify",
  281. WantAdmin: true,
  282. }, func(wrap *wrapper.Wrapper) {
  283. pf_id := wrap.R.FormValue("id")
  284. pf_name := wrap.R.FormValue("name")
  285. pf_alias := wrap.R.FormValue("alias")
  286. pf_content := wrap.R.FormValue("content")
  287. pf_meta_title := wrap.R.FormValue("meta_title")
  288. pf_meta_keywords := wrap.R.FormValue("meta_keywords")
  289. pf_meta_description := wrap.R.FormValue("meta_description")
  290. pf_active := wrap.R.FormValue("active")
  291. if pf_active == "" {
  292. pf_active = "0"
  293. }
  294. if !utils.IsNumeric(pf_id) {
  295. wrap.MsgError(`Inner system error`)
  296. return
  297. }
  298. if pf_name == "" {
  299. wrap.MsgError(`Please specify page name`)
  300. return
  301. }
  302. if pf_alias == "" {
  303. pf_alias = utils.GenerateAlias(pf_name)
  304. }
  305. if !utils.IsValidAlias(pf_alias) {
  306. wrap.MsgError(`Please specify correct page alias`)
  307. return
  308. }
  309. if pf_id == "0" {
  310. // Add new page
  311. _, err := wrap.DB.Query(
  312. `INSERT INTO pages SET
  313. user = ?,
  314. name = ?,
  315. alias = ?,
  316. content = ?,
  317. meta_title = ?,
  318. meta_keywords = ?,
  319. meta_description = ?,
  320. datetime = ?,
  321. active = ?
  322. ;`,
  323. wrap.User.A_id,
  324. pf_name,
  325. pf_alias,
  326. pf_content,
  327. pf_meta_title,
  328. pf_meta_keywords,
  329. pf_meta_description,
  330. utils.UnixTimestampToMySqlDateTime(utils.GetCurrentUnixTimestamp()),
  331. pf_active,
  332. )
  333. if err != nil {
  334. wrap.MsgError(err.Error())
  335. return
  336. }
  337. wrap.Write(`window.location='/cp/';`)
  338. } else {
  339. // Update page
  340. _, err := wrap.DB.Query(
  341. `UPDATE pages SET
  342. name = ?,
  343. alias = ?,
  344. content = ?,
  345. meta_title = ?,
  346. meta_keywords = ?,
  347. meta_description = ?,
  348. active = ?
  349. WHERE
  350. id = ?
  351. ;`,
  352. pf_name,
  353. pf_alias,
  354. pf_content,
  355. pf_meta_title,
  356. pf_meta_keywords,
  357. pf_meta_description,
  358. pf_active,
  359. utils.StrToInt(pf_id),
  360. )
  361. if err != nil {
  362. wrap.MsgError(err.Error())
  363. return
  364. }
  365. wrap.Write(`window.location='/cp/index/modify/` + pf_id + `/';`)
  366. }
  367. })
  368. }
  369. func (this *Modules) RegisterAction_IndexDelete() *Action {
  370. return this.newAction(AInfo{
  371. WantDB: true,
  372. Mount: "index-delete",
  373. WantAdmin: true,
  374. }, func(wrap *wrapper.Wrapper) {
  375. pf_id := wrap.R.FormValue("id")
  376. if !utils.IsNumeric(pf_id) {
  377. wrap.MsgError(`Inner system error`)
  378. return
  379. }
  380. // Delete page
  381. _, err := wrap.DB.Query(
  382. `DELETE FROM pages WHERE id = ?;`,
  383. utils.StrToInt(pf_id),
  384. )
  385. if err != nil {
  386. wrap.MsgError(err.Error())
  387. return
  388. }
  389. // Reload current page
  390. wrap.Write(`window.location.reload(false);`)
  391. })
  392. }
  393. func (this *Modules) RegisterAction_IndexMysqlSetup() *Action {
  394. return this.newAction(AInfo{
  395. WantDB: false,
  396. Mount: "index-mysql-setup",
  397. }, func(wrap *wrapper.Wrapper) {
  398. pf_host := wrap.R.FormValue("host")
  399. pf_port := wrap.R.FormValue("port")
  400. pf_name := wrap.R.FormValue("name")
  401. pf_user := wrap.R.FormValue("user")
  402. pf_password := wrap.R.FormValue("password")
  403. if pf_host == "" {
  404. wrap.MsgError(`Please specify host for MySQL connection`)
  405. return
  406. }
  407. if pf_port == "" {
  408. wrap.MsgError(`Please specify host port for MySQL connection`)
  409. return
  410. }
  411. if _, err := strconv.Atoi(pf_port); err != nil {
  412. wrap.MsgError(`MySQL host port must be integer number`)
  413. return
  414. }
  415. if pf_name == "" {
  416. wrap.MsgError(`Please specify MySQL database name`)
  417. return
  418. }
  419. if pf_user == "" {
  420. wrap.MsgError(`Please specify MySQL user`)
  421. return
  422. }
  423. // Try connect to mysql
  424. db, err := sql.Open("mysql", pf_user+":"+pf_password+"@tcp("+pf_host+":"+pf_port+")/"+pf_name)
  425. if err != nil {
  426. wrap.MsgError(err.Error())
  427. return
  428. }
  429. defer db.Close()
  430. err = db.Ping()
  431. if err != nil {
  432. wrap.MsgError(err.Error())
  433. return
  434. }
  435. // Try to install all tables
  436. _, err = db.Query(fmt.Sprintf(
  437. `CREATE TABLE %s.users (
  438. id int(11) NOT NULL AUTO_INCREMENT COMMENT 'AI',
  439. first_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'User first name',
  440. last_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'User last name',
  441. email VARCHAR(64) NOT NULL COMMENT 'User email',
  442. password VARCHAR(32) NOT NULL COMMENT 'User password (MD5)',
  443. admin int(1) NOT NULL COMMENT 'Is admin user or not',
  444. active int(1) NOT NULL COMMENT 'Is active user or not',
  445. PRIMARY KEY (id)
  446. ) ENGINE = InnoDB;`,
  447. pf_name))
  448. if err != nil {
  449. wrap.MsgError(err.Error())
  450. return
  451. }
  452. _, err = db.Query(fmt.Sprintf(
  453. `CREATE TABLE %s.pages (
  454. id int(11) NOT NULL AUTO_INCREMENT COMMENT 'AI',
  455. user int(11) NOT NULL COMMENT 'User id',
  456. name varchar(255) NOT NULL COMMENT 'Page name',
  457. alias varchar(255) NOT NULL COMMENT 'Page url part',
  458. content text NOT NULL COMMENT 'Page content',
  459. meta_title varchar(255) NOT NULL DEFAULT '' COMMENT 'Page meta title',
  460. meta_keywords varchar(255) NOT NULL DEFAULT '' COMMENT 'Page meta keywords',
  461. meta_description varchar(510) NOT NULL DEFAULT '' COMMENT 'Page meta description',
  462. datetime datetime NOT NULL COMMENT 'Creation date/time',
  463. active int(1) NOT NULL COMMENT 'Is active page or not',
  464. PRIMARY KEY (id)
  465. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`,
  466. pf_name))
  467. if err != nil {
  468. wrap.MsgError(err.Error())
  469. return
  470. }
  471. _, err = db.Query(fmt.Sprintf(
  472. `ALTER TABLE %s.pages ADD UNIQUE KEY alias (alias);`,
  473. pf_name))
  474. if err != nil {
  475. wrap.MsgError(err.Error())
  476. return
  477. }
  478. // Save mysql config file
  479. err = utils.MySqlConfigWrite(wrap.DConfig+string(os.PathSeparator)+"mysql.json", pf_host, pf_port, pf_name, pf_user, pf_password)
  480. if err != nil {
  481. wrap.MsgError(err.Error())
  482. return
  483. }
  484. // Reload current page
  485. wrap.Write(`window.location.reload(false);`)
  486. })
  487. }
  488. func (this *Modules) RegisterAction_IndexFirstUser() *Action {
  489. return this.newAction(AInfo{
  490. WantDB: true,
  491. Mount: "index-first-user",
  492. }, func(wrap *wrapper.Wrapper) {
  493. pf_first_name := wrap.R.FormValue("first_name")
  494. pf_last_name := wrap.R.FormValue("last_name")
  495. pf_email := wrap.R.FormValue("email")
  496. pf_password := wrap.R.FormValue("password")
  497. if pf_email == "" {
  498. wrap.MsgError(`Please specify user email`)
  499. return
  500. }
  501. if !utils.IsValidEmail(pf_email) {
  502. wrap.MsgError(`Please specify correct user email`)
  503. return
  504. }
  505. if pf_password == "" {
  506. wrap.MsgError(`Please specify user password`)
  507. return
  508. }
  509. _, err := wrap.DB.Query(
  510. `INSERT INTO users SET
  511. first_name = ?,
  512. last_name = ?,
  513. email = ?,
  514. password = MD5(?),
  515. admin = 1,
  516. active = 1
  517. ;`,
  518. pf_first_name,
  519. pf_last_name,
  520. pf_email,
  521. pf_password,
  522. )
  523. if err != nil {
  524. wrap.MsgError(err.Error())
  525. return
  526. }
  527. // Add home page
  528. _, err = wrap.DB.Query(
  529. `INSERT INTO pages SET
  530. user = ?,
  531. name = ?,
  532. alias = ?,
  533. content = ?,
  534. datetime = ?,
  535. active = ?
  536. ;`,
  537. 1,
  538. "Home",
  539. "/",
  540. "Hello World from Fave CMS!",
  541. utils.GetCurrentUnixTimestamp(),
  542. 1,
  543. )
  544. if err != nil {
  545. wrap.MsgError(err.Error())
  546. return
  547. }
  548. // Reload current page
  549. wrap.Write(`window.location.reload(false);`)
  550. })
  551. }
  552. func (this *Modules) RegisterAction_IndexUserSignIn() *Action {
  553. return this.newAction(AInfo{
  554. WantDB: true,
  555. Mount: "index-user-sign-in",
  556. }, func(wrap *wrapper.Wrapper) {
  557. pf_email := wrap.R.FormValue("email")
  558. pf_password := wrap.R.FormValue("password")
  559. if pf_email == "" {
  560. wrap.MsgError(`Please specify user email`)
  561. return
  562. }
  563. if !utils.IsValidEmail(pf_email) {
  564. wrap.MsgError(`Please specify correct user email`)
  565. return
  566. }
  567. if pf_password == "" {
  568. wrap.MsgError(`Please specify user password`)
  569. return
  570. }
  571. if wrap.S.GetInt("UserId", 0) > 0 {
  572. wrap.MsgError(`You already logined`)
  573. return
  574. }
  575. var user_id int
  576. err := wrap.DB.QueryRow(
  577. `SELECT
  578. id
  579. FROM
  580. users
  581. WHERE
  582. email = ? and
  583. password = MD5(?) and
  584. admin = 1 and
  585. active = 1
  586. LIMIT 1;`,
  587. pf_email,
  588. pf_password,
  589. ).Scan(
  590. &user_id,
  591. )
  592. if err != nil && err != sql.ErrNoRows {
  593. wrap.MsgError(err.Error())
  594. return
  595. }
  596. if err == sql.ErrNoRows {
  597. wrap.MsgError(`Incorrect email or password`)
  598. return
  599. }
  600. // Save to current session
  601. wrap.S.SetInt("UserId", user_id)
  602. // Reload current page
  603. wrap.Write(`window.location.reload(false);`)
  604. })
  605. }
  606. func (this *Modules) RegisterAction_IndexUserLogout() *Action {
  607. return this.newAction(AInfo{
  608. WantDB: true,
  609. Mount: "index-user-logout",
  610. WantUser: true,
  611. }, func(wrap *wrapper.Wrapper) {
  612. // Reset session var
  613. wrap.S.SetInt("UserId", 0)
  614. // Reload current page
  615. wrap.Write(`window.location.reload(false);`)
  616. })
  617. }
  618. func (this *Modules) RegisterAction_IndexUserUpdateProfile() *Action {
  619. return this.newAction(AInfo{
  620. WantDB: true,
  621. Mount: "index-user-update-profile",
  622. WantUser: true,
  623. }, func(wrap *wrapper.Wrapper) {
  624. pf_first_name := wrap.R.FormValue("first_name")
  625. pf_last_name := wrap.R.FormValue("last_name")
  626. pf_email := wrap.R.FormValue("email")
  627. pf_password := wrap.R.FormValue("password")
  628. if pf_email == "" {
  629. wrap.MsgError(`Please specify user email`)
  630. return
  631. }
  632. if !utils.IsValidEmail(pf_email) {
  633. wrap.MsgError(`Please specify correct user email`)
  634. return
  635. }
  636. if pf_password != "" {
  637. // Update with password if set
  638. _, err := wrap.DB.Query(
  639. `UPDATE users SET
  640. first_name = ?,
  641. last_name = ?,
  642. email = ?,
  643. password = MD5(?)
  644. WHERE
  645. id = ?
  646. ;`,
  647. pf_first_name,
  648. pf_last_name,
  649. pf_email,
  650. pf_password,
  651. wrap.User.A_id,
  652. )
  653. if err != nil {
  654. wrap.MsgError(err.Error())
  655. return
  656. }
  657. } else {
  658. // Update without password if not set
  659. _, err := wrap.DB.Query(
  660. `UPDATE users SET
  661. first_name = ?,
  662. last_name = ?,
  663. email = ?
  664. WHERE
  665. id = ?
  666. ;`,
  667. pf_first_name,
  668. pf_last_name,
  669. pf_email,
  670. wrap.User.A_id,
  671. )
  672. if err != nil {
  673. wrap.MsgError(err.Error())
  674. return
  675. }
  676. }
  677. // Reload current page
  678. wrap.Write(`window.location.reload(false);`)
  679. })
  680. }