module_index.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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. wrap.Write(`alert('Delete (` + pf_id + `)!');`)
  318. })
  319. }
  320. func (this *Modules) RegisterAction_IndexMysqlSetup() *Action {
  321. return this.newAction(AInfo{
  322. WantDB: false,
  323. Mount: "index-mysql-setup",
  324. }, func(wrap *wrapper.Wrapper) {
  325. pf_host := wrap.R.FormValue("host")
  326. pf_port := wrap.R.FormValue("port")
  327. pf_name := wrap.R.FormValue("name")
  328. pf_user := wrap.R.FormValue("user")
  329. pf_password := wrap.R.FormValue("password")
  330. if pf_host == "" {
  331. wrap.MsgError(`Please specify host for MySQL connection`)
  332. return
  333. }
  334. if pf_port == "" {
  335. wrap.MsgError(`Please specify host port for MySQL connection`)
  336. return
  337. }
  338. if _, err := strconv.Atoi(pf_port); err != nil {
  339. wrap.MsgError(`MySQL host port must be integer number`)
  340. return
  341. }
  342. if pf_name == "" {
  343. wrap.MsgError(`Please specify MySQL database name`)
  344. return
  345. }
  346. if pf_user == "" {
  347. wrap.MsgError(`Please specify MySQL user`)
  348. return
  349. }
  350. // Try connect to mysql
  351. db, err := sql.Open("mysql", pf_user+":"+pf_password+"@tcp("+pf_host+":"+pf_port+")/"+pf_name)
  352. if err != nil {
  353. wrap.MsgError(err.Error())
  354. return
  355. }
  356. defer db.Close()
  357. err = db.Ping()
  358. if err != nil {
  359. wrap.MsgError(err.Error())
  360. return
  361. }
  362. // Try to install all tables
  363. _, err = db.Query(fmt.Sprintf(
  364. `CREATE TABLE %s.users (
  365. id int(11) NOT NULL AUTO_INCREMENT COMMENT 'AI',
  366. first_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'User first name',
  367. last_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'User last name',
  368. email VARCHAR(64) NOT NULL COMMENT 'User email',
  369. password VARCHAR(32) NOT NULL COMMENT 'User password (MD5)',
  370. admin int(1) NOT NULL COMMENT 'Is admin user or not',
  371. active int(1) NOT NULL COMMENT 'Is active user or not',
  372. PRIMARY KEY (id)
  373. ) ENGINE = InnoDB;`,
  374. pf_name))
  375. if err != nil {
  376. wrap.MsgError(err.Error())
  377. return
  378. }
  379. _, err = db.Query(fmt.Sprintf(
  380. `CREATE TABLE %s.pages (
  381. id int(11) NOT NULL AUTO_INCREMENT COMMENT 'AI',
  382. user int(11) NOT NULL COMMENT 'User id',
  383. name varchar(255) NOT NULL COMMENT 'Page name',
  384. alias varchar(255) NOT NULL COMMENT 'Page url part',
  385. content text NOT NULL COMMENT 'Page content',
  386. meta_title varchar(255) NOT NULL DEFAULT '' COMMENT 'Page meta title',
  387. meta_keywords varchar(255) NOT NULL DEFAULT '' COMMENT 'Page meta keywords',
  388. meta_description varchar(510) NOT NULL DEFAULT '' COMMENT 'Page meta description',
  389. datetime datetime NOT NULL COMMENT 'Creation date/time',
  390. active int(1) NOT NULL COMMENT 'Is active page or not',
  391. PRIMARY KEY (id)
  392. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`,
  393. pf_name))
  394. if err != nil {
  395. wrap.MsgError(err.Error())
  396. return
  397. }
  398. _, err = db.Query(fmt.Sprintf(
  399. `ALTER TABLE %s.pages ADD UNIQUE KEY alias (alias);`,
  400. pf_name))
  401. if err != nil {
  402. wrap.MsgError(err.Error())
  403. return
  404. }
  405. // Save mysql config file
  406. err = utils.MySqlConfigWrite(wrap.DConfig+string(os.PathSeparator)+"mysql.json", pf_host, pf_port, pf_name, pf_user, pf_password)
  407. if err != nil {
  408. wrap.MsgError(err.Error())
  409. return
  410. }
  411. // Reload current page
  412. wrap.Write(`window.location.reload(false);`)
  413. })
  414. }
  415. func (this *Modules) RegisterAction_IndexFirstUser() *Action {
  416. return this.newAction(AInfo{
  417. WantDB: true,
  418. Mount: "index-first-user",
  419. }, func(wrap *wrapper.Wrapper) {
  420. pf_first_name := wrap.R.FormValue("first_name")
  421. pf_last_name := wrap.R.FormValue("last_name")
  422. pf_email := wrap.R.FormValue("email")
  423. pf_password := wrap.R.FormValue("password")
  424. if pf_email == "" {
  425. wrap.MsgError(`Please specify user email`)
  426. return
  427. }
  428. if !utils.IsValidEmail(pf_email) {
  429. wrap.MsgError(`Please specify correct user email`)
  430. return
  431. }
  432. if pf_password == "" {
  433. wrap.MsgError(`Please specify user password`)
  434. return
  435. }
  436. _, err := wrap.DB.Query(
  437. `INSERT INTO users SET
  438. first_name = ?,
  439. last_name = ?,
  440. email = ?,
  441. password = MD5(?),
  442. admin = 1,
  443. active = 1
  444. ;`,
  445. pf_first_name,
  446. pf_last_name,
  447. pf_email,
  448. pf_password,
  449. )
  450. if err != nil {
  451. wrap.MsgError(err.Error())
  452. return
  453. }
  454. // Reload current page
  455. wrap.Write(`window.location.reload(false);`)
  456. })
  457. }
  458. func (this *Modules) RegisterAction_IndexUserSignIn() *Action {
  459. return this.newAction(AInfo{
  460. WantDB: true,
  461. Mount: "index-user-sign-in",
  462. }, func(wrap *wrapper.Wrapper) {
  463. pf_email := wrap.R.FormValue("email")
  464. pf_password := wrap.R.FormValue("password")
  465. if pf_email == "" {
  466. wrap.MsgError(`Please specify user email`)
  467. return
  468. }
  469. if !utils.IsValidEmail(pf_email) {
  470. wrap.MsgError(`Please specify correct user email`)
  471. return
  472. }
  473. if pf_password == "" {
  474. wrap.MsgError(`Please specify user password`)
  475. return
  476. }
  477. if wrap.S.GetInt("UserId", 0) > 0 {
  478. wrap.MsgError(`You already logined`)
  479. return
  480. }
  481. var user_id int
  482. err := wrap.DB.QueryRow(
  483. `SELECT
  484. id
  485. FROM
  486. users
  487. WHERE
  488. email = ? and
  489. password = MD5(?) and
  490. admin = 1 and
  491. active = 1
  492. LIMIT 1;`,
  493. pf_email,
  494. pf_password,
  495. ).Scan(
  496. &user_id,
  497. )
  498. if err != nil && err != sql.ErrNoRows {
  499. wrap.MsgError(err.Error())
  500. return
  501. }
  502. if err == sql.ErrNoRows {
  503. wrap.MsgError(`Incorrect email or password`)
  504. return
  505. }
  506. // Save to current session
  507. wrap.S.SetInt("UserId", user_id)
  508. // Reload current page
  509. wrap.Write(`window.location.reload(false);`)
  510. })
  511. }
  512. func (this *Modules) RegisterAction_IndexUserLogout() *Action {
  513. return this.newAction(AInfo{
  514. WantDB: true,
  515. Mount: "index-user-logout",
  516. WantUser: true,
  517. }, func(wrap *wrapper.Wrapper) {
  518. // Reset session var
  519. wrap.S.SetInt("UserId", 0)
  520. // Reload current page
  521. wrap.Write(`window.location.reload(false);`)
  522. })
  523. }
  524. func (this *Modules) RegisterAction_IndexUserUpdateProfile() *Action {
  525. return this.newAction(AInfo{
  526. WantDB: true,
  527. Mount: "index-user-update-profile",
  528. WantUser: true,
  529. }, func(wrap *wrapper.Wrapper) {
  530. pf_first_name := wrap.R.FormValue("first_name")
  531. pf_last_name := wrap.R.FormValue("last_name")
  532. pf_email := wrap.R.FormValue("email")
  533. pf_password := wrap.R.FormValue("password")
  534. if pf_email == "" {
  535. wrap.MsgError(`Please specify user email`)
  536. return
  537. }
  538. if !utils.IsValidEmail(pf_email) {
  539. wrap.MsgError(`Please specify correct user email`)
  540. return
  541. }
  542. if pf_password != "" {
  543. // Update with password if set
  544. _, err := wrap.DB.Query(
  545. `UPDATE users SET
  546. first_name = ?,
  547. last_name = ?,
  548. email = ?,
  549. password = MD5(?)
  550. WHERE
  551. id = ?
  552. ;`,
  553. pf_first_name,
  554. pf_last_name,
  555. pf_email,
  556. pf_password,
  557. wrap.User.A_id,
  558. )
  559. if err != nil {
  560. wrap.MsgError(err.Error())
  561. return
  562. }
  563. } else {
  564. // Update without password if not set
  565. _, err := wrap.DB.Query(
  566. `UPDATE users SET
  567. first_name = ?,
  568. last_name = ?,
  569. email = ?
  570. WHERE
  571. id = ?
  572. ;`,
  573. pf_first_name,
  574. pf_last_name,
  575. pf_email,
  576. wrap.User.A_id,
  577. )
  578. if err != nil {
  579. wrap.MsgError(err.Error())
  580. return
  581. }
  582. }
  583. // Reload current page
  584. wrap.Write(`window.location.reload(false);`)
  585. })
  586. }