Impl complete testing needed

master
Bel LaPointe 2019-11-21 13:12:30 -07:00
parent 3079cd163f
commit a140d0eade
15 changed files with 111 additions and 33 deletions

13
TODO
View File

@ -27,11 +27,12 @@ x main test -
- dir->dir, - dir->dir,
- dir->file - dir->file
TOC levels x TOC levels
delete pages x delete pages
search x search
move auth as flag in router
. 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)
FTS FTS
https://stackoverflow.com/questions/26709971/could-this-be-more-efficient-in-go https://stackoverflow.com/questions/26709971/could-this-be-more-efficient-in-go
x move auth as flag in router
x . and ../** as roots cause bugs in listing and loading and linking
x `create` at root is a 400, base= in URL (when `create` input is empty)
delete top-level pages

View File

@ -71,6 +71,10 @@ func (p Path) MultiLink() string {
return full return full
} }
func (p Path) FullLI() string {
return fmt.Sprintf(`<li><a href=%q>%s</a></li>`, p.HREF, p.HREF)
}
func (p Path) LI() string { func (p Path) LI() string {
return fmt.Sprintf(`<li><a href=%q>%s</a></li>`, p.HREF, p.Base) return fmt.Sprintf(`<li><a href=%q>%s</a></li>`, p.HREF, p.Base)
} }

View File

@ -2,11 +2,15 @@ package filetree
type Paths []Path type Paths []Path
func (p Paths) List() string { func (p Paths) List(full ...bool) string {
content := "<ul>\n" content := "<ul>\n"
for _, path := range p { for _, path := range p {
if len(full) > 0 && full[0] {
content += path.FullLI() + "\n"
} else {
content += path.LI() + "\n" content += path.LI() + "\n"
} }
}
content += "</ul>\n" content += "</ul>\n"
return content return content
} }

15
notes/delete.go Normal file
View File

@ -0,0 +1,15 @@
package notes
import (
"errors"
"local/notes-server/filetree"
"os"
)
func (n *Notes) Delete(urlPath string) error {
p := filetree.NewPathFromURL(urlPath)
if p.IsDir() {
return errors.New("path is dir")
}
return os.Remove(p.Local)
}

1
notes/delete_test.go Normal file
View File

@ -0,0 +1 @@
package notes

View File

@ -5,31 +5,32 @@ import (
"bytes" "bytes"
"local/notes-server/filetree" "local/notes-server/filetree"
"os" "os"
"path"
"path/filepath" "path/filepath"
) )
func (n *Notes) Search(phrase string) (string, error) { func (n *Notes) Search(phrase string) (string, error) {
files := filetree.NewFiles() files := filetree.NewFiles()
err := filepath.Walk(n.root, err := filepath.Walk(n.root,
func(path string, info os.FileInfo, err error) error { func(walked string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if info.IsDir() { if info.IsDir() {
return nil return nil
} }
ok, err := grepFile(path, []byte(phrase)) ok, err := grepFile(walked, []byte(phrase))
if ok { if err == nil && ok {
p := filetree.NewPathFromLocal(path) p := filetree.NewPathFromLocal(path.Dir(walked))
files.Push(p, info) files.Push(p, info)
} }
return err return err
}, },
) )
return filetree.Paths(*files).List(), err return filetree.Paths(*files).List(true), err
} }
func grepFile(file string, pat []byte) (bool, error) { func grepFile(file string, phrase []byte) (bool, error) {
f, err := os.Open(file) f, err := os.Open(file)
if err != nil { if err != nil {
return false, err return false, err
@ -37,7 +38,7 @@ func grepFile(file string, pat []byte) (bool, error) {
defer f.Close() defer f.Close()
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
for scanner.Scan() { for scanner.Scan() {
if bytes.Contains(scanner.Bytes(), pat) { if bytes.Contains(scanner.Bytes(), phrase) {
return true, scanner.Err() return true, scanner.Err()
} }
} }

View File

@ -1 +1,3 @@
asdf asdf
this contains my search string

View File

@ -1 +0,0 @@
asdf

View File

@ -1 +1,2 @@
asdf asdf
searchString

View File

@ -1,12 +0,0 @@
# A.x
| hello | world |
|-------|-------|
| cont | ent. |
## A.X
1
2
3

16
server/delete.go Executable file
View File

@ -0,0 +1,16 @@
package server
import (
"net/http"
"path"
"strings"
)
func (s *Server) delete(w http.ResponseWriter, r *http.Request) {
if err := s.Notes.Delete(r.URL.Path); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
r.URL.Path = strings.Replace(path.Dir(r.URL.Path), "delete", "notes", 1)
http.Redirect(w, r, r.URL.String(), http.StatusPermanentRedirect)
}

View File

@ -23,6 +23,12 @@ func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
func notesHead(w http.ResponseWriter, p filetree.Path) { func notesHead(w http.ResponseWriter, p filetree.Path) {
fmt.Fprintln(w, h2(p.MultiLink())) fmt.Fprintln(w, h2(p.MultiLink()))
fmt.Fprintf(w, `
<form action=%q method="post">
<input type="text" name="keywords"></input>
<button type="submit">Search</button>
</form>
`, "/search")
} }
func (s *Server) dir(w http.ResponseWriter, r *http.Request) { func (s *Server) dir(w http.ResponseWriter, r *http.Request) {
@ -59,4 +65,7 @@ func fileHead(w http.ResponseWriter, baseHREF string) {
fmt.Fprintf(w, ` fmt.Fprintf(w, `
<a href=%q><input type="button" value="Edit"></input></a> <a href=%q><input type="button" value="Edit"></input></a>
`, path.Join("/edit/", baseHREF)) `, path.Join("/edit/", baseHREF))
fmt.Fprintf(w, `
<a href=%q><input type="button" value="Delete"></input></a>
`, path.Join("/delete/", baseHREF))
} }

View File

@ -24,6 +24,10 @@ func (s *Server) Routes() error {
path: fmt.Sprintf("edit/%s%s", wildcard, wildcard), path: fmt.Sprintf("edit/%s%s", wildcard, wildcard),
handler: s.authenticate(s.edit), handler: s.authenticate(s.edit),
}, },
{
path: fmt.Sprintf("delete/%s%s", wildcard, wildcard),
handler: s.authenticate(s.delete),
},
{ {
path: fmt.Sprintf("submit/%s%s", wildcard, wildcard), path: fmt.Sprintf("submit/%s%s", wildcard, wildcard),
handler: s.authenticate(s.submit), handler: s.authenticate(s.submit),
@ -32,6 +36,10 @@ func (s *Server) Routes() error {
path: fmt.Sprintf("create/%s%s", wildcard, wildcard), path: fmt.Sprintf("create/%s%s", wildcard, wildcard),
handler: s.authenticate(s.create), handler: s.authenticate(s.create),
}, },
{
path: fmt.Sprintf("search"),
handler: s.authenticate(s.search),
},
} }
for _, endpoint := range endpoints { for _, endpoint := range endpoints {

26
server/search.go Executable file
View File

@ -0,0 +1,26 @@
package server
import (
"fmt"
"html"
"local/notes-server/filetree"
"net/http"
)
func (s *Server) search(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
keywords := r.FormValue("keywords")
keywords = html.UnescapeString(keywords)
results, err := s.Notes.Search(keywords)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
head(w, r)
fmt.Fprintln(w, h2(filetree.NewPathFromURL("/notes").MultiLink()))
fmt.Fprintln(w, h1(keywords), results)
foot(w, r)
}

View File

@ -12,6 +12,9 @@
padding: .5pt; padding: .5pt;
border-radius: 6px; border-radius: 6px;
} }
nav li li li li {
display: none;
}
img { img {
max-height: 400px; max-height: 400px;
} }