module_index.go 14 KB

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