module_index.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. package modules
  2. import (
  3. "html"
  4. "io/ioutil"
  5. "net/http"
  6. "strings"
  7. "golang-fave/engine/assets"
  8. "golang-fave/engine/builder"
  9. "golang-fave/engine/consts"
  10. "golang-fave/engine/fetdata"
  11. "golang-fave/engine/utils"
  12. "golang-fave/engine/wrapper"
  13. )
  14. func (this *Modules) index_TemplateNameToValue(filename string) string {
  15. if i := strings.LastIndex(filename, "."); i > -1 {
  16. return filename[:i]
  17. }
  18. return filename
  19. }
  20. func (this *Modules) index_GetTemplateSelectOptions(wrap *wrapper.Wrapper, template string) string {
  21. result := ``
  22. // index.html
  23. result += `<option title="index.html" value="index"`
  24. if template == "index" {
  25. result += ` selected`
  26. }
  27. result += `>index.html</option>`
  28. // page.html
  29. result += `<option title="page.html" value="page"`
  30. if template == "" || template == "page" {
  31. result += ` selected`
  32. }
  33. result += `>page.html</option>`
  34. // User templates
  35. if files, err := ioutil.ReadDir(wrap.DTemplate); err == nil {
  36. for _, file := range files {
  37. if len(file.Name()) > 0 && file.Name()[0] == '.' {
  38. continue
  39. }
  40. if len(file.Name()) > 0 && strings.ToLower(file.Name()) == "robots.txt" {
  41. continue
  42. }
  43. if !wrap.IsSystemMountedTemplateFile(file.Name()) {
  44. value := this.index_TemplateNameToValue(file.Name())
  45. result += `<option title="` + file.Name() + `" value="` + value + `"`
  46. if template == value {
  47. result += ` selected`
  48. }
  49. result += `>` + file.Name() + `</option>`
  50. }
  51. }
  52. }
  53. return result
  54. }
  55. func (this *Modules) RegisterModule_Index() *Module {
  56. return this.newModule(MInfo{
  57. Mount: "index",
  58. Name: "Pages",
  59. Order: 0,
  60. Icon: assets.SysSvgIconPage,
  61. Sub: &[]MISub{
  62. {Mount: "default", Name: "List of pages", Show: true, Icon: assets.SysSvgIconList},
  63. {Mount: "add", Name: "Add new page", Show: true, Icon: assets.SysSvgIconPlus},
  64. {Mount: "modify", Name: "Modify page", Show: false},
  65. },
  66. }, func(wrap *wrapper.Wrapper) {
  67. // Front-end
  68. row := &utils.MySql_page{}
  69. rou := &utils.MySql_user{}
  70. err := wrap.DB.QueryRow(
  71. wrap.R.Context(),
  72. `SELECT
  73. fave_pages.id,
  74. fave_pages.user,
  75. fave_pages.template,
  76. fave_pages.name,
  77. fave_pages.alias,
  78. fave_pages.content,
  79. fave_pages.meta_title,
  80. fave_pages.meta_keywords,
  81. fave_pages.meta_description,
  82. UNIX_TIMESTAMP(fave_pages.datetime) as datetime,
  83. fave_pages.active,
  84. fave_users.id,
  85. fave_users.first_name,
  86. fave_users.last_name,
  87. fave_users.email,
  88. fave_users.admin,
  89. fave_users.active
  90. FROM
  91. fave_pages
  92. LEFT JOIN fave_users ON fave_users.id = fave_pages.user
  93. WHERE
  94. fave_pages.active = 1 and
  95. fave_pages.alias = ?
  96. LIMIT 1;`,
  97. wrap.R.URL.Path,
  98. ).Scan(
  99. &row.A_id,
  100. &row.A_user,
  101. &row.A_template,
  102. &row.A_name,
  103. &row.A_alias,
  104. &row.A_content,
  105. &row.A_meta_title,
  106. &row.A_meta_keywords,
  107. &row.A_meta_description,
  108. &row.A_datetime,
  109. &row.A_active,
  110. &rou.A_id,
  111. &rou.A_first_name,
  112. &rou.A_last_name,
  113. &rou.A_email,
  114. &rou.A_admin,
  115. &rou.A_active,
  116. )
  117. if err != nil && err != wrapper.ErrNoRows {
  118. // System error 500
  119. wrap.LogCpError(&err)
  120. utils.SystemErrorPageEngine(wrap.W, err)
  121. return
  122. } else if err == wrapper.ErrNoRows {
  123. // User error 404 page
  124. wrap.RenderFrontEnd("404", fetdata.New(wrap, true, nil, nil), http.StatusNotFound)
  125. return
  126. }
  127. // Render template
  128. wrap.RenderFrontEnd(row.A_template, fetdata.New(wrap, false, row, rou), http.StatusOK)
  129. }, func(wrap *wrapper.Wrapper) (string, string, string) {
  130. content := ""
  131. sidebar := ""
  132. if wrap.CurrSubModule == "" || wrap.CurrSubModule == "default" {
  133. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  134. {Name: "List of pages"},
  135. })
  136. content += builder.DataTable(
  137. wrap,
  138. "fave_pages",
  139. "id",
  140. "DESC",
  141. &[]builder.DataTableRow{
  142. {
  143. DBField: "id",
  144. },
  145. {
  146. DBField: "template",
  147. },
  148. {
  149. DBField: "name",
  150. NameInTable: "Page / URL",
  151. CallBack: func(values *[]string) string {
  152. name := `<a href="/cp/` + wrap.CurrModule + `/modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[2]) + `</a>`
  153. alias := html.EscapeString((*values)[3])
  154. template := html.EscapeString((*values)[1]) + ".html"
  155. return `<div>` + name + `</div><div class="template"><small>` + template + `</small></div><div><small>` + alias + `</small></div>`
  156. },
  157. },
  158. {
  159. DBField: "alias",
  160. },
  161. {
  162. DBField: "datetime",
  163. DBExp: "UNIX_TIMESTAMP(`datetime`)",
  164. NameInTable: "Date / Time",
  165. Classes: "d-none d-md-table-cell",
  166. CallBack: func(values *[]string) string {
  167. t := int64(utils.StrToInt((*values)[4]))
  168. return `<div>` + utils.UnixTimestampToFormat(t, "02.01.2006") + `</div>` +
  169. `<div><small>` + utils.UnixTimestampToFormat(t, "15:04:05") + `</small></div>`
  170. },
  171. },
  172. {
  173. DBField: "active",
  174. NameInTable: "Active",
  175. Classes: "d-none d-sm-table-cell",
  176. CallBack: func(values *[]string) string {
  177. return builder.CheckBox(utils.StrToInt((*values)[5]))
  178. },
  179. },
  180. },
  181. func(values *[]string) string {
  182. return builder.DataTableAction(&[]builder.DataTableActionRow{
  183. {
  184. Icon: assets.SysSvgIconView,
  185. Href: (*values)[3],
  186. Hint: "View",
  187. Target: "_blank",
  188. },
  189. {
  190. Icon: assets.SysSvgIconEdit,
  191. Href: "/cp/" + wrap.CurrModule + "/modify/" + (*values)[0] + "/",
  192. Hint: "Edit",
  193. },
  194. {
  195. Icon: assets.SysSvgIconRemove,
  196. Href: "javascript:fave.ActionDataTableDelete(this,'index-delete','" +
  197. (*values)[0] + "','Are you sure want to delete page?');",
  198. Hint: "Delete",
  199. Classes: "delete",
  200. },
  201. })
  202. },
  203. "/cp/"+wrap.CurrModule+"/",
  204. nil,
  205. nil,
  206. true,
  207. )
  208. } else if wrap.CurrSubModule == "add" || wrap.CurrSubModule == "modify" {
  209. if wrap.CurrSubModule == "add" {
  210. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  211. {Name: "Add new page"},
  212. })
  213. } else {
  214. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  215. {Name: "Modify page"},
  216. })
  217. }
  218. data := utils.MySql_page{
  219. A_id: 0,
  220. A_user: 0,
  221. A_template: "",
  222. A_name: "",
  223. A_alias: "",
  224. A_content: "",
  225. A_meta_title: "",
  226. A_meta_keywords: "",
  227. A_meta_description: "",
  228. A_datetime: 0,
  229. A_active: 0,
  230. }
  231. if wrap.CurrSubModule == "modify" {
  232. if len(wrap.UrlArgs) != 3 {
  233. return "", "", ""
  234. }
  235. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  236. return "", "", ""
  237. }
  238. err := wrap.DB.QueryRow(
  239. wrap.R.Context(),
  240. `SELECT
  241. id,
  242. user,
  243. template,
  244. name,
  245. alias,
  246. content,
  247. meta_title,
  248. meta_keywords,
  249. meta_description,
  250. active
  251. FROM
  252. fave_pages
  253. WHERE
  254. id = ?
  255. LIMIT 1;`,
  256. utils.StrToInt(wrap.UrlArgs[2]),
  257. ).Scan(
  258. &data.A_id,
  259. &data.A_user,
  260. &data.A_template,
  261. &data.A_name,
  262. &data.A_alias,
  263. &data.A_content,
  264. &data.A_meta_title,
  265. &data.A_meta_keywords,
  266. &data.A_meta_description,
  267. &data.A_active,
  268. )
  269. if *wrap.LogCpError(&err) != nil {
  270. return "", "", ""
  271. }
  272. }
  273. btn_caption := "Add"
  274. if wrap.CurrSubModule == "modify" {
  275. btn_caption = "Save"
  276. }
  277. content += builder.DataForm(wrap, []builder.DataFormField{
  278. {
  279. Kind: builder.DFKHidden,
  280. Name: "action",
  281. Value: "index-modify",
  282. },
  283. {
  284. Kind: builder.DFKHidden,
  285. Name: "id",
  286. Value: utils.IntToStr(data.A_id),
  287. },
  288. {
  289. Kind: builder.DFKText,
  290. Caption: "Page name",
  291. Name: "name",
  292. Value: data.A_name,
  293. Required: true,
  294. Min: "1",
  295. Max: "255",
  296. },
  297. {
  298. Kind: builder.DFKText,
  299. Caption: "Page alias",
  300. Name: "alias",
  301. Value: data.A_alias,
  302. Hint: "Example: /about-us/ or /about-us.html",
  303. Max: "255",
  304. },
  305. {
  306. Kind: builder.DFKText,
  307. Caption: "Page template",
  308. Name: "template",
  309. Value: "0",
  310. CallBack: func(field *builder.DataFormField) string {
  311. return `<div class="form-group n2">` +
  312. `<div class="row">` +
  313. `<div class="col-md-3">` +
  314. `<label for="lbl_template">Page template</label>` +
  315. `</div>` +
  316. `<div class="col-md-9">` +
  317. `<div>` +
  318. `<select class="selectpicker form-control" id="lbl_template" name="template" data-live-search="true">` +
  319. this.index_GetTemplateSelectOptions(wrap, data.A_template) +
  320. `</select>` +
  321. `</div>` +
  322. `</div>` +
  323. `</div>` +
  324. `</div>`
  325. },
  326. },
  327. {
  328. Kind: builder.DFKTextArea,
  329. Caption: "Page content",
  330. Name: "content",
  331. Value: data.A_content,
  332. Classes: "wysiwyg",
  333. },
  334. {
  335. Kind: builder.DFKText,
  336. Caption: "Meta title",
  337. Name: "meta_title",
  338. Value: data.A_meta_title,
  339. Max: "255",
  340. },
  341. {
  342. Kind: builder.DFKText,
  343. Caption: "Meta keywords",
  344. Name: "meta_keywords",
  345. Value: data.A_meta_keywords,
  346. Max: "255",
  347. },
  348. {
  349. Kind: builder.DFKTextArea,
  350. Caption: "Meta description",
  351. Name: "meta_description",
  352. Value: data.A_meta_description,
  353. Max: "510",
  354. },
  355. {
  356. Kind: builder.DFKCheckBox,
  357. Caption: "Active",
  358. Name: "active",
  359. Value: utils.IntToStr(data.A_active),
  360. },
  361. {
  362. Kind: builder.DFKSubmit,
  363. Value: btn_caption,
  364. Target: "add-edit-button",
  365. },
  366. })
  367. if wrap.CurrSubModule == "add" {
  368. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  369. } else {
  370. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  371. }
  372. }
  373. return this.getSidebarModules(wrap), content, sidebar
  374. })
  375. }