module_index.go 17 KB

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