199
package main
import (
"encoding/json"
"fmt"
"github.com/asdine/storm/v3"
"go.etcd.io/bbolt"
"log"
"net/http"
"path/filepath"
"sophuwu.site/myweb/config"
"sophuwu.site/myweb/template"
"strings"
"time"
)
var DB *storm.DB
func OpenDB() {
db, err := storm.Open(config.DBPath)
if err != nil {
log.Fatalf("failed to open db: %v", err)
}
DB = db
}
func CloseDB() {
err := DB.Close()
if err != nil {
log.Println(err)
}
}
// AddRequiredData looks for important data types in the db
// and adds a placeholder if they don't exist. This is useful
// for the first run of the server to prevent errors.
func AddRequiredData() {
d, err := GetPageData("index")
if err != nil || d == nil {
_ = SetPageData("index", template.HTMLDataMap{
"Title": "The title of the page",
"Description": "The description for meta tags",
"AboutText": []string{
"Paragraph 1",
},
"ImagePath": "/path/to/pic.jpg",
"Profiles": []Profile{
{"char in iconfont", "name of url", "URL", "username"},
},
"Content": "<p>HTML content</p>",
})
}
d, err = GetPageData("blogs")
if err != nil || d == nil {
_ = SetPageData("blogs", template.HTMLDataMap{
"Title": "The title of the page",
"Description": "The description for meta tags",
})
}
d, err = GetPageData("anims")
if err != nil || d == nil {
_ = SetPageData("anims", template.HTMLDataMap{
"Title": "The title of the page",
"Description": "The description for meta tags",
})
}
}
// GetPageData returns a map of page metadata and data
// used for index/list pages which don't have a separate
// data source.
func GetPageData(page string) (template.HTMLDataMap, error) {
var d template.HTMLDataMap
err := DB.Get("pages", page, &d)
return d, err
}
// SetPageData writes a HTMLDataMap to the db for persistent
// storage of page data without its own data source.
func SetPageData(page string, data template.HTMLDataMap) error {
return DB.Set("pages", page, data)
}
// EditIndex handles the /manage/edit/ route for editing the
// index page's data and metadata.
func EditIndex(w http.ResponseWriter, r *http.Request) {
var err error
page := r.URL.Query().Get("page")
if page == "" {
HttpErr(w, r, 404)
}
if r.Method == "GET" && r.URL.Path == "/manage/edit/" {
var d template.HTMLDataMap
d, err = GetPageData(page)
if CheckHttpErr(err, w, r, 404) {
return
}
var b []byte
b, err = json.MarshalIndent(d, "", " ")
if CheckHttpErr(err, w, r, 500) {
return
}
bb := string(b)
data := template.Data("Edit "+page, "Edit the page's data and metadata")
data.Set("Data", bb)
data.Set("EditUrl", "/manage/edit/save?page="+page)
err = template.Use(w, r, "edit", data)
CheckHttpErr(err, w, r, 500)
return
} else if r.Method == "POST" && r.URL.Path == "/manage/edit/save" {
err = r.ParseForm()
if CheckHttpErr(err, w, r, 500) {
return
}
var bb string
bb = r.Form.Get("data")
if bb == "" {
HttpErr(w, r, 400)
return
}
var d template.HTMLDataMap
err = json.Unmarshal([]byte(bb), &d)
if CheckHttpErr(err, w, r, 400) {
return
}
err = SetPageData(page, d)
if CheckHttpErr(err, w, r, 400) {
return
}
http.Redirect(w, r, "/", 302)
return
}
HttpErr(w, r, 405)
}
// UrlOpt is a struct for the options on the manage page.
type UrlOpt struct{ Name, URL string }
// ManagerHandler handles the /manage/ route for managing
// the website. It displays a list of options for managing
// the website's content. And forwards to the appropriate
// handler for each option.
func ManagerHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/manage/" {
data := template.Data("Manage", config.URL)
data["Options"] = []UrlOpt{
{"Edit index", "/manage/edit/?page=index"},
{"Edit blog list meta", "/manage/edit/?page=blogs"},
{"Edit animation meta", "/manage/edit/?page=anims"},
{"Upload media", "/manage/media/"},
{"Delete media", "/manage/delete/media/"},
{"Manage blogs", "/manage/blog/"},
{"Manage Animations", "/manage/animation/"},
{"Backup", "/manage/backup/"},
}
err := template.Use(w, r, "manage", data)
CheckHttpErr(err, w, r, 500)
return
}
if r.URL.Path == "/manage/edit/" || r.URL.Path == "/manage/edit/save" {
EditIndex(w, r)
return
}
if r.URL.Path == "/manage/media/" {
ManageMedia(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/manage/delete/media/") {
DeleteMedia(w, r)
return
}
if r.URL.Path == "/manage/animation/" {
AnimManager(w, r)
return
}
if r.URL.Path == "/manage/blog/" {
BlogManager(w, r)
return
}
if r.URL.Path == "/manage/backup/" {
BackerUpper(w, r)
return
}
HttpErr(w, r, 404)
}
// BackerUpper is a handler to download the database file.
func BackerUpper(w http.ResponseWriter, r *http.Request) {
err := DB.Bolt.View(func(tx *bbolt.Tx) error {
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s-data.db.%s.bak"`, filepath.Base(config.URL), time.Now().Format("2006-01-02")))
w.Header().Set("Content-Length", fmt.Sprint(int(tx.Size())))
_, err := tx.WriteTo(w)
return err
})
if CheckHttpErr(err, w, r, 500) {
return
}
}