module_index.go 14 KB

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