added dump/restore and fixed title stuff
This commit is contained in:
parent
d4971cda89
commit
8d3187b160
13 changed files with 200627 additions and 189988 deletions
|
|
@ -5,6 +5,7 @@ package cmd
|
|||
import (
|
||||
"git.giftfish.de/ston1th/godrop/v2"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/db"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/log"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/server"
|
||||
"github.com/urfave/cli"
|
||||
|
|
@ -18,13 +19,18 @@ import (
|
|||
|
||||
const (
|
||||
defDataDir = "/var/lib/gowiki"
|
||||
defListen = "127.0.0.1:8090"
|
||||
defListen = "127.0.0.1:8080"
|
||||
defLogFile = "gowiki.log"
|
||||
|
||||
defRunUser = "wiki"
|
||||
defRunGroup = "wiki"
|
||||
)
|
||||
|
||||
var (
|
||||
conf core.Config
|
||||
dumpFile string
|
||||
)
|
||||
|
||||
func initServer(conf core.Config) (err error) {
|
||||
dropCfg := godrop.Config{
|
||||
User: conf.User,
|
||||
|
|
@ -70,11 +76,6 @@ func initServer(conf core.Config) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
var (
|
||||
verbose bool
|
||||
conf core.Config
|
||||
)
|
||||
|
||||
func Run(version string) {
|
||||
app := cli.NewApp()
|
||||
app.Name = "gowiki"
|
||||
|
|
@ -95,31 +96,67 @@ func Run(version string) {
|
|||
},
|
||||
{
|
||||
Name: "dump",
|
||||
Usage: "create a json dump of all articles in the data directory (dump is written to stdout) gowiki needs to be stopped",
|
||||
Usage: "create a json dump of all articles in the data directory (gowiki needs to be stopped)",
|
||||
Flags: defaultFlags(dumpRestoreFlags()),
|
||||
Action: func(c *cli.Context) error {
|
||||
if err := os.Chdir(conf.DataDir); err != nil {
|
||||
var (
|
||||
file = os.Stdout
|
||||
err error
|
||||
)
|
||||
if dumpFile != "-" {
|
||||
file, err = os.OpenFile(dumpFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
stdlog.Fatal("dump: ", err)
|
||||
}
|
||||
}
|
||||
if err = os.Chdir(conf.DataDir); err != nil {
|
||||
stdlog.Fatal("dump: ", err)
|
||||
}
|
||||
DB, err := db.New(conf.DataDir)
|
||||
if err != nil {
|
||||
stdlog.Fatal("dump: ", err)
|
||||
}
|
||||
if err = DB.Dump(file); err != nil {
|
||||
stdlog.Fatal("dump: ", err)
|
||||
}
|
||||
file.Close()
|
||||
err = DB.Close()
|
||||
if err != nil {
|
||||
stdlog.Fatal("dump: ", err)
|
||||
}
|
||||
//TODO
|
||||
//if err := db.Dump(blevePath, verbose); err != nil {
|
||||
// stdlog.Fatal("dump: ", err)
|
||||
//}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "restore",
|
||||
Usage: "restore a json dump to the data directory (dump is read from stdin) gowiki needs to be stopped",
|
||||
Usage: "restore a json dump to the data directory (gowiki needs to be stopped)",
|
||||
Flags: defaultFlags(dumpRestoreFlags()),
|
||||
Action: func(c *cli.Context) error {
|
||||
if err := os.Chdir(conf.DataDir); err != nil {
|
||||
var (
|
||||
file = os.Stdin
|
||||
err error
|
||||
)
|
||||
if dumpFile != "-" {
|
||||
file, err = os.Open(dumpFile)
|
||||
if err != nil {
|
||||
stdlog.Fatal("dump: ", err)
|
||||
}
|
||||
}
|
||||
if err = os.Chdir(conf.DataDir); err != nil {
|
||||
stdlog.Fatal("restore: ", err)
|
||||
}
|
||||
DB, err := db.New(conf.DataDir)
|
||||
if err != nil {
|
||||
stdlog.Fatal("restore: ", err)
|
||||
}
|
||||
if err = DB.Restore(file); err != nil {
|
||||
stdlog.Fatal("restore: ", err)
|
||||
}
|
||||
file.Close()
|
||||
err = DB.Close()
|
||||
if err != nil {
|
||||
stdlog.Fatal("restore: ", err)
|
||||
}
|
||||
//TODO
|
||||
//if err := db.Restore(blevePath, verbose); err != nil {
|
||||
// stdlog.Fatal("restore: ", err)
|
||||
//}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
|
@ -178,10 +215,11 @@ func serverFlags() []cli.Flag {
|
|||
|
||||
func dumpRestoreFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "verbose, v",
|
||||
Usage: "enable verbose mode",
|
||||
Destination: &verbose,
|
||||
cli.StringFlag{
|
||||
Name: "file, f",
|
||||
Value: "-",
|
||||
Usage: "file to read/write dump (default stdin/stdout)",
|
||||
Destination: &dumpFile,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28
pkg/db/db.go
28
pkg/db/db.go
|
|
@ -7,7 +7,9 @@ import (
|
|||
"git.giftfish.de/ston1th/gowiki/pkg/cache"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/index"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/render"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/store"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -61,10 +63,30 @@ func New(datadir string) (db *DB, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (db *DB) Close() error {
|
||||
err := db.store.Close()
|
||||
func (db *DB) Dump(w io.Writer) error {
|
||||
return db.store.Dump(w)
|
||||
}
|
||||
|
||||
func (db *DB) Restore(r io.Reader) (err error) {
|
||||
err = db.store.Restore(r)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
err = db.store.ForEach(func(k string, _ []byte) error {
|
||||
if trim, ok := hasTrimPrefix(k, pagePrefix); ok {
|
||||
p := new(core.Page)
|
||||
db.store.Get(pagePrefix+trim, p)
|
||||
db.Index.Add(p.Title, p.StoreTitle, render.Render(p))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) Close() (err error) {
|
||||
err = db.store.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Index.Close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
package db
|
||||
|
||||
/*import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
||||
)
|
||||
|
||||
type DBDump struct {
|
||||
Pages []DumpPage `json:"pages"`
|
||||
Snippets []Snippet `json:"snippets"`
|
||||
Users []User `json:"users"`
|
||||
}
|
||||
|
||||
type DumpPage struct {
|
||||
Title string `json:"title"`
|
||||
LinkTitle string `json:"link_title"`
|
||||
MD string `json:"md"`
|
||||
Created string `json:"created"`
|
||||
Updated string `json:"updated"`
|
||||
Public bool `json:"public"`
|
||||
}
|
||||
|
||||
func verboseLog(prefix, title string, v bool) {
|
||||
if v {
|
||||
fmt.Fprintln(os.Stderr, prefix, title)
|
||||
}
|
||||
}
|
||||
|
||||
func Dump(path string, v bool) (err error) {
|
||||
bs, err := NewBoltStore()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var dump DBDump
|
||||
//TODO bs.GetAllPages
|
||||
var pages []*core.Page
|
||||
for _, p := range pages {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
verboseLog("dump:", p.Title, v)
|
||||
dump.Pages = append(dump.Pages, DumpPage{
|
||||
Title: p.Title,
|
||||
LinkTitle: p.LinkTitle,
|
||||
MD: p.MD,
|
||||
Created: p.Created,
|
||||
Updated: p.Updated,
|
||||
Public: p.Public,
|
||||
})
|
||||
}
|
||||
//TODO snippets
|
||||
//verboseLog("dump:", "snippets", v)
|
||||
verboseLog("dump:", "users", v)
|
||||
dump.Users, err = bs.DumpUsers()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return json.NewEncoder(os.Stdout).Encode(dump)
|
||||
}
|
||||
|
||||
func Restore(path string, v bool) (err error) {
|
||||
i, err := NewIndex(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer i.Close()
|
||||
bs, err := NewBoltStore()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var dump DBDump
|
||||
err = json.NewDecoder(os.Stdin).Decode(&dump)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, art := range dump.Articles {
|
||||
verboseLog("restore:", art.Title, v)
|
||||
err = i.Restore(&art)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
//TODO snippets
|
||||
//verboseLog("restore:", "snippets", v)
|
||||
verboseLog("restore:", "users", v)
|
||||
err = bs.RestoreUsers(dump.Users)
|
||||
return
|
||||
}*/
|
||||
|
|
@ -25,7 +25,7 @@ func (db *DB) GetAllPages(username string) (pages core.Pages) {
|
|||
if trim == core.IndexURI {
|
||||
return nil
|
||||
}
|
||||
p, err := db.GetPage(trim, username)
|
||||
p, err := db.getPage(trim, username)
|
||||
if err == nil {
|
||||
pages = append(pages, *p)
|
||||
}
|
||||
|
|
@ -36,11 +36,12 @@ func (db *DB) GetAllPages(username string) (pages core.Pages) {
|
|||
return
|
||||
}
|
||||
|
||||
func (db *DB) GetPage(title, username string) (p *core.Page, err error) {
|
||||
p = db.cache.Get(title)
|
||||
func (db *DB) GetPage(section, title, username string) (p *core.Page, err error) {
|
||||
st := render.StoreTitle(section, title)
|
||||
p = db.cache.Get(st)
|
||||
if p == nil {
|
||||
p, err = db.getPage(title, username)
|
||||
db.cache.Add(title, p)
|
||||
p, err = db.getPage(st, username)
|
||||
db.cache.Add(st, p)
|
||||
return
|
||||
}
|
||||
if !core.ReadPerm(username, p) {
|
||||
|
|
@ -74,7 +75,7 @@ func (db *DB) CreatePage(title, section, markdown, username string, p core.Permi
|
|||
return
|
||||
}
|
||||
}
|
||||
st := render.StoreTitle(section, title)
|
||||
st := render.StoreTitle(section, render.Title(title))
|
||||
if _, err = db.getPage(st, username); err != nil && err != store.ErrKeyNotFound {
|
||||
return
|
||||
}
|
||||
|
|
@ -130,7 +131,7 @@ func (db *DB) UpdatePage(title, section, markdown, username string, p core.Permi
|
|||
return
|
||||
}
|
||||
|
||||
err = db.Index.Add(title, st, search)
|
||||
err = db.Index.Add(page.Title, st, search)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"git.giftfish.de/ston1th/gowiki/pkg/log"
|
||||
"git.giftfish.de/ston1th/jwt/v3"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -19,26 +20,21 @@ var (
|
|||
errUserNotFound = dbErr("user not found")
|
||||
errUserExists = dbErr("user already exist")
|
||||
errUserReserved = dbErr("username is reserved")
|
||||
|
||||
userRe = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||
)
|
||||
|
||||
func (db *DB) DumpUsers() (users core.Users, err error) {
|
||||
db.store.ForEach(func(k string, _ []byte) error {
|
||||
func (db *DB) GetUsers() (users core.Users, err error) {
|
||||
err = db.store.ForEach(func(k string, _ []byte) error {
|
||||
if trim, ok := hasTrimPrefix(k, userPrefix); ok {
|
||||
u, err := db.GetUser(trim)
|
||||
u.Password = ""
|
||||
if err == nil {
|
||||
users = append(users, u)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) GetUsers() (users core.Users, err error) {
|
||||
users, err = db.DumpUsers()
|
||||
for i := range users {
|
||||
users[i].Password = ""
|
||||
}
|
||||
sort.Sort(users)
|
||||
return
|
||||
}
|
||||
|
|
@ -58,31 +54,8 @@ func (db *DB) UserExists(username string) error {
|
|||
return db.store.Get(userPrefix+username, nil)
|
||||
}
|
||||
|
||||
// TODO
|
||||
/*func (bs *BoltStore) RestoreUsers(users []User) error {
|
||||
return bs.db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(userTable))
|
||||
err := b.ForEach(func(k, v []byte) error {
|
||||
return b.Delete(k)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, u := range users {
|
||||
v, err := bs.Marshal(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = b.Put([]byte(u.Username), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}*/
|
||||
|
||||
func (db *DB) CreateUser(username, password string, admin bool) error {
|
||||
username = userRe.ReplaceAllString(username, "")
|
||||
if reservedUser(username) {
|
||||
return errUserReserved
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ var (
|
|||
|
||||
func Render(p *core.Page) string {
|
||||
rend := blackfriday.MarkdownCommon([]byte(p.Markdown))
|
||||
index, html := buildIndex(string(rend))
|
||||
index, html := buildTOC(string(rend))
|
||||
html = strings.Replace(html, "<table>", `<table class="table">`, -1)
|
||||
html = strings.Replace(html, "</h1>", `</h1><hr>`, -1)
|
||||
html = strings.Replace(html, "<a", `<a target="_blank"`, -1)
|
||||
|
|
@ -58,12 +58,17 @@ func UnstoreTitle(storeTitle string) (section, title string) {
|
|||
return
|
||||
}
|
||||
|
||||
func buildIndex(html string) (string, string) {
|
||||
func buildTOC(html string) (string, string) {
|
||||
var ret string
|
||||
m := make(map[string]int)
|
||||
hn := reIndex.FindAllStringSubmatch(html, -1)
|
||||
html = reHeader.ReplaceAllString(html, `<a id="${2}" class="anchor"></a>${1}${2}${3}`)
|
||||
html = reLink.ReplaceAllStringFunc(html, spaceReplace)
|
||||
html = reLink.ReplaceAllStringFunc(html, func(s string) string {
|
||||
if len(s) >= 3 {
|
||||
return `id="` + Title(s[2:]) + `"`
|
||||
}
|
||||
return s
|
||||
})
|
||||
for k, v := range hn {
|
||||
link := Title(v[2])
|
||||
i := m[link]
|
||||
|
|
|
|||
|
|
@ -86,11 +86,11 @@ func loginHandler(ctx *Context) {
|
|||
case "GET":
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
user := ctx.Form("user")
|
||||
password := ctx.Form("password")
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
user := ctx.Form("user")
|
||||
password := ctx.Form("password")
|
||||
if user == "" || password == "" {
|
||||
ctx.Error("wrong inputs")
|
||||
return
|
||||
|
|
@ -115,10 +115,10 @@ func searchHandler(ctx *Context) {
|
|||
case "GET":
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
search := ctx.Form("search")
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
search := ctx.Form("search")
|
||||
|
||||
res, err := ctx.Srv.DB.Index.Search(search)
|
||||
if err != nil {
|
||||
|
|
@ -150,8 +150,11 @@ func pageNewHandler(ctx *Context) {
|
|||
ctx.Data.Data = core.Page{Perm: core.Public}
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
section := ctx.Form("section")
|
||||
title := render.Title(ctx.Form("title"))
|
||||
title := ctx.Form("title")
|
||||
markdown := ctx.Form("markdown")
|
||||
perm := core.ParsePermString(ctx.Form("perm"))
|
||||
p := core.Page{
|
||||
|
|
@ -160,9 +163,7 @@ func pageNewHandler(ctx *Context) {
|
|||
Perm: perm,
|
||||
}
|
||||
ctx.Data.Data = p
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
|
||||
if section != core.WikiSection {
|
||||
section = ctx.User()
|
||||
}
|
||||
|
|
@ -213,7 +214,7 @@ func pageHandler(ctx *Context) {
|
|||
ctx.Template("pageHandler")
|
||||
}
|
||||
}
|
||||
page, err := ctx.Srv.DB.GetPage(render.StoreTitle(section, title), user)
|
||||
page, err := ctx.Srv.DB.GetPage(section, title, user)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
ctx.NotFound()
|
||||
|
|
@ -236,10 +237,9 @@ func pageShareHandler(ctx *Context) {
|
|||
ctx.Template("pageShareHandler")
|
||||
ctx.Data = webData{}
|
||||
section := ctx.Var("section")
|
||||
title := render.Title(ctx.Var("title"))
|
||||
title := ctx.Var("title")
|
||||
user := ctx.User()
|
||||
st := render.StoreTitle(section, title)
|
||||
page, err := ctx.Srv.DB.GetPage(st, user)
|
||||
page, err := ctx.Srv.DB.GetPage(section, title, user)
|
||||
if err != nil {
|
||||
ctx.NotFound()
|
||||
return
|
||||
|
|
@ -248,18 +248,18 @@ func pageShareHandler(ctx *Context) {
|
|||
ctx.Error("only private pages can be shared")
|
||||
return
|
||||
}
|
||||
ctx.Data.Data = st
|
||||
ctx.Data.Data = page.StoreTitle
|
||||
ctx.Data.Title = page.Title
|
||||
ctx.Data.BodyTitle = page.Title
|
||||
switch ctx.Method() {
|
||||
case "GET":
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
duration := ctx.Form("duration")
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
d, err := time.ParseDuration(duration)
|
||||
|
||||
d, err := time.ParseDuration(ctx.Form("duration"))
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
return
|
||||
|
|
@ -295,6 +295,7 @@ func pageBlacklistHandler(ctx *Context) {
|
|||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
|
||||
t, err := jwt.DecodeToken(ctx.Form("share"))
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
|
|
@ -327,8 +328,8 @@ func pageEditHandler(ctx *Context) {
|
|||
ctx.Template("pageEditHandler")
|
||||
ctx.Data = webData{}
|
||||
section := ctx.Var("section")
|
||||
title := render.Title(ctx.Var("title"))
|
||||
page, err := ctx.Srv.DB.GetPage(render.StoreTitle(section, title), ctx.User())
|
||||
title := ctx.Var("title")
|
||||
page, err := ctx.Srv.DB.GetPage(section, title, ctx.User())
|
||||
if err != nil {
|
||||
ctx.NotFound()
|
||||
return
|
||||
|
|
@ -340,12 +341,13 @@ func pageEditHandler(ctx *Context) {
|
|||
ctx.Data.Data = page
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
page.Markdown = ctx.Form("markdown")
|
||||
page.Perm = core.ParsePermString(ctx.Form("perm"))
|
||||
ctx.Data.Data = page
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
page.Markdown = ctx.Form("markdown")
|
||||
page.Perm = core.ParsePermString(ctx.Form("perm"))
|
||||
ctx.Data.Data = page
|
||||
|
||||
err = ctx.Srv.DB.UpdatePage(title, section, page.Markdown, ctx.User(), page.Perm)
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
|
|
@ -357,10 +359,9 @@ func pageEditHandler(ctx *Context) {
|
|||
|
||||
func pageDelHandler(ctx *Context) {
|
||||
section := ctx.Var("section")
|
||||
title := render.Title(ctx.Var("title"))
|
||||
st := render.StoreTitle(section, title)
|
||||
title := ctx.Var("title")
|
||||
ctx.Template("pageDelHandler")
|
||||
ctx.Data.Data = st
|
||||
ctx.Data.Data = render.StoreTitle(section, title)
|
||||
ctx.Data.Title = title
|
||||
ctx.Data.BodyTitle = title
|
||||
switch ctx.Method() {
|
||||
|
|
@ -407,6 +408,9 @@ func userNewHandler(ctx *Context) {
|
|||
case "GET":
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
user := ctx.Form("user")
|
||||
password := ctx.Form("password")
|
||||
repeat := ctx.Form("repeat")
|
||||
|
|
@ -415,9 +419,7 @@ func userNewHandler(ctx *Context) {
|
|||
if admin == "0" {
|
||||
adm = true
|
||||
}
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
|
||||
if user == "" || password == "" || password != repeat {
|
||||
ctx.Error("wrong inputs")
|
||||
return
|
||||
|
|
@ -446,6 +448,9 @@ func userEditHandler(ctx *Context) {
|
|||
ctx.Data.Data = u
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
user := ctx.Var("user")
|
||||
password := ctx.Form("password")
|
||||
repeat := ctx.Form("repeat")
|
||||
|
|
@ -454,9 +459,7 @@ func userEditHandler(ctx *Context) {
|
|||
if admin == "0" {
|
||||
adm = true
|
||||
}
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
|
||||
if user == "" || password != repeat {
|
||||
ctx.Error("wrong inputs")
|
||||
return
|
||||
|
|
@ -504,6 +507,9 @@ func userDelHandler(ctx *Context) {
|
|||
ctx.Data.Data = user
|
||||
ctx.Exec()
|
||||
case "POST":
|
||||
if !ctx.CheckXsrf() {
|
||||
return
|
||||
}
|
||||
if err := ctx.Srv.DB.DeleteUser(ctx.Var("user")); err != nil {
|
||||
log.Println("delete:", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,29 +98,29 @@ var routes = []route{
|
|||
[]string{"GET"},
|
||||
},
|
||||
{
|
||||
"/{section}/{title}",
|
||||
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}",
|
||||
pageHandler,
|
||||
[]string{"GET"},
|
||||
},
|
||||
{
|
||||
"/{section}/{title}/md",
|
||||
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/md",
|
||||
pageMDHandler(
|
||||
pageHandler),
|
||||
[]string{"GET"},
|
||||
},
|
||||
{
|
||||
"/{section}/{title}/share",
|
||||
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/share",
|
||||
pageShareHandler,
|
||||
[]string{"GET", "POST"},
|
||||
},
|
||||
{
|
||||
"/{section}/{title}/edit",
|
||||
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/edit",
|
||||
authHandler(
|
||||
pageEditHandler),
|
||||
[]string{"GET", "POST"},
|
||||
},
|
||||
{
|
||||
"/{section}/{title}/del",
|
||||
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/del",
|
||||
authHandler(
|
||||
pageDelHandler),
|
||||
[]string{"GET", "POST"},
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const (
|
|||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-1LNAeuiM/rtsY1jIgLovUZ7HbYnOCkj3ZyailNA3rFQ="></link>
|
||||
</head>
|
||||
<body>
|
||||
<body id="back-to-top">
|
||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<a href="/" class="navbar-brand">GoWiki</a>
|
||||
|
|
@ -60,7 +60,7 @@ const (
|
|||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div id="back-to-top" class="proper-content">
|
||||
<div class="proper-content">
|
||||
{{if .Msg}}
|
||||
<div class="alert alert-danger msg">
|
||||
<h4>Error!</h4>
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ func NewBoltStore(file string, m Marshaler) (bs *BoltStore, err error) {
|
|||
}
|
||||
|
||||
type dump struct {
|
||||
k string `json:"k"`
|
||||
v []byte `json:"v"`
|
||||
K string `json:"k"`
|
||||
V []byte `json:"v"`
|
||||
}
|
||||
|
||||
func (bs *BoltStore) Dump(w io.Writer) (err error) {
|
||||
|
|
@ -44,7 +44,9 @@ func (bs *BoltStore) Dump(w io.Writer) (err error) {
|
|||
}
|
||||
var d []dump
|
||||
err = bs.ForEach(func(k string, v []byte) error {
|
||||
d = append(d, dump{k, v})
|
||||
b := make([]byte, len(v))
|
||||
copy(b, v)
|
||||
d = append(d, dump{k, b})
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -74,7 +76,7 @@ func (bs *BoltStore) Restore(r io.Reader) (err error) {
|
|||
return bs.db.Update(func(tx *bolt.Tx) (err error) {
|
||||
b := tx.Bucket([]byte(defaultBoltBucket))
|
||||
for _, v := range d {
|
||||
b.Put([]byte(v.k), v.v)
|
||||
b.Put([]byte(v.K), v.V)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue