module_index.go 15 KB

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