package web import ( "errors" "fmt" "net/http" "strconv" "time" "git.veillax.com/Veillax/mako/internal/store" ) func (s *Server) pages(w http.ResponseWriter, r *http.Request, p principal) { counts, tags := p.st.Summary() writeJSON(w, map[string]any{"pages": p.st.Pages(), "counts": counts, "tags": tags}) } func (s *Server) listNotes(w http.ResponseWriter, r *http.Request, p principal) { q := r.URL.Query() limit, _ := strconv.Atoi(q.Get("limit")) if limit <= 0 || limit > 200 { limit = 50 } offset, _ := strconv.Atoi(q.Get("offset")) text := q.Get("q") if len(text) > 200 { text = text[:200] } notes, total := p.st.List(store.Query{Text: text, Tag: q.Get("tag"), View: q.Get("view"), Offset: offset, Limit: limit}) writeJSON(w, map[string]any{"notes": notes, "total": total}) } func (s *Server) find(w http.ResponseWriter, r *http.Request, p principal) { q := r.URL.Query().Get("q") if len(q) > 200 { q = q[:200] } writeJSON(w, map[string]any{"hits": p.st.Find(q, 12)}) } func (s *Server) createNote(w http.ResponseWriter, r *http.Request, p principal) { var in struct{ Title, Body, Parent string } if !decode(w, r, &in) { return } n, err := p.st.Create(store.NewNote{Title: in.Title, Body: in.Body, Parent: in.Parent}) if err != nil { storeFail(w, err) return } writeJSONStatus(w, http.StatusCreated, n) } // page is a note with the pages that link to it. type page struct { store.Note Backlinks []store.Ref `json:"backlinks"` } func (s *Server) getNote(w http.ResponseWriter, r *http.Request, p principal) { n, err := p.st.Get(r.PathValue("id")) if err != nil { storeFail(w, err) return } writeJSON(w, page{n, p.st.Backlinks(n.ID)}) } func (s *Server) updateNote(w http.ResponseWriter, r *http.Request, p principal) { var in struct { Title *string `json:"title"` Body *string `json:"body"` Pinned *bool `json:"pinned"` Parent *string `json:"parent"` Base string `json:"base"` } if !decode(w, r, &in) { return } var base time.Time if in.Base != "" { t, err := time.Parse(time.RFC3339Nano, in.Base) if err != nil { fail(w, http.StatusBadRequest, "base must be the page's updated time") return } base = t } n, err := p.st.Update(r.PathValue("id"), store.Change{Title: in.Title, Body: in.Body, Pinned: in.Pinned, Parent: in.Parent}, base) if errors.Is(err, store.ErrConflict) { writeJSONStatus(w, http.StatusConflict, map[string]any{"error": "This page changed somewhere else", "note": n}) return } if err != nil { storeFail(w, err) return } writeJSON(w, page{n, p.st.Backlinks(n.ID)}) } func (s *Server) deleteNote(w http.ResponseWriter, r *http.Request, p principal) { id := r.PathValue("id") var err error if r.URL.Query().Get("purge") == "1" { err = p.st.Purge(id) } else { _, err = p.st.Trash(id) } if err != nil { storeFail(w, err) return } writeJSON(w, map[string]bool{"ok": true}) } func (s *Server) restoreNote(w http.ResponseWriter, r *http.Request, p principal) { n, err := p.st.Restore(r.PathValue("id")) if err != nil { storeFail(w, err) return } writeJSON(w, n) } func (s *Server) emptyTrash(w http.ResponseWriter, r *http.Request, p principal) { n, err := p.st.EmptyTrash() if err != nil { storeFail(w, err) return } writeJSON(w, map[string]int{"deleted": n}) } func (s *Server) daily(w http.ResponseWriter, r *http.Request, p principal) { var in struct{ Date string } if !decode(w, r, &in) { return } n, err := p.st.Daily(in.Date) if err != nil { storeFail(w, err) return } writeJSON(w, page{n, p.st.Backlinks(n.ID)}) } func (s *Server) export(w http.ResponseWriter, r *http.Request, p principal) { w.Header().Set("Content-Type", "application/zip") w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="mako-%s.zip"`, time.Now().Format("2006-01-02"))) if err := p.st.WriteZip(w); err != nil { // The download has started, so all that can be done is to cut it short. panic(http.ErrAbortHandler) } }