module_index.go 14 KB

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