module_index.go 15 KB

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