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 (
|
import (
|
||||||
"git.giftfish.de/ston1th/godrop/v2"
|
"git.giftfish.de/ston1th/godrop/v2"
|
||||||
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
"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/log"
|
||||||
"git.giftfish.de/ston1th/gowiki/pkg/server"
|
"git.giftfish.de/ston1th/gowiki/pkg/server"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
|
@ -18,13 +19,18 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defDataDir = "/var/lib/gowiki"
|
defDataDir = "/var/lib/gowiki"
|
||||||
defListen = "127.0.0.1:8090"
|
defListen = "127.0.0.1:8080"
|
||||||
defLogFile = "gowiki.log"
|
defLogFile = "gowiki.log"
|
||||||
|
|
||||||
defRunUser = "wiki"
|
defRunUser = "wiki"
|
||||||
defRunGroup = "wiki"
|
defRunGroup = "wiki"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
conf core.Config
|
||||||
|
dumpFile string
|
||||||
|
)
|
||||||
|
|
||||||
func initServer(conf core.Config) (err error) {
|
func initServer(conf core.Config) (err error) {
|
||||||
dropCfg := godrop.Config{
|
dropCfg := godrop.Config{
|
||||||
User: conf.User,
|
User: conf.User,
|
||||||
|
|
@ -70,11 +76,6 @@ func initServer(conf core.Config) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
verbose bool
|
|
||||||
conf core.Config
|
|
||||||
)
|
|
||||||
|
|
||||||
func Run(version string) {
|
func Run(version string) {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "gowiki"
|
app.Name = "gowiki"
|
||||||
|
|
@ -95,31 +96,67 @@ func Run(version string) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "dump",
|
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()),
|
Flags: defaultFlags(dumpRestoreFlags()),
|
||||||
Action: func(c *cli.Context) error {
|
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)
|
stdlog.Fatal("dump: ", err)
|
||||||
}
|
}
|
||||||
//TODO
|
|
||||||
//if err := db.Dump(blevePath, verbose); err != nil {
|
|
||||||
// stdlog.Fatal("dump: ", err)
|
|
||||||
//}
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "restore",
|
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()),
|
Flags: defaultFlags(dumpRestoreFlags()),
|
||||||
Action: func(c *cli.Context) error {
|
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)
|
stdlog.Fatal("restore: ", err)
|
||||||
}
|
}
|
||||||
//TODO
|
|
||||||
//if err := db.Restore(blevePath, verbose); err != nil {
|
|
||||||
// stdlog.Fatal("restore: ", err)
|
|
||||||
//}
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -178,10 +215,11 @@ func serverFlags() []cli.Flag {
|
||||||
|
|
||||||
func dumpRestoreFlags() []cli.Flag {
|
func dumpRestoreFlags() []cli.Flag {
|
||||||
return []cli.Flag{
|
return []cli.Flag{
|
||||||
cli.BoolFlag{
|
cli.StringFlag{
|
||||||
Name: "verbose, v",
|
Name: "file, f",
|
||||||
Usage: "enable verbose mode",
|
Value: "-",
|
||||||
Destination: &verbose,
|
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/cache"
|
||||||
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
||||||
"git.giftfish.de/ston1th/gowiki/pkg/index"
|
"git.giftfish.de/ston1th/gowiki/pkg/index"
|
||||||
|
"git.giftfish.de/ston1th/gowiki/pkg/render"
|
||||||
"git.giftfish.de/ston1th/gowiki/pkg/store"
|
"git.giftfish.de/ston1th/gowiki/pkg/store"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -61,10 +63,30 @@ func New(datadir string) (db *DB, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Close() error {
|
func (db *DB) Dump(w io.Writer) error {
|
||||||
err := db.store.Close()
|
return db.store.Dump(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Restore(r io.Reader) (err error) {
|
||||||
|
err = db.store.Restore(r)
|
||||||
if err != nil {
|
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()
|
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 {
|
if trim == core.IndexURI {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
p, err := db.GetPage(trim, username)
|
p, err := db.getPage(trim, username)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pages = append(pages, *p)
|
pages = append(pages, *p)
|
||||||
}
|
}
|
||||||
|
|
@ -36,11 +36,12 @@ func (db *DB) GetAllPages(username string) (pages core.Pages) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) GetPage(title, username string) (p *core.Page, err error) {
|
func (db *DB) GetPage(section, title, username string) (p *core.Page, err error) {
|
||||||
p = db.cache.Get(title)
|
st := render.StoreTitle(section, title)
|
||||||
|
p = db.cache.Get(st)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
p, err = db.getPage(title, username)
|
p, err = db.getPage(st, username)
|
||||||
db.cache.Add(title, p)
|
db.cache.Add(st, p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !core.ReadPerm(username, p) {
|
if !core.ReadPerm(username, p) {
|
||||||
|
|
@ -74,7 +75,7 @@ func (db *DB) CreatePage(title, section, markdown, username string, p core.Permi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
st := render.StoreTitle(section, title)
|
st := render.StoreTitle(section, render.Title(title))
|
||||||
if _, err = db.getPage(st, username); err != nil && err != store.ErrKeyNotFound {
|
if _, err = db.getPage(st, username); err != nil && err != store.ErrKeyNotFound {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +131,7 @@ func (db *DB) UpdatePage(title, section, markdown, username string, p core.Permi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Index.Add(title, st, search)
|
err = db.Index.Add(page.Title, st, search)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"git.giftfish.de/ston1th/gowiki/pkg/log"
|
"git.giftfish.de/ston1th/gowiki/pkg/log"
|
||||||
"git.giftfish.de/ston1th/jwt/v3"
|
"git.giftfish.de/ston1th/jwt/v3"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -19,26 +20,21 @@ var (
|
||||||
errUserNotFound = dbErr("user not found")
|
errUserNotFound = dbErr("user not found")
|
||||||
errUserExists = dbErr("user already exist")
|
errUserExists = dbErr("user already exist")
|
||||||
errUserReserved = dbErr("username is reserved")
|
errUserReserved = dbErr("username is reserved")
|
||||||
|
|
||||||
|
userRe = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (db *DB) DumpUsers() (users core.Users, err error) {
|
func (db *DB) GetUsers() (users core.Users, err error) {
|
||||||
db.store.ForEach(func(k string, _ []byte) error {
|
err = db.store.ForEach(func(k string, _ []byte) error {
|
||||||
if trim, ok := hasTrimPrefix(k, userPrefix); ok {
|
if trim, ok := hasTrimPrefix(k, userPrefix); ok {
|
||||||
u, err := db.GetUser(trim)
|
u, err := db.GetUser(trim)
|
||||||
|
u.Password = ""
|
||||||
if err == nil {
|
if err == nil {
|
||||||
users = append(users, u)
|
users = append(users, u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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)
|
sort.Sort(users)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -58,31 +54,8 @@ func (db *DB) UserExists(username string) error {
|
||||||
return db.store.Get(userPrefix+username, nil)
|
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 {
|
func (db *DB) CreateUser(username, password string, admin bool) error {
|
||||||
|
username = userRe.ReplaceAllString(username, "")
|
||||||
if reservedUser(username) {
|
if reservedUser(username) {
|
||||||
return errUserReserved
|
return errUserReserved
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ var (
|
||||||
|
|
||||||
func Render(p *core.Page) string {
|
func Render(p *core.Page) string {
|
||||||
rend := blackfriday.MarkdownCommon([]byte(p.Markdown))
|
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, "<table>", `<table class="table">`, -1)
|
||||||
html = strings.Replace(html, "</h1>", `</h1><hr>`, -1)
|
html = strings.Replace(html, "</h1>", `</h1><hr>`, -1)
|
||||||
html = strings.Replace(html, "<a", `<a target="_blank"`, -1)
|
html = strings.Replace(html, "<a", `<a target="_blank"`, -1)
|
||||||
|
|
@ -58,12 +58,17 @@ func UnstoreTitle(storeTitle string) (section, title string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildIndex(html string) (string, string) {
|
func buildTOC(html string) (string, string) {
|
||||||
var ret string
|
var ret string
|
||||||
m := make(map[string]int)
|
m := make(map[string]int)
|
||||||
hn := reIndex.FindAllStringSubmatch(html, -1)
|
hn := reIndex.FindAllStringSubmatch(html, -1)
|
||||||
html = reHeader.ReplaceAllString(html, `<a id="${2}" class="anchor"></a>${1}${2}${3}`)
|
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 {
|
for k, v := range hn {
|
||||||
link := Title(v[2])
|
link := Title(v[2])
|
||||||
i := m[link]
|
i := m[link]
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,11 @@ func loginHandler(ctx *Context) {
|
||||||
case "GET":
|
case "GET":
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
user := ctx.Form("user")
|
|
||||||
password := ctx.Form("password")
|
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
user := ctx.Form("user")
|
||||||
|
password := ctx.Form("password")
|
||||||
if user == "" || password == "" {
|
if user == "" || password == "" {
|
||||||
ctx.Error("wrong inputs")
|
ctx.Error("wrong inputs")
|
||||||
return
|
return
|
||||||
|
|
@ -115,10 +115,10 @@ func searchHandler(ctx *Context) {
|
||||||
case "GET":
|
case "GET":
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
search := ctx.Form("search")
|
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
search := ctx.Form("search")
|
||||||
|
|
||||||
res, err := ctx.Srv.DB.Index.Search(search)
|
res, err := ctx.Srv.DB.Index.Search(search)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -150,8 +150,11 @@ func pageNewHandler(ctx *Context) {
|
||||||
ctx.Data.Data = core.Page{Perm: core.Public}
|
ctx.Data.Data = core.Page{Perm: core.Public}
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
|
if !ctx.CheckXsrf() {
|
||||||
|
return
|
||||||
|
}
|
||||||
section := ctx.Form("section")
|
section := ctx.Form("section")
|
||||||
title := render.Title(ctx.Form("title"))
|
title := ctx.Form("title")
|
||||||
markdown := ctx.Form("markdown")
|
markdown := ctx.Form("markdown")
|
||||||
perm := core.ParsePermString(ctx.Form("perm"))
|
perm := core.ParsePermString(ctx.Form("perm"))
|
||||||
p := core.Page{
|
p := core.Page{
|
||||||
|
|
@ -160,9 +163,7 @@ func pageNewHandler(ctx *Context) {
|
||||||
Perm: perm,
|
Perm: perm,
|
||||||
}
|
}
|
||||||
ctx.Data.Data = p
|
ctx.Data.Data = p
|
||||||
if !ctx.CheckXsrf() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if section != core.WikiSection {
|
if section != core.WikiSection {
|
||||||
section = ctx.User()
|
section = ctx.User()
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +214,7 @@ func pageHandler(ctx *Context) {
|
||||||
ctx.Template("pageHandler")
|
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 {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
|
|
@ -236,10 +237,9 @@ func pageShareHandler(ctx *Context) {
|
||||||
ctx.Template("pageShareHandler")
|
ctx.Template("pageShareHandler")
|
||||||
ctx.Data = webData{}
|
ctx.Data = webData{}
|
||||||
section := ctx.Var("section")
|
section := ctx.Var("section")
|
||||||
title := render.Title(ctx.Var("title"))
|
title := ctx.Var("title")
|
||||||
user := ctx.User()
|
user := ctx.User()
|
||||||
st := render.StoreTitle(section, title)
|
page, err := ctx.Srv.DB.GetPage(section, title, user)
|
||||||
page, err := ctx.Srv.DB.GetPage(st, user)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
return
|
return
|
||||||
|
|
@ -248,18 +248,18 @@ func pageShareHandler(ctx *Context) {
|
||||||
ctx.Error("only private pages can be shared")
|
ctx.Error("only private pages can be shared")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data.Data = st
|
ctx.Data.Data = page.StoreTitle
|
||||||
ctx.Data.Title = page.Title
|
ctx.Data.Title = page.Title
|
||||||
ctx.Data.BodyTitle = page.Title
|
ctx.Data.BodyTitle = page.Title
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
case "GET":
|
case "GET":
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
duration := ctx.Form("duration")
|
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d, err := time.ParseDuration(duration)
|
|
||||||
|
d, err := time.ParseDuration(ctx.Form("duration"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
return
|
return
|
||||||
|
|
@ -295,6 +295,7 @@ func pageBlacklistHandler(ctx *Context) {
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := jwt.DecodeToken(ctx.Form("share"))
|
t, err := jwt.DecodeToken(ctx.Form("share"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
|
|
@ -327,8 +328,8 @@ func pageEditHandler(ctx *Context) {
|
||||||
ctx.Template("pageEditHandler")
|
ctx.Template("pageEditHandler")
|
||||||
ctx.Data = webData{}
|
ctx.Data = webData{}
|
||||||
section := ctx.Var("section")
|
section := ctx.Var("section")
|
||||||
title := render.Title(ctx.Var("title"))
|
title := ctx.Var("title")
|
||||||
page, err := ctx.Srv.DB.GetPage(render.StoreTitle(section, title), ctx.User())
|
page, err := ctx.Srv.DB.GetPage(section, title, ctx.User())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
return
|
return
|
||||||
|
|
@ -340,12 +341,13 @@ func pageEditHandler(ctx *Context) {
|
||||||
ctx.Data.Data = page
|
ctx.Data.Data = page
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
page.Markdown = ctx.Form("markdown")
|
|
||||||
page.Perm = core.ParsePermString(ctx.Form("perm"))
|
|
||||||
ctx.Data.Data = page
|
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
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)
|
err = ctx.Srv.DB.UpdatePage(title, section, page.Markdown, ctx.User(), page.Perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
|
|
@ -357,10 +359,9 @@ func pageEditHandler(ctx *Context) {
|
||||||
|
|
||||||
func pageDelHandler(ctx *Context) {
|
func pageDelHandler(ctx *Context) {
|
||||||
section := ctx.Var("section")
|
section := ctx.Var("section")
|
||||||
title := render.Title(ctx.Var("title"))
|
title := ctx.Var("title")
|
||||||
st := render.StoreTitle(section, title)
|
|
||||||
ctx.Template("pageDelHandler")
|
ctx.Template("pageDelHandler")
|
||||||
ctx.Data.Data = st
|
ctx.Data.Data = render.StoreTitle(section, title)
|
||||||
ctx.Data.Title = title
|
ctx.Data.Title = title
|
||||||
ctx.Data.BodyTitle = title
|
ctx.Data.BodyTitle = title
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
|
|
@ -407,6 +408,9 @@ func userNewHandler(ctx *Context) {
|
||||||
case "GET":
|
case "GET":
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
|
if !ctx.CheckXsrf() {
|
||||||
|
return
|
||||||
|
}
|
||||||
user := ctx.Form("user")
|
user := ctx.Form("user")
|
||||||
password := ctx.Form("password")
|
password := ctx.Form("password")
|
||||||
repeat := ctx.Form("repeat")
|
repeat := ctx.Form("repeat")
|
||||||
|
|
@ -415,9 +419,7 @@ func userNewHandler(ctx *Context) {
|
||||||
if admin == "0" {
|
if admin == "0" {
|
||||||
adm = true
|
adm = true
|
||||||
}
|
}
|
||||||
if !ctx.CheckXsrf() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if user == "" || password == "" || password != repeat {
|
if user == "" || password == "" || password != repeat {
|
||||||
ctx.Error("wrong inputs")
|
ctx.Error("wrong inputs")
|
||||||
return
|
return
|
||||||
|
|
@ -446,6 +448,9 @@ func userEditHandler(ctx *Context) {
|
||||||
ctx.Data.Data = u
|
ctx.Data.Data = u
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
|
if !ctx.CheckXsrf() {
|
||||||
|
return
|
||||||
|
}
|
||||||
user := ctx.Var("user")
|
user := ctx.Var("user")
|
||||||
password := ctx.Form("password")
|
password := ctx.Form("password")
|
||||||
repeat := ctx.Form("repeat")
|
repeat := ctx.Form("repeat")
|
||||||
|
|
@ -454,9 +459,7 @@ func userEditHandler(ctx *Context) {
|
||||||
if admin == "0" {
|
if admin == "0" {
|
||||||
adm = true
|
adm = true
|
||||||
}
|
}
|
||||||
if !ctx.CheckXsrf() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if user == "" || password != repeat {
|
if user == "" || password != repeat {
|
||||||
ctx.Error("wrong inputs")
|
ctx.Error("wrong inputs")
|
||||||
return
|
return
|
||||||
|
|
@ -504,6 +507,9 @@ func userDelHandler(ctx *Context) {
|
||||||
ctx.Data.Data = user
|
ctx.Data.Data = user
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
|
if !ctx.CheckXsrf() {
|
||||||
|
return
|
||||||
|
}
|
||||||
if err := ctx.Srv.DB.DeleteUser(ctx.Var("user")); err != nil {
|
if err := ctx.Srv.DB.DeleteUser(ctx.Var("user")); err != nil {
|
||||||
log.Println("delete:", err)
|
log.Println("delete:", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,29 +98,29 @@ var routes = []route{
|
||||||
[]string{"GET"},
|
[]string{"GET"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/{section}/{title}",
|
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}",
|
||||||
pageHandler,
|
pageHandler,
|
||||||
[]string{"GET"},
|
[]string{"GET"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/{section}/{title}/md",
|
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/md",
|
||||||
pageMDHandler(
|
pageMDHandler(
|
||||||
pageHandler),
|
pageHandler),
|
||||||
[]string{"GET"},
|
[]string{"GET"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/{section}/{title}/share",
|
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/share",
|
||||||
pageShareHandler,
|
pageShareHandler,
|
||||||
[]string{"GET", "POST"},
|
[]string{"GET", "POST"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/{section}/{title}/edit",
|
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/edit",
|
||||||
authHandler(
|
authHandler(
|
||||||
pageEditHandler),
|
pageEditHandler),
|
||||||
[]string{"GET", "POST"},
|
[]string{"GET", "POST"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/{section}/{title}/del",
|
"/{section:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/del",
|
||||||
authHandler(
|
authHandler(
|
||||||
pageDelHandler),
|
pageDelHandler),
|
||||||
[]string{"GET", "POST"},
|
[]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="/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>
|
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-1LNAeuiM/rtsY1jIgLovUZ7HbYnOCkj3ZyailNA3rFQ="></link>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body id="back-to-top">
|
||||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="/" class="navbar-brand">GoWiki</a>
|
<a href="/" class="navbar-brand">GoWiki</a>
|
||||||
|
|
@ -60,7 +60,7 @@ const (
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div id="back-to-top" class="proper-content">
|
<div class="proper-content">
|
||||||
{{if .Msg}}
|
{{if .Msg}}
|
||||||
<div class="alert alert-danger msg">
|
<div class="alert alert-danger msg">
|
||||||
<h4>Error!</h4>
|
<h4>Error!</h4>
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ func NewBoltStore(file string, m Marshaler) (bs *BoltStore, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type dump struct {
|
type dump struct {
|
||||||
k string `json:"k"`
|
K string `json:"k"`
|
||||||
v []byte `json:"v"`
|
V []byte `json:"v"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BoltStore) Dump(w io.Writer) (err error) {
|
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
|
var d []dump
|
||||||
err = bs.ForEach(func(k string, v []byte) error {
|
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
|
return nil
|
||||||
})
|
})
|
||||||
if err != 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) {
|
return bs.db.Update(func(tx *bolt.Tx) (err error) {
|
||||||
b := tx.Bucket([]byte(defaultBoltBucket))
|
b := tx.Bucket([]byte(defaultBoltBucket))
|
||||||
for _, v := range d {
|
for _, v := range d {
|
||||||
b.Put([]byte(v.k), v.v)
|
b.Put([]byte(v.K), v.V)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
<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>
|
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-1LNAeuiM/rtsY1jIgLovUZ7HbYnOCkj3ZyailNA3rFQ="></link>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body id="back-to-top">
|
||||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="/" class="navbar-brand">GoWiki</a>
|
<a href="/" class="navbar-brand">GoWiki</a>
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div id="back-to-top" class="proper-content">
|
<div class="proper-content">
|
||||||
{{if .Msg}}
|
{{if .Msg}}
|
||||||
<div class="alert alert-danger msg">
|
<div class="alert alert-danger msg">
|
||||||
<h4>Error!</h4>
|
<h4>Error!</h4>
|
||||||
|
|
|
||||||
38508
vendor/github.com/blevesearch/segment/segment_words.go
generated
vendored
38508
vendor/github.com/blevesearch/segment/segment_words.go
generated
vendored
File diff suppressed because it is too large
Load diff
71317
vendor/github.com/blevesearch/segment/segment_words_prod.go
generated
vendored
71317
vendor/github.com/blevesearch/segment/segment_words_prod.go
generated
vendored
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue