module_index.go 15 KB

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