mirror of https://github.com/jlelse/GoBlog
Add database-based settings, settings screen and migrate sections to db and allow to configure them
parent
22fce13246
commit
cd9d500a55
@ -0,0 +1,9 @@
|
||||
create table sections (
|
||||
blog text not null,
|
||||
name text not null,
|
||||
title text not null default '',
|
||||
description text not null default '',
|
||||
pathtemplate text not null default '',
|
||||
showfull boolean not null default false,
|
||||
primary key (blog, name)
|
||||
);
|
@ -0,0 +1,5 @@
|
||||
create table settings (
|
||||
name text not null,
|
||||
value text not null default '',
|
||||
primary key (name)
|
||||
);
|
@ -0,0 +1,129 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
const settingsPath = "/settings"
|
||||
|
||||
func (a *goBlog) serveSettings(w http.ResponseWriter, r *http.Request) {
|
||||
blog, bc := a.getBlog(r)
|
||||
|
||||
sections := lo.Values(bc.Sections)
|
||||
sort.Slice(sections, func(i, j int) bool { return sections[i].Name < sections[j].Name })
|
||||
|
||||
a.render(w, r, a.renderSettings, &renderData{
|
||||
Data: &settingsRenderData{
|
||||
blog: blog,
|
||||
sections: sections,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const settingsDeleteSectionPath = "/deletesection"
|
||||
|
||||
func (a *goBlog) settingsDeleteSection(w http.ResponseWriter, r *http.Request) {
|
||||
blog, bc := a.getBlog(r)
|
||||
section := r.FormValue("sectionname")
|
||||
// Check if any post uses this section
|
||||
count, err := a.db.countPosts(&postsRequestConfig{
|
||||
blog: blog,
|
||||
sections: []string{section},
|
||||
})
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to check if section is still used", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
a.serveError(w, r, "Section is still used", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Delete section
|
||||
err = a.deleteSection(blog, section)
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to delete section from the database", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Reload sections
|
||||
err = a.loadSections()
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to reload section configuration from the database", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
a.reloadRouter()
|
||||
a.cache.purge()
|
||||
http.Redirect(w, r, bc.getRelativePath(settingsPath), http.StatusFound)
|
||||
}
|
||||
|
||||
const settingsCreateSectionPath = "/createsection"
|
||||
|
||||
func (a *goBlog) settingsCreateSection(w http.ResponseWriter, r *http.Request) {
|
||||
blog, bc := a.getBlog(r)
|
||||
// Read values
|
||||
sectionName := r.FormValue("sectionname")
|
||||
sectionTitle := r.FormValue("sectiontitle")
|
||||
if sectionName == "" || sectionTitle == "" {
|
||||
a.serveError(w, r, "Missing values for name or title", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Create section
|
||||
section := &configSection{
|
||||
Name: sectionName,
|
||||
Title: sectionTitle,
|
||||
}
|
||||
err := a.addSection(blog, section)
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to insert section into database", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Reload sections
|
||||
err = a.loadSections()
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to reload section configuration from the database", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
a.reloadRouter()
|
||||
a.cache.purge()
|
||||
http.Redirect(w, r, bc.getRelativePath(settingsPath), http.StatusFound)
|
||||
}
|
||||
|
||||
const settingsUpdateSectionPath = "/updatesection"
|
||||
|
||||
func (a *goBlog) settingsUpdateSection(w http.ResponseWriter, r *http.Request) {
|
||||
blog, bc := a.getBlog(r)
|
||||
// Read values
|
||||
sectionName := r.FormValue("sectionname")
|
||||
sectionTitle := r.FormValue("sectiontitle")
|
||||
if sectionName == "" || sectionTitle == "" {
|
||||
a.serveError(w, r, "Missing values for name or title", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
sectionDescription := r.FormValue("sectiondescription")
|
||||
sectionPathTemplate := r.FormValue("sectionpathtemplate")
|
||||
sectionShowFull := r.FormValue("sectionshowfull") == "on"
|
||||
// Create section
|
||||
section := &configSection{
|
||||
Name: sectionName,
|
||||
Title: sectionTitle,
|
||||
Description: sectionDescription,
|
||||
PathTemplate: sectionPathTemplate,
|
||||
ShowFull: sectionShowFull,
|
||||
}
|
||||
err := a.updateSection(blog, sectionName, section)
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to update section in database", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Reload sections
|
||||
err = a.loadSections()
|
||||
if err != nil {
|
||||
a.serveError(w, r, "Failed to reload section configuration from the database", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
a.reloadRouter()
|
||||
a.cache.purge()
|
||||
http.Redirect(w, r, bc.getRelativePath(settingsPath), http.StatusFound)
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func (a *goBlog) getSettingValue(name string) (string, error) {
|
||||
row, err := a.db.queryRow("select value from settings where name = @name", sql.Named("name", name))
|
||||
if err != nil {
|
||||
return "",
|
||||
err
|
||||
}
|
||||
var value string
|
||||
err = row.Scan(&value)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return "", nil
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (a *goBlog) saveSettingValue(name, value string) error {
|
||||
_, err := a.db.exec(
|
||||
"insert into settings (name, value) values (@name, @value) on conflict (name) do update set value = @value2",
|
||||
sql.Named("name", name),
|
||||
sql.Named("value", value),
|
||||
sql.Named("value2", value),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *goBlog) loadSections() error {
|
||||
for blog, bc := range a.cfg.Blogs {
|
||||
sections, err := a.getSections(blog)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bc.Sections = sections
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *goBlog) getSections(blog string) (map[string]*configSection, error) {
|
||||
rows, err := a.db.query("select name, title, description, pathtemplate, showfull from sections where blog = @blog", sql.Named("blog", blog))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sections := map[string]*configSection{}
|
||||
for rows.Next() {
|
||||
section := &configSection{}
|
||||
err = rows.Scan(§ion.Name, §ion.Title, §ion.Description, §ion.PathTemplate, §ion.ShowFull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sections[section.Name] = section
|
||||
}
|
||||
return sections, nil
|
||||
}
|
||||
|
||||
func (a *goBlog) saveAllSections() error {
|
||||
for blog, bc := range a.cfg.Blogs {
|
||||
for k, s := range bc.Sections {
|
||||
s.Name = k
|
||||
if err := a.addSection(blog, s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *goBlog) addSection(blog string, section *configSection) error {
|
||||
_, err := a.db.exec(
|
||||
"insert into sections (blog, name, title, description, pathtemplate, showfull) values (@blog, @name, @title, @description, @pathtemplate, @showfull)",
|
||||
sql.Named("blog", blog),
|
||||
sql.Named("name", section.Name),
|
||||
sql.Named("title", section.Title),
|
||||
sql.Named("description", section.Description),
|
||||
sql.Named("pathtemplate", section.PathTemplate),
|
||||
sql.Named("showfull", section.ShowFull),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *goBlog) deleteSection(blog string, name string) error {
|
||||
_, err := a.db.exec("delete from sections where blog = @blog and name = @name", sql.Named("blog", blog), sql.Named("name", name))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *goBlog) updateSection(blog string, name string, section *configSection) error {
|
||||
_, err := a.db.exec(
|
||||
"update sections set title = @title, description = @description, pathtemplate = @pathtemplate, showfull = @showfull where blog = @blog and name = @name",
|
||||
sql.Named("title", section.Title),
|
||||
sql.Named("description", section.Description),
|
||||
sql.Named("pathtemplate", section.PathTemplate),
|
||||
sql.Named("showfull", section.ShowFull),
|
||||
sql.Named("blog", blog),
|
||||
sql.Named("name", section.Name),
|
||||
)
|
||||
return err
|
||||
}
|