From 53f2dad4a2038f7b76eced635f718619eda0a077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCller?= Date: Sat, 23 Sep 2017 23:29:06 +0200 Subject: [PATCH] form submission changed to ajax --- assets/public/note.js | 20 +++++++++++++ assets/public/style.css | 5 ++++ assets/templates/form.html | 35 +++++++++++++++++++---- assets/templates/note.html | 15 ++-------- render.go | 19 ++----------- server.go | 58 +++++++++++++++++++++++--------------- storage.go | 2 +- 7 files changed, 95 insertions(+), 59 deletions(-) create mode 100644 assets/public/note.js diff --git a/assets/public/note.js b/assets/public/note.js new file mode 100644 index 0000000..d800522 --- /dev/null +++ b/assets/public/note.js @@ -0,0 +1,20 @@ +"use strict"; + +function post(url, vals, cb) { + var data = new FormData(); + for (var key in vals) { + data.append(key, vals[key]); + } + var xhr = new XMLHttpRequest(); + xhr.open('POST', url) + xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE) return cb(xhr.status, xhr.responseText) }; + xhr.send(data); +} + +function report(id) { + var resp = prompt("Please shortly explain the problem with this note."); + if (resp) { + post('/' + id + '/report', { "report": resp }) + alert("Thank you!") + } +} diff --git a/assets/public/style.css b/assets/public/style.css index 8a7f455..7680cf0 100644 --- a/assets/public/style.css +++ b/assets/public/style.css @@ -272,3 +272,8 @@ form { li { margin: 0.3em 0; } + +#feedback { + margin-left: 1em; + color: #f66; +} diff --git a/assets/templates/form.html b/assets/templates/form.html index 69c273f..7004cc6 100644 --- a/assets/templates/form.html +++ b/assets/templates/form.html @@ -8,19 +8,23 @@ +
- +
- - + +
- + +
diff --git a/render.go b/render.go index 728d195..244c613 100644 --- a/render.go +++ b/render.go @@ -2,7 +2,6 @@ package main import ( "errors" - "fmt" "html/template" "io/ioutil" "net/http" @@ -28,24 +27,10 @@ var ( rexpNoScriptIframe = regexp.MustCompile("<.*?(iframe|script).*?>") rexpLink = regexp.MustCompile("(ht|f)tp://[^\\s]+") - errorUnathorised = errors.New("id or password is wrong") + errorUnathorised = errors.New("password is wrong") errorBadRequest = errors.New("password is empty") ) -func responsePage(code int, details ...string) *Note { - text := statuses[code] - body := text - if len(details) > 0 { - body += ": " + strings.Join(details, ";") - } - n := &Note{ - Title: text, - Text: fmt.Sprintf("# %d %s", code, body), - } - n.prepare() - return n -} - func (n *Note) prepare() { fstLine := rexpNewLine.Split(n.Text, -1)[0] maxLength := 25 @@ -69,7 +54,7 @@ func md2html(c echo.Context, name string) (*Note, int) { if err != nil { c.Logger().Errorf("couldn't open markdown page %s: %v", path, err) code := http.StatusServiceUnavailable - return responsePage(code), code + return &Note{Title: statuses[code], Text: "# " + statuses[code]}, code } c.Logger().Debugf("rendering markdown page %s", name) return &Note{Title: name, Content: mdTmplHTML(mdContent)}, http.StatusOK diff --git a/server.go b/server.go index 5ec56e7..e7d0d81 100644 --- a/server.go +++ b/server.go @@ -57,6 +57,7 @@ func main() { e.File("/favicon.ico", "assets/public/favicon.ico") e.File("/robots.txt", "assets/public/robots.txt") e.File("/style.css", "assets/public/style.css") + e.File("/note.js", "assets/public/note.js") e.File("/index.html", "assets/public/index.html") e.File("/", "assets/public/index.html") @@ -98,30 +99,46 @@ func main() { return c.Render(code, "Form", n) }) + e.POST("/:id/report", func(c echo.Context) error { + report := c.FormValue("report") + if report != "" { + id := c.Param("id") + c.Logger().Infof("note %s was reported: %s", id, report) + if err := email(id, report); err != nil { + c.Logger().Errorf("couldn't send email: %v", err) + } + } + return c.NoContent(http.StatusNoContent) + }) + e.GET("/new", func(c echo.Context) error { c.Logger().Debug("/new requested") return c.Render(http.StatusOK, "Form", nil) }) - e.POST("/note", func(c echo.Context) error { - c.Logger().Debug("POST /note requested") + type postResp struct { + Success bool + Payload string + } + + e.POST("/", func(c echo.Context) error { + c.Logger().Debug("POST /") if !skipCaptcha && !checkRecaptcha(c, c.FormValue("g-recaptcha-response")) { code := http.StatusForbidden - return c.Render(code, "Note", responsePage(code)) + return c.JSON(code, postResp{false, statuses[code]}) } if c.FormValue("tos") != "on" { code := http.StatusPreconditionFailed - c.Logger().Errorf("POST /note error: %d", code) - return c.Render(code, "Note", responsePage(code)) + c.Logger().Errorf("POST / error: %d", code) + return c.JSON(code, postResp{false, statuses[code]}) } id := c.FormValue("id") text := c.FormValue("text") l := len(text) if (id == "" || id != "" && l != 0) && (10 > l || l > 50000) { code := http.StatusBadRequest - c.Logger().Errorf("POST /note error: %d", code) - return c.Render(code, "Note", - responsePage(code, "note length not accepted")) + c.Logger().Errorf("POST / error: %d", code) + return c.JSON(code, postResp{false, statuses[code] + ": note length not accepted"}) } n := &Note{ ID: id, @@ -137,23 +154,18 @@ func main() { } else if err == errorBadRequest { code = http.StatusBadRequest } - c.Logger().Errorf("POST /note error: %d", code) - return c.Render(code, "Note", responsePage(code, err.Error())) + c.Logger().Errorf("POST / error: %d", code) + return c.JSON(code, postResp{false, statuses[code] + ": " + err.Error()}) } - c.Logger().Infof("note %s saved", n.ID) - return c.Redirect(http.StatusMovedPermanently, "/"+n.ID) - }) - - e.POST("/:id/report", func(c echo.Context) error { - report := c.FormValue("report") - if report != "" { - id := c.Param("id") - if err := email(id, report); err != nil { - c.Logger().Errorf("couldn't send email: %v", err) - } - c.Logger().Debugf("note %s was reported", id) + if id == "" { + c.Logger().Infof("note %s created", n.ID) + return c.JSON(http.StatusCreated, postResp{true, n.ID}) + } else if text == "" { + c.Logger().Infof("note %s deleted", n.ID) + return c.JSON(http.StatusOK, postResp{true, n.ID}) } - return c.NoContent(http.StatusNoContent) + c.Logger().Infof("note %s updated", n.ID) + return c.JSON(http.StatusOK, postResp{true, n.ID}) }) s := &http.Server{ diff --git a/storage.go b/storage.go index ae6a062..3b16eea 100644 --- a/storage.go +++ b/storage.go @@ -125,7 +125,7 @@ func load(c echo.Context, db *sql.DB) (*Note, int) { var views int if err := row.Scan(&id, &text, &published, &editedVal, &password, &views); err != nil { code := http.StatusNotFound - return responsePage(code), code + return &Note{Title: statuses[code], Text: "# " + statuses[code]}, code } n := &Note{ ID: id,