module_index.go 14 KB

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