|
|
|
@ -2,6 +2,7 @@ package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
@ -26,12 +27,19 @@ func init() {
|
|
|
|
|
log.SetFlags(log.Lshortfile)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type authorizedKey string
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
authKey = authorizedKey("authorizedKey")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
mp PagesRepository
|
|
|
|
|
|
|
|
|
|
port = flag.Int("port", 8080, "listen port")
|
|
|
|
|
baseurl = flag.String("baseurl", "", "baseurl")
|
|
|
|
|
redirectURI string = ""
|
|
|
|
|
port = flag.Int("port", 8080, "listen port")
|
|
|
|
|
baseurl = flag.String("baseurl", "", "baseurl")
|
|
|
|
|
redirectURI = ""
|
|
|
|
|
authToken = "XVlBzgbaiCMRAjWw"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Backref struct {
|
|
|
|
@ -620,6 +628,10 @@ func (h *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page := r.URL.Path[1:]
|
|
|
|
|
if page == "favicon.ico" {
|
|
|
|
|
http.Error(w, "Not Found", 404)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
page = resolvePageName(page)
|
|
|
|
|
|
|
|
|
|
mpPage := mp.Get(page)
|
|
|
|
@ -636,7 +648,7 @@ func (h *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
var rawMsg json.RawMessage
|
|
|
|
|
err = json.NewDecoder(strings.NewReader(pageText)).Decode(&rawMsg)
|
|
|
|
|
|
|
|
|
|
title := cleanTitle(page)
|
|
|
|
|
title := cleanTitle(mpPage.Title)
|
|
|
|
|
|
|
|
|
|
jsonPage := pageText != "" && err == nil
|
|
|
|
|
if jsonPage {
|
|
|
|
@ -889,7 +901,65 @@ func main() {
|
|
|
|
|
mp = NewFilePages(dataDir, searchIndex)
|
|
|
|
|
|
|
|
|
|
http.Handle("/auth/", &authHandler{})
|
|
|
|
|
http.HandleFunc("/api/document/append", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.HandleFunc("/api/block/", wrapAuth(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
defer r.Body.Close()
|
|
|
|
|
|
|
|
|
|
if !r.Context().Value(authKey).(bool) {
|
|
|
|
|
http.Error(w, "Unauthorized", 401)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r.Method != "GET" {
|
|
|
|
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
format := r.URL.Query().Get("format")
|
|
|
|
|
if format == "" {
|
|
|
|
|
format = "json"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !(format == "json" || format == "metakv") {
|
|
|
|
|
http.Error(w, "unknown format", http.StatusBadRequest)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page := r.URL.Path
|
|
|
|
|
page = strings.TrimPrefix(page, "/api/block/")
|
|
|
|
|
page = resolvePageName(page)
|
|
|
|
|
|
|
|
|
|
mpPage := mp.Get(page)
|
|
|
|
|
pageText := mpPage.Content
|
|
|
|
|
if pageText == "" {
|
|
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if format == "json" {
|
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
w.Header().Set("Cache-Control", "no-store")
|
|
|
|
|
// Shortcut for json output
|
|
|
|
|
_, err := io.WriteString(w, pageText)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), 500)
|
|
|
|
|
}
|
|
|
|
|
} else if format == "metakv" {
|
|
|
|
|
so, err := createStructuredFormat(mpPage)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), 500)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
w.Header().Set("Cache-Control", "no-store")
|
|
|
|
|
enc := json.NewEncoder(w)
|
|
|
|
|
enc.SetIndent("", " ")
|
|
|
|
|
err = enc.Encode(so)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), 500)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
http.HandleFunc("/api/block/append", wrapAuth(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
err := r.ParseForm()
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), 400)
|
|
|
|
@ -904,6 +974,7 @@ func main() {
|
|
|
|
|
page := mp.Get(id)
|
|
|
|
|
log.Println(page.Content)
|
|
|
|
|
var listItems []ListItem
|
|
|
|
|
id = page.Name // Use the name that was actually loaded
|
|
|
|
|
|
|
|
|
|
err = json.NewDecoder(strings.NewReader(page.Content)).Decode(&listItems)
|
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
@ -912,8 +983,9 @@ func main() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newId := &ID{"1", true}
|
|
|
|
|
generatedID := newId.NewID()
|
|
|
|
|
listItems = append(listItems, ListItem{
|
|
|
|
|
ID: newId.NewID(),
|
|
|
|
|
ID: generatedID,
|
|
|
|
|
Indented: 0,
|
|
|
|
|
Text: r.Form.Get("text"),
|
|
|
|
|
Fleeting: false,
|
|
|
|
@ -936,8 +1008,10 @@ func main() {
|
|
|
|
|
http.Error(w, fmt.Sprintf("while saving: %s", err.Error()), 500)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println(generatedID)
|
|
|
|
|
return
|
|
|
|
|
})
|
|
|
|
|
}))
|
|
|
|
|
http.HandleFunc("/links.json", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
http.ServeFile(w, r, filepath.Join(dataDir, LinksFile))
|
|
|
|
@ -997,6 +1071,20 @@ func main() {
|
|
|
|
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func wrapAuth(handler http.HandlerFunc) http.HandlerFunc {
|
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
auth := r.Header.Get("Authorization")
|
|
|
|
|
if auth == "" || auth == "Token "+authToken {
|
|
|
|
|
r = r.WithContext(context.WithValue(r.Context(), authKey, auth != ""))
|
|
|
|
|
// auth == "", require cookie in handler
|
|
|
|
|
handler.ServeHTTP(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
http.Error(w, "Authorization Required", 401)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func createSearchIndex(dataDir, indexName string) (bleve.Index, error) {
|
|
|
|
|
indexDir := filepath.Join(dataDir, indexName)
|
|
|
|
|
if _, err := os.Stat(indexDir); os.IsNotExist(err) {
|
|
|
|
|