|
@@ -5,8 +5,10 @@ import (
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"html/template"
|
|
|
+ "io"
|
|
|
"log"
|
|
|
"net/http"
|
|
|
+ "net/url"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
|
|
@@ -14,17 +16,18 @@ import (
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
- App = "contactsapp"
|
|
|
+ App = "Contacts.app"
|
|
|
SecretKey = "hypermedia rocks"
|
|
|
)
|
|
|
|
|
|
-func MakeTemplate(names ...string) *template.Template {
|
|
|
- names = append([]string{"layout"}, names...)
|
|
|
- paths := make([]string, len(names))
|
|
|
- for i, name := range names {
|
|
|
+func MakeTemplate(first string, others ...string) *template.Template {
|
|
|
+ all := append([]string{first}, others...)
|
|
|
+ paths := make([]string, len(all))
|
|
|
+ for i, name := range all {
|
|
|
paths[i] = fmt.Sprintf("./templates/%s.gohtml", name)
|
|
|
}
|
|
|
- tpl := template.Must(template.New("layout.html").
|
|
|
+ // All templates are named like "whatever.html" to match the Python version.
|
|
|
+ tpl := template.Must(template.New(first + ".html").
|
|
|
Funcs(sprig.FuncMap()).
|
|
|
Funcs(template.FuncMap{
|
|
|
"get_flashed_messages": func() []string {
|
|
@@ -36,321 +39,431 @@ func MakeTemplate(names ...string) *template.Template {
|
|
|
return tpl
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
-@app.route("/contacts")
|
|
|
-def contacts():
|
|
|
-*/
|
|
|
-func RouteContacts(w http.ResponseWriter, r *http.Request) {
|
|
|
- search := r.URL.Query().Get("q")
|
|
|
- page, err := strconv.Atoi(r.URL.Query().Get("page"))
|
|
|
- if err != nil || page == 0 {
|
|
|
- page = 1
|
|
|
- }
|
|
|
- var contactsSet []Contact
|
|
|
- if search != "" {
|
|
|
- contactsSet = (&Contact{}).Search(search)
|
|
|
- if r.Header.Get("HX-Trigger") == "search" {
|
|
|
- MakeTemplate("rows").Execute(w, anyMap{"contacts": contactsSet})
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- contactsSet = (&Contact{}).All(page)
|
|
|
- }
|
|
|
- MakeTemplate(
|
|
|
- "index",
|
|
|
- "archive_ui",
|
|
|
- "rows",
|
|
|
- ).Execute(w, anyMap{
|
|
|
- "contacts": contactsSet,
|
|
|
- "search": search,
|
|
|
- "page": page,
|
|
|
- "archiver": NewArchiver(),
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
var (
|
|
|
/*
|
|
|
@app.route("/")
|
|
|
def index():
|
|
|
*/
|
|
|
RouteFront = http.RedirectHandler("/contacts", http.StatusFound)
|
|
|
+)
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/archive", methods=["POST"])
|
|
|
- def start_archive():
|
|
|
- */
|
|
|
- MakeStartArchive = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- archiver := NewArchiver()
|
|
|
- archiver.Run()
|
|
|
- templates.ExecuteTemplate(w, "archive_ui.html", anyMap{"archiver": archiver})
|
|
|
+/*
|
|
|
+@app.route("/contacts")
|
|
|
+def contacts():
|
|
|
+*/
|
|
|
+func MakeRouteContacts() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "index",
|
|
|
+ "archive_ui",
|
|
|
+ "rows",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ search := r.URL.Query().Get("q")
|
|
|
+ page, err := strconv.Atoi(r.URL.Query().Get("page"))
|
|
|
+ if err != nil || page == 0 {
|
|
|
+ page = 1
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- @app.route("/contacts/archive", methods=["GET"])
|
|
|
- def archive_status():
|
|
|
- */
|
|
|
- MakeArchiveStatus = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- archiver := NewArchiver()
|
|
|
- templates.ExecuteTemplate(w, "archive_ui.html", anyMap{"archiver": archiver})
|
|
|
+ var contactsSet []Contact
|
|
|
+ if search != "" {
|
|
|
+ contactsSet = (&Contact{}).Search(search)
|
|
|
+ if r.Header.Get("HX-Trigger") == "search" {
|
|
|
+ MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "rows",
|
|
|
+ ).Execute(w, anyMap{"contacts": contactsSet})
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ contactsSet = (&Contact{}).All(page)
|
|
|
+ }
|
|
|
+ if err := tpl.Execute(w, anyMap{
|
|
|
+ "contacts": contactsSet,
|
|
|
+ "search": search,
|
|
|
+ "page": page,
|
|
|
+ "archiver": GetArchiver(),
|
|
|
+ }); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/archive/file", methods=["GET"])
|
|
|
- def archive_content():
|
|
|
- */
|
|
|
- ArchiveContent http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- archiver := NewArchiver()
|
|
|
- fileName := archiver.ArchiveFile()
|
|
|
- w.Header().Set("Content-Disposition", fmt.Sprintf(`attachement; filename="%s"`, fileName))
|
|
|
- http.ServeFile(w, r, fileName)
|
|
|
+/*
|
|
|
+@app.route("/contacts/archive", methods=["POST"])
|
|
|
+def start_archive():
|
|
|
+*/
|
|
|
+func MakeStartArchive() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "archive_ui",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ archiver := GetArchiver()
|
|
|
+ archiver.Run()
|
|
|
+ tpl.Execute(w, anyMap{"archiver": archiver})
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/archive", methods=["DELETE"])
|
|
|
- def reset_archive():
|
|
|
- */
|
|
|
- MakeResetArchive = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- archiver := NewArchiver()
|
|
|
- archiver.Reset()
|
|
|
- templates.ExecuteTemplate(w, "archive_ui.html", anyMap{"archiver": archiver})
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/contacts/archive", methods=["GET"])
|
|
|
+def archive_status():
|
|
|
+*/
|
|
|
+func MakeArchiveStatus() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "archive_ui",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ archiver := GetArchiver()
|
|
|
+ tpl.Execute(w, anyMap{"archiver": archiver})
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/count")
|
|
|
- def contacts_count():
|
|
|
- */
|
|
|
- ContactsCount http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- count := (&Contact{}).Count()
|
|
|
- _, _ = fmt.Fprintf(w, "(%d total Contacts)", count)
|
|
|
+/*
|
|
|
+@app.route("/contacts/archive/file", methods=["GET"])
|
|
|
+def archive_content():
|
|
|
+*/
|
|
|
+func ArchiveContent(w http.ResponseWriter, r *http.Request) {
|
|
|
+ archiver := GetArchiver()
|
|
|
+ w.Header().Set("Content-Disposition", `attachement; filename="archive.json"`)
|
|
|
+ http.ServeFile(w, r, archiver.ArchiveFile())
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+@app.route("/contacts/archive", methods=["DELETE"])
|
|
|
+def reset_archive():
|
|
|
+*/
|
|
|
+func MakeResetArchive() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "archive_ui",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ archiver := GetArchiver()
|
|
|
+ archiver.Reset()
|
|
|
+ tpl.Execute(w, anyMap{"archiver": archiver})
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/new", methods=['GET'])
|
|
|
- def contacts_new_get():
|
|
|
- */
|
|
|
- MakeContactsNewGet = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- templates.ExecuteTemplate(w, "new.html", anyMap{"contact": NewContact(nil)})
|
|
|
+/*
|
|
|
+@app.route("/contacts/count")
|
|
|
+def contacts_count():
|
|
|
+*/
|
|
|
+func ContactsCount(w http.ResponseWriter, r *http.Request) {
|
|
|
+ count := (&Contact{}).Count()
|
|
|
+ _, _ = fmt.Fprintf(w, "(%d total Contacts)", count)
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+@app.route("/contacts/new", methods=['GET'])
|
|
|
+def contacts_new_get():
|
|
|
+*/
|
|
|
+func MakeContactsNewGet() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "new",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ if err := tpl.Execute(w, anyMap{"contact": NewContact(nil)}); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/new", methods=['POST'])
|
|
|
- def contacts_new():
|
|
|
- */
|
|
|
- MakeContactsNew = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- c := NewContact(anyMap{
|
|
|
- "first": r.FormValue("first_name"),
|
|
|
- "last": r.FormValue("last_name"),
|
|
|
- "email": r.FormValue("phone"),
|
|
|
- "phone": r.FormValue("email"),
|
|
|
- })
|
|
|
- if c.Save() {
|
|
|
- flash("Created New Contact!")
|
|
|
- http.Redirect(w, r, "/contacts", http.StatusFound)
|
|
|
- return
|
|
|
- } else {
|
|
|
- templates.ExecuteTemplate(w, "new.html", anyMap{"contact": c})
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/contacts/new", methods=['POST'])
|
|
|
+def contacts_new():
|
|
|
+*/
|
|
|
+func MakeContactsNew() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "new",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ c := NewContact(anyMap{
|
|
|
+ "first": r.FormValue("first_name"),
|
|
|
+ "last": r.FormValue("last_name"),
|
|
|
+ "email": r.FormValue("phone"),
|
|
|
+ "phone": r.FormValue("email"),
|
|
|
+ })
|
|
|
+ if c.Save() {
|
|
|
+ flash("Created New Contact!")
|
|
|
+ http.Redirect(w, r, "/contacts", http.StatusFound)
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ tpl.Execute(w, anyMap{"contact": c})
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/<contact_id>")
|
|
|
- def contacts_view(contact_id=0):
|
|
|
- */
|
|
|
- MakeContactsView = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
- contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
- templates.ExecuteTemplate(w, "show.html", anyMap{"contact": contact})
|
|
|
+/*
|
|
|
+@app.route("/contacts/<contact_id>")
|
|
|
+def contacts_view(contact_id=0):
|
|
|
+*/
|
|
|
+func MakeContactsView() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "show",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+ contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ if err := tpl.Execute(w, anyMap{"contact": contact}); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/<contact_id>/edit", methods=["GET"])
|
|
|
- def contacts_edit_get(contact_id=0):
|
|
|
- */
|
|
|
- MakeContactsEditGet = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
- contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
- MakeTemplate(
|
|
|
- "edit",
|
|
|
- ).
|
|
|
- Execute(w, anyMap{"contact": contact})
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/contacts/<contact_id>/edit", methods=["GET"])
|
|
|
+def contacts_edit_get(contact_id=0):
|
|
|
+*/
|
|
|
+func MakeContactsEditGet() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "edit",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+ contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ tpl.Execute(w, anyMap{"contact": contact})
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/<contact_id>/edit", methods=["POST"])
|
|
|
- def contacts_edit_post(contact_id=0):
|
|
|
- */
|
|
|
- MakeContactsEditPost = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, request *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(request.PathValue("contact_id"))
|
|
|
- c := (&Contact{}).Find(uint64(contact_id))
|
|
|
- c.Update(
|
|
|
- request.FormValue("first_name"),
|
|
|
- request.FormValue("last_name"),
|
|
|
- request.FormValue("phone"),
|
|
|
- request.FormValue("email"),
|
|
|
- )
|
|
|
- if c.Save() {
|
|
|
- flash("Updated Contact!")
|
|
|
- http.Redirect(w, request, fmt.Sprintf("/contacts/%d", contact_id), http.StatusFound)
|
|
|
- return
|
|
|
- } else {
|
|
|
- templates.ExecuteTemplate(w, "edit.html", anyMap{"contact": c})
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/contacts/<contact_id>/edit", methods=["POST"])
|
|
|
+def contacts_edit_post(contact_id=0):
|
|
|
+*/
|
|
|
+func MakeContactsEditPost() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "edit",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, request *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(request.PathValue("contact_id"))
|
|
|
+ c := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ c.Update(
|
|
|
+ request.FormValue("first_name"),
|
|
|
+ request.FormValue("last_name"),
|
|
|
+ request.FormValue("phone"),
|
|
|
+ request.FormValue("email"),
|
|
|
+ )
|
|
|
+ if c.Save() {
|
|
|
+ flash("Updated Contact!")
|
|
|
+ http.Redirect(w, request, fmt.Sprintf("/contacts/%d", contact_id), http.StatusFound)
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ tpl.Execute(w, anyMap{"contact": c})
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/<contact_id>/email", methods=["GET"])
|
|
|
- def contacts_email_get(contact_id=0):
|
|
|
- */
|
|
|
- ContactsEmailGet http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
- c := (&Contact{}).Find(uint64(contact_id))
|
|
|
- c.Email = r.FormValue("email")
|
|
|
- c.validate()
|
|
|
- // FIXME find what this is really expected to do in the original Python.
|
|
|
- for _, err := range c.Errors {
|
|
|
- err := err.Error()
|
|
|
- if strings.Contains(err, "email") {
|
|
|
- fmt.Fprintln(w, err)
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/contacts/<contact_id>/email", methods=["GET"])
|
|
|
+def contacts_email_get(contact_id=0):
|
|
|
+*/
|
|
|
+func ContactsEmailGet(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+ c := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ c.Email = r.FormValue("email")
|
|
|
+ c.validate()
|
|
|
+ // FIXME find what this is really expected to do in the original Python.
|
|
|
+ for _, err := range c.Errors {
|
|
|
+ upErr := strings.ToUpper(err.Error())
|
|
|
+ if strings.Contains(upErr, "EMAIL") {
|
|
|
+ fmt.Fprintln(w, err)
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+@app.route("/contacts/<contact_id>", methods=["DELETE"])
|
|
|
+def contacts_delete(contact_id=0):
|
|
|
+*/
|
|
|
+func ContactsDelete(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+ contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ contact.Delete()
|
|
|
+ if r.Header.Get("HX-Trigger") == "delete-btn" {
|
|
|
+ flash("Deleted Contact!")
|
|
|
+ http.Redirect(w, r, "/contacts", http.StatusSeeOther)
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/contacts/<contact_id>", methods=["DELETE"])
|
|
|
- def contacts_delete(contact_id=0):
|
|
|
- */
|
|
|
- ContactsDelete http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
- contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
- contact.Delete()
|
|
|
- if r.Header.Get("HX-Trigger") == "delete-btn" {
|
|
|
- flash("Deleted Contact!")
|
|
|
- http.Redirect(w, r, "/contacts", http.StatusSeeOther)
|
|
|
+/*
|
|
|
+@app.route("/contacts/", methods=["DELETE"])
|
|
|
+def contacts_delete_all():
|
|
|
+*/
|
|
|
+func MakeContactsDeleteAll() http.HandlerFunc {
|
|
|
+ tpl := MakeTemplate(
|
|
|
+ "layout",
|
|
|
+ "index",
|
|
|
+ "archive_ui",
|
|
|
+ "rows",
|
|
|
+ )
|
|
|
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ // Per rfc7231#section-4.3.5 "A payload within a DELETE request message has no defined semantics"
|
|
|
+ //
|
|
|
+ // So Go does not parse forms on methods other than POST, PUT and PATCH,
|
|
|
+ // but this handler is called with DELETE, so we need a manual parse.
|
|
|
+ if r == nil || r.Body == nil {
|
|
|
+ http.Error(w, "invalid void request", http.StatusBadRequest)
|
|
|
return
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ body, err := io.ReadAll(r.Body)
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, fmt.Sprintf("reading request body: %v", err), http.StatusBadRequest)
|
|
|
return
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- @app.route("/contacts/", methods=["DELETE"])
|
|
|
- def contacts_delete_all():
|
|
|
- */
|
|
|
- MakeContactsDeleteAll = func(templates *template.Template) http.HandlerFunc {
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
- sContactIDs := strings.Split(r.FormValue("selected_contact_ids"), ",")
|
|
|
- for _, sContactID := range sContactIDs {
|
|
|
- if contactID, err := strconv.Atoi(sContactID); contactID > 0 && err == nil {
|
|
|
- contact := (&Contact{}).Find(uint64(contactID))
|
|
|
- contact.Delete()
|
|
|
- }
|
|
|
+ values, err := url.ParseQuery(string(body))
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, fmt.Sprintf("parsing form data: %v", err), http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ contactIDs := values["selected_contact_ids"]
|
|
|
+ for _, sContactID := range contactIDs {
|
|
|
+ if contactID, err := strconv.Atoi(sContactID); contactID > 0 && err == nil {
|
|
|
+ contact := (&Contact{}).Find(uint64(contactID))
|
|
|
+ contact.Delete()
|
|
|
}
|
|
|
- flash("Deleted contacts!")
|
|
|
- contacts_set := (&Contact{}).All(1)
|
|
|
- templates.ExecuteTemplate(w, "index.html", anyMap{"contacts": contacts_set})
|
|
|
+ }
|
|
|
+ flash("Deleted contacts!")
|
|
|
+ contacts_set := (&Contact{}).All(1)
|
|
|
+ if err := tpl.Execute(w, anyMap{"contacts": contacts_set}); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- # ===========================================================
|
|
|
- # JSON Data API
|
|
|
- # ===========================================================
|
|
|
- */
|
|
|
- /*
|
|
|
- @app.route("/api/v1/contacts", methods=["GET"])
|
|
|
- def json_contacts():
|
|
|
- */
|
|
|
- JSONContacts http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- contacts_set := (&Contact{}).All(1)
|
|
|
- enc := json.NewEncoder(w)
|
|
|
- if err := enc.Encode(anyMap{"contacts": contacts_set}); err != nil {
|
|
|
+/*
|
|
|
+ # ===========================================================
|
|
|
+ # JSON Data API
|
|
|
+ # ===========================================================
|
|
|
+*/
|
|
|
+/*
|
|
|
+ @app.route("/api/v1/contacts", methods=["GET"])
|
|
|
+ def json_contacts():
|
|
|
+*/
|
|
|
+func JSONContacts(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contacts_set := (&Contact{}).All(1)
|
|
|
+ enc := json.NewEncoder(w)
|
|
|
+ if err := enc.Encode(anyMap{"contacts": contacts_set}); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+@app.route("/api/v1/contacts", methods=["POST"])
|
|
|
+def json_contacts_new():
|
|
|
+*/
|
|
|
+func JSONContactsNew(w http.ResponseWriter, r *http.Request) {
|
|
|
+ if r == nil || r.Body == nil {
|
|
|
+ http.Error(w, "invalid void request", http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ body, err := io.ReadAll(r.Body)
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, fmt.Sprintf("error reading body: %v", err), http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ m := make(anyMap, 4)
|
|
|
+ if err := json.Unmarshal(body, &m); err != nil {
|
|
|
+ http.Error(w, fmt.Sprintf("parsing JSON request: %v", err), http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ c := NewContact(anyMap{
|
|
|
+ "first": m["first_name"],
|
|
|
+ "last": m["last_name"],
|
|
|
+ "phone": m["phone"],
|
|
|
+ "email": m["email"],
|
|
|
+ })
|
|
|
+ enc := json.NewEncoder(w)
|
|
|
+ if c.Save() {
|
|
|
+ if err := enc.Encode(c); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ w.WriteHeader(http.StatusBadRequest)
|
|
|
+ if err := enc.Encode(anyMap{"errors": c.Errors}); err != nil {
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/api/v1/contacts", methods=["POST"])
|
|
|
- def json_contacts_new():
|
|
|
- */
|
|
|
- JSONContactsNew http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- c := NewContact(anyMap{
|
|
|
- "first": r.FormValue("first_°name"),
|
|
|
- "last": r.FormValue("last_name"),
|
|
|
- "phone": r.FormValue("phone"),
|
|
|
- "email": r.FormValue("email"),
|
|
|
- })
|
|
|
- enc := json.NewEncoder(w)
|
|
|
- if c.Save() {
|
|
|
- if err := enc.Encode(c); err != nil {
|
|
|
- http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- w.WriteHeader(http.StatusBadRequest)
|
|
|
- if err := enc.Encode(anyMap{"errors": c.Errors}); err != nil {
|
|
|
- http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/api/v1/contacts/<contact_id>", methods=["GET"])
|
|
|
+def json_contacts_view(contact_id=0):
|
|
|
+*/
|
|
|
+func JSONContactsView(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+ c := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ enc := json.NewEncoder(w)
|
|
|
+ if err := enc.Encode(c); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/api/v1/contacts/<contact_id>", methods=["GET"])
|
|
|
- def json_contacts_view(contact_id=0):
|
|
|
- */
|
|
|
- JSONContactsEdit http.HandlerFunc = func(w http.ResponseWriter, request *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(request.PathValue("contact_id"))
|
|
|
- c := (&Contact{}).Find(uint64(contact_id))
|
|
|
- c.Update(
|
|
|
- request.FormValue("first_name"),
|
|
|
- request.FormValue("last_name"),
|
|
|
- request.FormValue("phone"),
|
|
|
- request.FormValue("email"),
|
|
|
- )
|
|
|
- enc := json.NewEncoder(w)
|
|
|
- if c.Save() {
|
|
|
- if err := enc.Encode(c); err != nil {
|
|
|
- http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- w.WriteHeader(http.StatusBadRequest)
|
|
|
- if err := enc.Encode(anyMap{"errors": c.Errors}); err != nil {
|
|
|
- http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
- return
|
|
|
- }
|
|
|
+/*
|
|
|
+@app.route("/api/v1/contacts/<contact_id>", methods=["PUT"])
|
|
|
+def json_contacts_edit(contact_id):
|
|
|
+*/
|
|
|
+func JSONContactsEdit(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+
|
|
|
+ if r == nil || r.Body == nil {
|
|
|
+ http.Error(w, "invalid void request", http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ body, err := io.ReadAll(r.Body)
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, fmt.Sprintf("error reading body: %v", err), http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ m := make(map[string]string, 4)
|
|
|
+ if err := json.Unmarshal(body, &m); err != nil {
|
|
|
+ http.Error(w, fmt.Sprintf("parsing JSON request: %v", err), http.StatusBadRequest)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ c := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ c.Update(
|
|
|
+ m["first_name"],
|
|
|
+ m["last_name"],
|
|
|
+ m["phone"],
|
|
|
+ m["email"],
|
|
|
+ )
|
|
|
+ enc := json.NewEncoder(w)
|
|
|
+ if c.Save() {
|
|
|
+ if err := enc.Encode(c); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ w.WriteHeader(http.StatusBadRequest)
|
|
|
+ if err := enc.Encode(anyMap{"errors": c.Errors}); err != nil {
|
|
|
+ http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
+ return
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- @app.route("/api/v1/contacts/<contact_id>", methods=["DELETE"])
|
|
|
- def json_contacts_delete(contact_id=0):
|
|
|
- */
|
|
|
- JSONContactsDelete http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
|
|
- contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
- contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
- contact.Delete()
|
|
|
- enc := json.NewEncoder(w)
|
|
|
- _ = enc.Encode(anyMap{"success": true})
|
|
|
- }
|
|
|
-)
|
|
|
+/*
|
|
|
+@app.route("/api/v1/contacts/<contact_id>", methods=["DELETE"])
|
|
|
+def json_contacts_delete(contact_id=0):
|
|
|
+*/
|
|
|
+func JSONContactsDelete(w http.ResponseWriter, r *http.Request) {
|
|
|
+ contact_id, _ := strconv.Atoi(r.PathValue("contact_id"))
|
|
|
+ contact := (&Contact{}).Find(uint64(contact_id))
|
|
|
+ contact.Delete()
|
|
|
+ enc := json.NewEncoder(w)
|
|
|
+ _ = enc.Encode(anyMap{"success": true})
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
*
|
|
@@ -361,26 +474,28 @@ func flash(message string) {
|
|
|
}
|
|
|
|
|
|
func setupRoutes(mux *http.ServeMux, templates *template.Template) {
|
|
|
+ // OK
|
|
|
mux.Handle("/", RouteFront)
|
|
|
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
|
|
|
- mux.HandleFunc("/contacts", RouteContacts)
|
|
|
- mux.Handle("POST /contacts/archive", MakeStartArchive(templates))
|
|
|
- mux.Handle("GET /contacts/archive", MakeArchiveStatus(templates))
|
|
|
- mux.Handle("GET /contacts/archive/file", ArchiveContent)
|
|
|
- mux.Handle("DELETE /contacts/archive", MakeResetArchive(templates))
|
|
|
- mux.Handle("GET /contacts/count", ContactsCount)
|
|
|
- mux.Handle("GET /contacts/new", MakeContactsNewGet(templates))
|
|
|
- mux.Handle("POST /contacts/new", MakeContactsNew(templates))
|
|
|
- mux.Handle("GET /contacts/{contact_id}", MakeContactsView(templates))
|
|
|
- mux.Handle("GET /contacts/{contact_id}/edit", MakeContactsEditGet(templates))
|
|
|
- mux.Handle("POST /contacts/{contact_id}/edit", MakeContactsEditPost(templates))
|
|
|
- mux.Handle("GET /contacts/{contact_id}/email", ContactsEmailGet)
|
|
|
- mux.Handle("DELETE /contacts/{contact_id}", ContactsDelete)
|
|
|
- mux.Handle("DELETE /contacts/", MakeContactsDeleteAll(templates))
|
|
|
- mux.Handle("GET /api/v1/contacts", JSONContacts)
|
|
|
- mux.Handle("POST /api/v1/contacts", JSONContactsNew)
|
|
|
- mux.Handle("GET /api/v1/contacts/{contact_id}", JSONContactsEdit)
|
|
|
- mux.Handle("DELETE /api/v1/contacts/{contact_id}", JSONContactsDelete)
|
|
|
+ mux.HandleFunc("/contacts", MakeRouteContacts())
|
|
|
+ mux.Handle("POST /contacts/archive", MakeStartArchive())
|
|
|
+ mux.Handle("GET /contacts/archive", MakeArchiveStatus())
|
|
|
+ mux.HandleFunc("GET /contacts/archive/file", ArchiveContent)
|
|
|
+ mux.Handle("DELETE /contacts/archive", MakeResetArchive())
|
|
|
+ mux.HandleFunc("GET /contacts/count", ContactsCount)
|
|
|
+ mux.Handle("GET /contacts/new", MakeContactsNewGet())
|
|
|
+ mux.Handle("POST /contacts/new", MakeContactsNew())
|
|
|
+ mux.Handle("GET /contacts/{contact_id}", MakeContactsView())
|
|
|
+ mux.Handle("GET /contacts/{contact_id}/edit", MakeContactsEditGet())
|
|
|
+ mux.Handle("POST /contacts/{contact_id}/edit", MakeContactsEditPost())
|
|
|
+ mux.HandleFunc("GET /contacts/{contact_id}/email", ContactsEmailGet)
|
|
|
+ mux.HandleFunc("DELETE /contacts/{contact_id}", ContactsDelete)
|
|
|
+ mux.Handle("DELETE /contacts/", MakeContactsDeleteAll())
|
|
|
+ mux.HandleFunc("GET /api/v1/contacts", JSONContacts)
|
|
|
+ mux.HandleFunc("POST /api/v1/contacts", JSONContactsNew)
|
|
|
+ mux.HandleFunc("GET /api/v1/contacts/{contact_id}", JSONContactsView)
|
|
|
+ mux.HandleFunc("PUT /api/v1/contacts/{contact_id}", JSONContactsEdit)
|
|
|
+ mux.HandleFunc("DELETE /api/v1/contacts/{contact_id}", JSONContactsDelete)
|
|
|
}
|
|
|
|
|
|
func main() {
|