package modules
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"html"
"strings"
"golang-fave/assets"
"golang-fave/consts"
"golang-fave/engine/builder"
"golang-fave/engine/wrapper"
"golang-fave/utils"
)
func (this *Modules) RegisterModule_Blog() *Module {
return this.newModule(MInfo{
WantDB: true,
Mount: "blog",
Name: "Blog",
Order: 1,
System: false,
Icon: assets.SysSvgIconList,
Sub: &[]MISub{
{Mount: "default", Name: "List of posts", Show: true, Icon: assets.SysSvgIconList},
{Mount: "add", Name: "Add new post", Show: true, Icon: assets.SysSvgIconPlus},
{Mount: "modify", Name: "Modify post", Show: false},
{Sep: true, Show: true},
{Mount: "categories", Name: "List of categories", Show: true, Icon: assets.SysSvgIconList},
{Mount: "categories-add", Name: "Add new category", Show: true, Icon: assets.SysSvgIconPlus},
{Mount: "categories-modify", Name: "Modify category", Show: false},
},
}, nil, func(wrap *wrapper.Wrapper) (string, string, string) {
content := ""
sidebar := ""
if wrap.CurrSubModule == "" || wrap.CurrSubModule == "default" {
content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
{Name: "List of posts"},
})
content += builder.DataTable(
wrap,
"blog_posts",
"id",
"DESC",
&[]builder.DataTableRow{
{
DBField: "id",
},
{
DBField: "name",
NameInTable: "Post / URL",
CallBack: func(values *[]string) string {
name := `` + html.EscapeString((*values)[1]) + ``
alias := html.EscapeString((*values)[2])
return `
` + name + `
/blog/` + alias + `/
`
},
},
{
DBField: "alias",
},
{
DBField: "datetime",
DBExp: "UNIX_TIMESTAMP(`datetime`)",
NameInTable: "Date / Time",
Classes: "d-none d-md-table-cell",
CallBack: func(values *[]string) string {
t := int64(utils.StrToInt((*values)[3]))
return `` + utils.UnixTimestampToFormat(t, "02.01.2006") + `
` +
`` + utils.UnixTimestampToFormat(t, "15:04:05") + `
`
},
},
{
DBField: "active",
NameInTable: "Active",
Classes: "d-none d-sm-table-cell",
CallBack: func(values *[]string) string {
return builder.CheckBox(utils.StrToInt((*values)[4]))
},
},
},
func(values *[]string) string {
return builder.DataTableAction(&[]builder.DataTableActionRow{
{
Icon: assets.SysSvgIconView,
Href: `/blog/` + (*values)[2] + `/`,
Hint: "View",
Target: "_blank",
},
{
Icon: assets.SysSvgIconEdit,
Href: "/cp/" + wrap.CurrModule + "/modify/" + (*values)[0] + "/",
Hint: "Edit",
},
{
Icon: assets.SysSvgIconRemove,
Href: "javascript:fave.ActionDataTableDelete(this,'blog-delete','" +
(*values)[0] + "','Are you sure want to delete post?');",
Hint: "Delete",
Classes: "delete",
},
})
},
"/cp/"+wrap.CurrModule+"/",
nil,
nil,
true,
)
} else if wrap.CurrSubModule == "categories" {
content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
{Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
{Name: "List of categories"},
})
content += builder.DataTable(
wrap,
"blog_cats",
"id",
"ASC",
&[]builder.DataTableRow{
{
DBField: "id",
},
{
DBField: "user",
},
{
DBField: "name",
NameInTable: "Category",
CallBack: func(values *[]string) string {
depth := utils.StrToInt((*values)[4]) - 1
if depth < 0 {
depth = 0
}
sub := strings.Repeat("— ", depth)
name := `` + sub + html.EscapeString((*values)[2]) + ``
return `` + name + `
`
},
},
{
DBField: "alias",
},
{
DBField: "depth",
},
},
func(values *[]string) string {
return builder.DataTableAction(&[]builder.DataTableActionRow{
{
Icon: assets.SysSvgIconEdit,
Href: "/cp/" + wrap.CurrModule + "/categories-modify/" + (*values)[0] + "/",
Hint: "Edit",
},
{
Icon: assets.SysSvgIconRemove,
Href: "javascript:fave.ActionDataTableDelete(this,'blog-categories-delete','" +
(*values)[0] + "','Are you sure want to delete category?');",
Hint: "Delete",
Classes: "delete",
},
})
},
"/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
nil,
func(limit_offset int, pear_page int) (*sql.Rows, error) {
return wrap.DB.Query(
`SELECT
node.id,
node.user,
node.name,
node.alias,
(COUNT(parent.id) - 1) AS depth
FROM
blog_cats AS node,
blog_cats AS parent
WHERE
node.lft BETWEEN parent.lft AND parent.rgt AND
node.id > 1
GROUP BY
node.id
ORDER BY
node.lft ASC
;`,
)
},
false,
)
} else if wrap.CurrSubModule == "add" || wrap.CurrSubModule == "modify" {
if wrap.CurrSubModule == "add" {
content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
{Name: "Add new post"},
})
} else {
content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
{Name: "Modify post"},
})
}
data := utils.MySql_blog_posts{
A_id: 0,
A_user: 0,
A_name: "",
A_alias: "",
A_content: "",
A_datetime: 0,
A_active: 0,
}
if wrap.CurrSubModule == "modify" {
if len(wrap.UrlArgs) != 3 {
return "", "", ""
}
if !utils.IsNumeric(wrap.UrlArgs[2]) {
return "", "", ""
}
err := wrap.DB.QueryRow(`
SELECT
id,
user,
name,
alias,
content,
active
FROM
blog_posts
WHERE
id = ?
LIMIT 1;`,
utils.StrToInt(wrap.UrlArgs[2]),
).Scan(
&data.A_id,
&data.A_user,
&data.A_name,
&data.A_alias,
&data.A_content,
&data.A_active,
)
if err != nil {
return "", "", ""
}
}
// All post current categories
var selids []int
if data.A_id > 0 {
rows, err := wrap.DB.Query("SELECT category_id FROM blog_cat_post_rel WHERE post_id = ?;", data.A_id)
if err == nil {
defer rows.Close()
values := make([]int, 1)
scan := make([]interface{}, len(values))
for i := range values {
scan[i] = &values[i]
}
for rows.Next() {
err = rows.Scan(scan...)
if err == nil {
selids = append(selids, int(values[0]))
}
}
}
}
btn_caption := "Add"
if wrap.CurrSubModule == "modify" {
btn_caption = "Save"
}
content += builder.DataForm(wrap, []builder.DataFormField{
{
Kind: builder.DFKHidden,
Name: "action",
Value: "blog-modify",
},
{
Kind: builder.DFKHidden,
Name: "id",
Value: utils.IntToStr(data.A_id),
},
{
Kind: builder.DFKText,
Caption: "Post name",
Name: "name",
Value: data.A_name,
},
{
Kind: builder.DFKText,
Caption: "Post alias",
Name: "alias",
Value: data.A_alias,
Hint: "Example: our-news",
},
{
Kind: builder.DFKText,
Caption: "Categories",
Name: "cats",
Value: "0",
CallBack: func(field *builder.DataFormField) string {
return ``
},
},
{
Kind: builder.DFKTextArea,
Caption: "Post content",
Name: "content",
Value: data.A_content,
Classes: "autosize",
},
{
Kind: builder.DFKCheckBox,
Caption: "Active",
Name: "active",
Value: utils.IntToStr(data.A_active),
},
{
Kind: builder.DFKMessage,
},
{
Kind: builder.DFKSubmit,
Value: btn_caption,
Target: "add-edit-button",
},
})
if wrap.CurrSubModule == "add" {
sidebar += ``
} else {
sidebar += ``
}
} else if wrap.CurrSubModule == "categories-add" || wrap.CurrSubModule == "categories-modify" {
if wrap.CurrSubModule == "categories-add" {
content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
{Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
{Name: "Add new category"},
})
} else {
content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
{Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
{Name: "Modify category"},
})
}
data := utils.MySql_blog_category{
A_id: 0,
A_user: 0,
A_name: "",
A_alias: "",
A_lft: 0,
A_rgt: 0,
}
if wrap.CurrSubModule == "categories-modify" {
if len(wrap.UrlArgs) != 3 {
return "", "", ""
}
if !utils.IsNumeric(wrap.UrlArgs[2]) {
return "", "", ""
}
err := wrap.DB.QueryRow(`
SELECT
id,
user,
name,
alias,
lft,
rgt
FROM
blog_cats
WHERE
id = ?
LIMIT 1;`,
utils.StrToInt(wrap.UrlArgs[2]),
).Scan(
&data.A_id,
&data.A_user,
&data.A_name,
&data.A_alias,
&data.A_lft,
&data.A_rgt,
)
if err != nil {
return "", "", ""
}
}
btn_caption := "Add"
if wrap.CurrSubModule == "categories-modify" {
btn_caption = "Save"
}
parentId := 0
if wrap.CurrSubModule == "categories-modify" {
parentId = this.blog_GetCategoryParentId(wrap, data.A_id)
}
content += builder.DataForm(wrap, []builder.DataFormField{
{
Kind: builder.DFKHidden,
Name: "action",
Value: "blog-categories-modify",
},
{
Kind: builder.DFKHidden,
Name: "id",
Value: utils.IntToStr(data.A_id),
},
{
Kind: builder.DFKText,
Caption: "Parent",
Name: "parent",
Value: "0",
CallBack: func(field *builder.DataFormField) string {
return ``
},
},
{
Kind: builder.DFKText,
Caption: "Name",
Name: "name",
Value: data.A_name,
},
{
Kind: builder.DFKText,
Caption: "Alias",
Name: "alias",
Value: data.A_alias,
Hint: "Example: popular-posts",
},
{
Kind: builder.DFKMessage,
},
{
Kind: builder.DFKSubmit,
Value: btn_caption,
Target: "add-edit-button",
},
})
if wrap.CurrSubModule == "categories-add" {
sidebar += ``
} else {
sidebar += ``
}
}
return this.getSidebarModules(wrap), content, sidebar
})
}
func (this *Modules) RegisterAction_BlogModify() *Action {
return this.newAction(AInfo{
WantDB: true,
Mount: "blog-modify",
WantAdmin: true,
}, func(wrap *wrapper.Wrapper) {
pf_id := wrap.R.FormValue("id")
pf_name := wrap.R.FormValue("name")
pf_alias := wrap.R.FormValue("alias")
pf_content := wrap.R.FormValue("content")
pf_active := wrap.R.FormValue("active")
if pf_active == "" {
pf_active = "0"
}
if !utils.IsNumeric(pf_id) {
wrap.MsgError(`Inner system error`)
return
}
if pf_name == "" {
wrap.MsgError(`Please specify page name`)
return
}
if pf_alias == "" {
pf_alias = utils.GenerateSingleAlias(pf_name)
}
if !utils.IsValidSingleAlias(pf_alias) {
wrap.MsgError(`Please specify correct post alias`)
return
}
if pf_id == "0" {
// Add new post
_, err := wrap.DB.Exec(
`INSERT INTO blog_posts SET
user = ?,
name = ?,
alias = ?,
content = ?,
datetime = ?,
active = ?
;`,
wrap.User.A_id,
pf_name,
pf_alias,
pf_content,
utils.UnixTimestampToMySqlDateTime(utils.GetCurrentUnixTimestamp()),
pf_active,
)
if err != nil {
wrap.MsgError(err.Error())
return
}
wrap.Write(`window.location='/cp/blog/';`)
} else {
// Update post
_, err := wrap.DB.Exec(
`UPDATE blog_posts SET
name = ?,
alias = ?,
content = ?,
active = ?
WHERE
id = ?
;`,
pf_name,
pf_alias,
pf_content,
pf_active,
utils.StrToInt(pf_id),
)
if err != nil {
wrap.MsgError(err.Error())
return
}
wrap.Write(`window.location='/cp/blog/modify/` + pf_id + `/';`)
}
})
}
func (this *Modules) RegisterAction_BlogDelete() *Action {
return this.newAction(AInfo{
WantDB: true,
Mount: "blog-delete",
WantAdmin: true,
}, func(wrap *wrapper.Wrapper) {
pf_id := wrap.R.FormValue("id")
if !utils.IsNumeric(pf_id) {
wrap.MsgError(`Inner system error`)
return
}
// Start transaction with table lock
_, err := wrap.DB.Exec("LOCK TABLES blog_posts WRITE, blog_cat_post_rel WRITE;")
if err != nil {
wrap.MsgError(err.Error())
return
}
tx, err := wrap.DB.Begin()
if err != nil {
wrap.MsgError(err.Error())
return
}
// Delete target post with category connection data
if _, err = tx.Exec("DELETE FROM blog_cat_post_rel WHERE post_id = ?;", pf_id); err != nil {
tx.Rollback()
wrap.MsgError(err.Error())
return
}
if _, err = tx.Exec("DELETE FROM blog_posts WHERE id = ?;", pf_id); err != nil {
tx.Rollback()
wrap.MsgError(err.Error())
return
}
// Commit all changes and unlock table
err = tx.Commit()
if err != nil {
wrap.MsgError(err.Error())
return
}
_, err = wrap.DB.Exec("UNLOCK TABLES;")
if err != nil {
wrap.MsgError(err.Error())
return
}
// Reload current page
wrap.Write(`window.location.reload(false);`)
})
}