Split into packages only manually tested
parent
0d497f4fa8
commit
60dc6bc876
29
TODO
29
TODO
|
|
@ -8,3 +8,32 @@ search
|
||||||
move auth as flag in router
|
move auth as flag in router
|
||||||
. and ../** as roots cause bugs in listing and loading and linking
|
. and ../** as roots cause bugs in listing and loading and linking
|
||||||
`create` at root is a 400, base= in URL (when `create` input is empty)
|
`create` at root is a 400, base= in URL (when `create` input is empty)
|
||||||
|
|
||||||
|
FTS
|
||||||
|
https://stackoverflow.com/questions/26709971/could-this-be-more-efficient-in-go
|
||||||
|
|
||||||
|
main test -
|
||||||
|
- create,
|
||||||
|
- header
|
||||||
|
- text box
|
||||||
|
- submit
|
||||||
|
- submit target
|
||||||
|
- edit,
|
||||||
|
- header
|
||||||
|
- text box
|
||||||
|
- submit
|
||||||
|
- submit target
|
||||||
|
- dir,
|
||||||
|
- header
|
||||||
|
- create
|
||||||
|
- create target
|
||||||
|
- list
|
||||||
|
- note,
|
||||||
|
- header
|
||||||
|
- edit
|
||||||
|
- edit target
|
||||||
|
- content
|
||||||
|
- root-> dir,
|
||||||
|
- root->file,
|
||||||
|
- dir->dir,
|
||||||
|
- dir->file
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package filetree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
type Dirs []Path
|
type Dirs []Path
|
||||||
|
|
||||||
func newDirs() *Dirs {
|
func NewDirs() *Dirs {
|
||||||
d := Dirs([]Path{})
|
d := Dirs([]Path{})
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package filetree
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package filetree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
type Files []Path
|
type Files []Path
|
||||||
|
|
||||||
func newFiles() *Files {
|
func NewFiles() *Files {
|
||||||
d := Files([]Path{})
|
d := Files([]Path{})
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package filetree
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package filetree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package filetree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"local/notes-server/config"
|
"local/notes-server/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package filetree
|
||||||
|
|
||||||
type Paths []Path
|
type Paths []Path
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package filetree
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"local/notes-server/filetree"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Notes) Create(urlPath string) (string, error) {
|
||||||
|
p := filetree.NewPathFromURL(urlPath)
|
||||||
|
if p.IsDir() {
|
||||||
|
return "", errors.New("directory exists")
|
||||||
|
}
|
||||||
|
return path.Join("/edit/", p.BaseHREF), nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"local/notes-server/filetree"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Notes) Dir(urlPath string) (string, string, error) {
|
||||||
|
p := filetree.NewPathFromURL(urlPath)
|
||||||
|
if !p.IsDir() {
|
||||||
|
return "", "", errors.New("not a dir")
|
||||||
|
}
|
||||||
|
dirs, files := n.lsDir(p)
|
||||||
|
return dirs.List(), files.List(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Notes) lsDir(path filetree.Path) (filetree.Paths, filetree.Paths) {
|
||||||
|
dirs := filetree.NewDirs()
|
||||||
|
files := filetree.NewFiles()
|
||||||
|
|
||||||
|
found, _ := ioutil.ReadDir(path.Local)
|
||||||
|
for _, f := range found {
|
||||||
|
dirs.Push(path, f)
|
||||||
|
files.Push(path, f)
|
||||||
|
}
|
||||||
|
return filetree.Paths(*dirs), filetree.Paths(*files)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"local/notes-server/config"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDir(t *testing.T) {
|
||||||
|
n := &Notes{}
|
||||||
|
config.Root = "/"
|
||||||
|
dirs, files, err := n.Dir("/notes/usr/local")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(dirs) == 0 {
|
||||||
|
t.Fatal(len(dirs))
|
||||||
|
}
|
||||||
|
if len(files) == 0 {
|
||||||
|
t.Fatal(len(files))
|
||||||
|
}
|
||||||
|
t.Log(dirs)
|
||||||
|
t.Log(files)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotesDir(t *testing.T) {
|
||||||
|
n := &Notes{}
|
||||||
|
body, body2, err := n.Dir("/notes/usr/local")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if body == "" || body2 == "" {
|
||||||
|
t.Fatal(body, body2)
|
||||||
|
}
|
||||||
|
t.Logf("%s", body)
|
||||||
|
t.Logf("%s", body2)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"local/notes-server/filetree"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Notes) Edit(urlPath string) (string, error) {
|
||||||
|
p := filetree.NewPathFromURL(urlPath)
|
||||||
|
if p.IsDir() {
|
||||||
|
return "", errors.New("path is dir")
|
||||||
|
}
|
||||||
|
return editFile(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func editFile(p filetree.Path) string {
|
||||||
|
href := p.HREF
|
||||||
|
href = strings.TrimPrefix(href, "/")
|
||||||
|
hrefs := strings.SplitN(href, "/", 2)
|
||||||
|
href = hrefs[0]
|
||||||
|
if len(hrefs) > 1 {
|
||||||
|
href = hrefs[1]
|
||||||
|
}
|
||||||
|
b, _ := ioutil.ReadFile(p.Local)
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
<form action="/submit/%s" method="post" style="width:100%%; height: 90%%">
|
||||||
|
<table style="width:100%%; height: 90%%">
|
||||||
|
<textarea name="content" style="width:100%%; min-height:90%%">%s</textarea>
|
||||||
|
</table>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
`, href, b)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"local/notes-server/filetree"
|
||||||
|
|
||||||
|
"github.com/gomarkdown/markdown"
|
||||||
|
"github.com/gomarkdown/markdown/html"
|
||||||
|
"github.com/gomarkdown/markdown/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Notes) File(urlPath string) (string, error) {
|
||||||
|
p := filetree.NewPathFromURL(urlPath)
|
||||||
|
if p.IsDir() {
|
||||||
|
return "", errors.New("path is dir")
|
||||||
|
}
|
||||||
|
b, _ := ioutil.ReadFile(p.Local)
|
||||||
|
renderer := html.NewRenderer(html.RendererOptions{
|
||||||
|
Flags: html.CommonFlags | html.TOC,
|
||||||
|
})
|
||||||
|
parser := parser.NewWithExtensions(parser.CommonExtensions | parser.HeadingIDs | parser.AutoHeadingIDs | parser.Titleblock)
|
||||||
|
content := markdown.ToHTML(b, parser, renderer)
|
||||||
|
return string(content) + "\n", nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"local/notes-server/config"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFile(t *testing.T) {
|
||||||
|
f, err := ioutil.TempFile(os.TempDir(), "until*")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
fmt.Fprintln(f, `
|
||||||
|
# Hello
|
||||||
|
## World
|
||||||
|
* This
|
||||||
|
* is
|
||||||
|
* bullets
|
||||||
|
|
||||||
|
| My | table | goes |
|
||||||
|
|----|-------|------|
|
||||||
|
| h | e | n |
|
||||||
|
|
||||||
|
`)
|
||||||
|
f.Close()
|
||||||
|
n := &Notes{}
|
||||||
|
config.Root = "/"
|
||||||
|
s, err := n.File(path.Join("notes", f.Name()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
shouldContain := []string{
|
||||||
|
"tbody",
|
||||||
|
"h1",
|
||||||
|
"h2",
|
||||||
|
}
|
||||||
|
for _, should := range shouldContain {
|
||||||
|
if !strings.Contains(s, should) {
|
||||||
|
t.Fatalf("%s: %s", should, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("%s", s)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import "local/notes-server/config"
|
||||||
|
|
||||||
|
type Notes struct {
|
||||||
|
root string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Notes {
|
||||||
|
return &Notes{
|
||||||
|
root: config.Root,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"local/notes-server/filetree"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Notes) Submit(urlPath, content string) error {
|
||||||
|
p := filetree.NewPathFromURL(urlPath)
|
||||||
|
os.MkdirAll(path.Dir(p.Local), os.ModePerm)
|
||||||
|
return ioutil.WriteFile(p.Local, []byte(content), os.ModePerm)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html"
|
||||||
|
"local/notes-server/filetree"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Notes) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
|
content := r.FormValue("base")
|
||||||
|
content = html.UnescapeString(content)
|
||||||
|
content = strings.ReplaceAll(content, "\r", "")
|
||||||
|
urlPath := path.Join(r.URL.Path, content)
|
||||||
|
p := filetree.NewPathFromURL(urlPath)
|
||||||
|
if p.IsDir() {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url := *r.URL
|
||||||
|
url.Path = path.Join("/edit/", p.BaseHREF)
|
||||||
|
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package notes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package notes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
p := NewPathFromURL(r.URL.Path)
|
||||||
|
if p.IsDir() {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
head(w, r)
|
||||||
|
editHead(w, p)
|
||||||
|
editFile(w, p)
|
||||||
|
foot(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func editHead(w http.ResponseWriter, p Path) {
|
||||||
|
fmt.Fprintln(w, h2(p.MultiLink()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func editFile(w http.ResponseWriter, p Path) {
|
||||||
|
href := p.HREF
|
||||||
|
href = strings.TrimPrefix(href, "/")
|
||||||
|
hrefs := strings.SplitN(href, "/", 2)
|
||||||
|
href = hrefs[0]
|
||||||
|
if len(hrefs) > 1 {
|
||||||
|
href = hrefs[1]
|
||||||
|
}
|
||||||
|
b, _ := ioutil.ReadFile(p.Local)
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
<form action="/submit/%s" method="post" style="width:100%%; height: 90%%">
|
||||||
|
<table style="width:100%%; height: 90%%">
|
||||||
|
<textarea name="content" style="width:100%%; min-height:90%%">%s</textarea>
|
||||||
|
</table>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
`, href, b)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package notes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package server
|
package notes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import "local/notes-server/config"
|
||||||
|
|
||||||
|
type Notes struct {
|
||||||
|
root string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Notes {
|
||||||
|
return &Notes{
|
||||||
|
root: config.Root,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
|
||||||
|
p := NewPathFromURL(r.URL.Path)
|
||||||
|
if p.IsDir() {
|
||||||
|
head(w, r)
|
||||||
|
notesHead(w, p)
|
||||||
|
notesDir(p, w, r)
|
||||||
|
foot(w, r)
|
||||||
|
} else if p.IsFile() {
|
||||||
|
head(w, r)
|
||||||
|
notesHead(w, p)
|
||||||
|
notesFile(p, w, r)
|
||||||
|
foot(w, r)
|
||||||
|
} else {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func notesHead(w http.ResponseWriter, p Path) {
|
||||||
|
fmt.Fprintln(w, h2(p.MultiLink()))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package notes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) submit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
content := r.FormValue("content")
|
||||||
|
content = html.UnescapeString(content)
|
||||||
|
content = strings.ReplaceAll(content, "\r", "")
|
||||||
|
p := NewPathFromURL(r.URL.Path)
|
||||||
|
os.MkdirAll(path.Dir(p.Local), os.ModePerm)
|
||||||
|
if err := ioutil.WriteFile(p.Local, []byte(content), os.ModePerm); err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
} else {
|
||||||
|
url := *r.URL
|
||||||
|
url.Path = path.Join("/notes/", p.BaseHREF)
|
||||||
|
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package notes
|
||||||
|
|
@ -12,12 +12,12 @@ func (s *Server) create(w http.ResponseWriter, r *http.Request) {
|
||||||
content = html.UnescapeString(content)
|
content = html.UnescapeString(content)
|
||||||
content = strings.ReplaceAll(content, "\r", "")
|
content = strings.ReplaceAll(content, "\r", "")
|
||||||
urlPath := path.Join(r.URL.Path, content)
|
urlPath := path.Join(r.URL.Path, content)
|
||||||
p := NewPathFromURL(urlPath)
|
url := *r.URL
|
||||||
if p.IsDir() {
|
path, err := s.Notes.Create(urlPath)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
url := *r.URL
|
url.Path = path
|
||||||
url.Path = path.Join("/edit/", p.BaseHREF)
|
|
||||||
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
@ -2,42 +2,22 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"local/notes-server/filetree"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) edit(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) edit(w http.ResponseWriter, r *http.Request) {
|
||||||
p := NewPathFromURL(r.URL.Path)
|
head(w, r)
|
||||||
if p.IsDir() {
|
editHead(w, filetree.NewPathFromURL(r.URL.Path))
|
||||||
http.NotFound(w, r)
|
edit, err := s.Notes.Edit(r.URL.Path)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
head(w, r)
|
fmt.Fprintln(w, edit)
|
||||||
editHead(w, p)
|
|
||||||
editFile(w, p)
|
|
||||||
foot(w, r)
|
foot(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func editHead(w http.ResponseWriter, p Path) {
|
func editHead(w http.ResponseWriter, p filetree.Path) {
|
||||||
fmt.Fprintln(w, h2(p.MultiLink()))
|
fmt.Fprintln(w, h2(p.MultiLink()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func editFile(w http.ResponseWriter, p Path) {
|
|
||||||
href := p.HREF
|
|
||||||
href = strings.TrimPrefix(href, "/")
|
|
||||||
hrefs := strings.SplitN(href, "/", 2)
|
|
||||||
href = hrefs[0]
|
|
||||||
if len(hrefs) > 1 {
|
|
||||||
href = hrefs[1]
|
|
||||||
}
|
|
||||||
b, _ := ioutil.ReadFile(p.Local)
|
|
||||||
fmt.Fprintf(w, `
|
|
||||||
<form action="/submit/%s" method="post" style="width:100%%; height: 90%%">
|
|
||||||
<table style="width:100%%; height: 90%%">
|
|
||||||
<textarea name="content" style="width:100%%; min-height:90%%">%s</textarea>
|
|
||||||
</table>
|
|
||||||
<button type="submit">Submit</button>
|
|
||||||
</form>
|
|
||||||
`, href, b)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"local/notes-server/config"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func head(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte(config.Head + "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func foot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte(config.Foot + "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func block(w http.ResponseWriter, content string) {
|
||||||
|
fmt.Fprintf(w, "\n<div>\n%s\n</div>\n", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func h1(content string) string {
|
||||||
|
return h("1", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func h2(content string) string {
|
||||||
|
return h("2", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func h3(content string) string {
|
||||||
|
return h("3", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func h4(content string) string {
|
||||||
|
return h("4", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func h5(content string) string {
|
||||||
|
return h("5", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func h(level, content string) string {
|
||||||
|
return fmt.Sprintf("\n<h%s>\n%s\n</h%s>\n", level, content, level)
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ func TestFoot(t *testing.T) {
|
||||||
|
|
||||||
func TestBlock(t *testing.T) {
|
func TestBlock(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
block("hi", w)
|
block(w, "hi")
|
||||||
s := strings.ReplaceAll(strings.TrimSpace(string(w.Body.Bytes())), "\n", ".")
|
s := strings.ReplaceAll(strings.TrimSpace(string(w.Body.Bytes())), "\n", ".")
|
||||||
if ok, err := regexp.MatchString("<div>.*hi.*<.div>", s); err != nil {
|
if ok, err := regexp.MatchString("<div>.*hi.*<.div>", s); err != nil {
|
||||||
t.Fatal(err, s)
|
t.Fatal(err, s)
|
||||||
|
|
@ -2,26 +2,61 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"local/notes-server/filetree"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
|
||||||
p := NewPathFromURL(r.URL.Path)
|
p := filetree.NewPathFromURL(r.URL.Path)
|
||||||
|
head(w, r)
|
||||||
|
notesHead(w, p)
|
||||||
|
defer foot(w, r)
|
||||||
if p.IsDir() {
|
if p.IsDir() {
|
||||||
head(w, r)
|
s.dir(w, r)
|
||||||
notesHead(w, p)
|
|
||||||
notesDir(p, w, r)
|
|
||||||
foot(w, r)
|
|
||||||
} else if p.IsFile() {
|
} else if p.IsFile() {
|
||||||
head(w, r)
|
s.file(w, r)
|
||||||
notesHead(w, p)
|
|
||||||
notesFile(p, w, r)
|
|
||||||
foot(w, r)
|
|
||||||
} else {
|
} else {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func notesHead(w http.ResponseWriter, p Path) {
|
func notesHead(w http.ResponseWriter, p filetree.Path) {
|
||||||
fmt.Fprintln(w, h2(p.MultiLink()))
|
fmt.Fprintln(w, h2(p.MultiLink()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) dir(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dirs, files, err := s.Notes.Dir(r.URL.Path)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dirHead(w, filetree.NewPathFromURL(r.URL.Path).BaseHREF)
|
||||||
|
block(w, dirs)
|
||||||
|
block(w, files)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dirHead(w http.ResponseWriter, baseHREF string) {
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
<form action=%q method="get">
|
||||||
|
<input type="text" name="base"></input>
|
||||||
|
<button type="submit">Create</button>
|
||||||
|
</form>
|
||||||
|
`, path.Join("/create/", baseHREF))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) file(w http.ResponseWriter, r *http.Request) {
|
||||||
|
file, err := s.Notes.File(r.URL.Path)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileHead(w, filetree.NewPathFromURL(r.URL.Path).BaseHREF)
|
||||||
|
fmt.Fprintln(w, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileHead(w http.ResponseWriter, baseHREF string) {
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
<a href=%q><input type="button" value="Edit"></input></a>
|
||||||
|
`, path.Join("/edit/", baseHREF))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
@ -2,10 +2,7 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"local/notes-server/config"
|
|
||||||
"local/oauth2/oauth2client"
|
|
||||||
"local/router"
|
"local/router"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,16 +37,3 @@ func (s *Server) Routes() error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) authenticate(foo http.HandlerFunc) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if config.OAuthServer != "" {
|
|
||||||
err := oauth2client.Authenticate(config.OAuthServer, "notes-server", w, r)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foo(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,35 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"local/notes-server/config"
|
"local/notes-server/config"
|
||||||
|
"local/notes-server/notes"
|
||||||
|
"local/oauth2/oauth2client"
|
||||||
"local/router"
|
"local/router"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
*router.Router
|
*router.Router
|
||||||
|
Notes *notes.Notes
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *Server {
|
func New() *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
Router: router.New(),
|
Router: router.New(),
|
||||||
|
Notes: notes.New(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func head(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) authenticate(foo http.HandlerFunc) http.HandlerFunc {
|
||||||
w.Write([]byte(config.Head + "\n"))
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
if config.OAuthServer != "" {
|
||||||
|
err := oauth2client.Authenticate(config.OAuthServer, "notes-server", w, r)
|
||||||
func foot(w http.ResponseWriter, r *http.Request) {
|
if err != nil {
|
||||||
w.Write([]byte(config.Foot + "\n"))
|
log.Println(err)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
func block(content string, w http.ResponseWriter) {
|
}
|
||||||
fmt.Fprintf(w, "\n<div>\n%s\n</div>\n", content)
|
foo(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func h1(content string) string {
|
|
||||||
return h("1", content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func h2(content string) string {
|
|
||||||
return h("2", content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func h3(content string) string {
|
|
||||||
return h("3", content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func h4(content string) string {
|
|
||||||
return h("4", content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func h5(content string) string {
|
|
||||||
return h("5", content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func h(level, content string) string {
|
|
||||||
return fmt.Sprintf("\n<h%s>\n%s\n</h%s>\n", level, content, level)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"html"
|
"html"
|
||||||
"io/ioutil"
|
"local/notes-server/filetree"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -18,14 +16,12 @@ func (s *Server) submit(w http.ResponseWriter, r *http.Request) {
|
||||||
content := r.FormValue("content")
|
content := r.FormValue("content")
|
||||||
content = html.UnescapeString(content)
|
content = html.UnescapeString(content)
|
||||||
content = strings.ReplaceAll(content, "\r", "")
|
content = strings.ReplaceAll(content, "\r", "")
|
||||||
p := NewPathFromURL(r.URL.Path)
|
err := s.Notes.Submit(r.URL.Path, content)
|
||||||
os.MkdirAll(path.Dir(p.Local), os.ModePerm)
|
if err != nil {
|
||||||
if err := ioutil.WriteFile(p.Local, []byte(content), os.ModePerm); err != nil {
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
return
|
||||||
fmt.Fprintln(w, err)
|
|
||||||
} else {
|
|
||||||
url := *r.URL
|
|
||||||
url.Path = path.Join("/notes/", p.BaseHREF)
|
|
||||||
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
|
||||||
}
|
}
|
||||||
|
url := *r.URL
|
||||||
|
url.Path = path.Join("/notes/", filetree.NewPathFromURL(r.URL.Path).BaseHREF)
|
||||||
|
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
||||||
Loading…
Reference in New Issue