From de66fb0b7788eab05a69c6dd988bb21d3bd23b22 Mon Sep 17 00:00:00 2001 From: Maximilian Friedersdorff Date: Fri, 8 Aug 2025 21:10:10 +0100 Subject: [PATCH] Store and save metadata in frontmatter --- internal/notes/notes.go | 69 +++++++++++++++++++++++++++++++++-- internal/notes/views/views.go | 19 ++++++++-- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/internal/notes/notes.go b/internal/notes/notes.go index 99d5d40..e8c9564 100644 --- a/internal/notes/notes.go +++ b/internal/notes/notes.go @@ -3,6 +3,7 @@ package notes import ( + "bufio" "bytes" "encoding/base64" "errors" @@ -23,6 +24,7 @@ import ( "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" + "gopkg.in/yaml.v2" ) // Note is the central data structure. It can be Saved, Rendered and Loaded @@ -94,14 +96,48 @@ func (ns *NoteStore) Get(owner string) []*Note { return ns.notes[owner] } +func (ns *NoteStore) GetOne(owner string, encodedTitle string) (*Note, bool) { + notes := ns.Get(owner) + + for _, note := range notes { + if note.EncodedTitle() == encodedTitle { + log.Printf("Found single note during GetOne %+v", note) + return note, true + } + } + return nil, false +} + +func (ns *NoteStore) Add(note *Note) { + ns.notes[note.Owner] = append(ns.notes[note.Owner], note) +} + func fmtPath(path string) string { return fmt.Sprintf("%s.%s", path, conf.Conf.Extension) } +func (n *Note) marshalFrontmatter() ([]byte, error) { + frontmatter := make(map[string]interface{}) + frontmatter["owner"] = n.Owner + frontmatter["viewers"] = n.Viewers + + marshaled, err := yaml.Marshal(&frontmatter) + return marshaled, err +} + // Save a note to a path derived from the title func (n *Note) Save() error { + frontmatter, err := n.marshalFrontmatter() + if err != nil { + return err + } + filename := filepath.Join(conf.Conf.NotesDir, fmtPath(n.EncodedTitle())) - return os.WriteFile(filename, n.Body, 0600) + return os.WriteFile( + filename, + []byte(fmt.Sprintf("---\n%s---\n%s", frontmatter, n.Body)), + 0600, + ) } // Render the markdown content of the note to HTML @@ -119,15 +155,42 @@ func (n *Note) Render() { // LoadNote from the disk. The path is derived from the title func LoadNote(encodedTitle string) (*Note, error) { filename := filepath.Join(conf.Conf.NotesDir, fmtPath(encodedTitle)) - body, err := os.ReadFile(filename) + f, err := os.Open(filename) if err != nil { return nil, err } + defer f.Close() + + bodyScanner := bufio.NewScanner(f) + body := make([]byte, 0, 10) + fullBody := make([]byte, 0, 10) + + inFrontmatter := false + for bodyScanner.Scan() { + fullBody = append(fullBody, bodyScanner.Bytes()...) + fullBody = append(fullBody, '\n') + + text := bodyScanner.Text() + if text == "---" { + if !inFrontmatter { + inFrontmatter = true + } else { + inFrontmatter = false + break + } + } + } + + for bodyScanner.Scan() { + body = append(body, bodyScanner.Bytes()...) + body = append(body, '\n') + } + title := DecodeTitle(encodedTitle) var buf bytes.Buffer context := parser.NewContext() - if err := md.Convert([]byte(body), &buf, parser.WithContext(context)); err != nil { + if err := md.Convert([]byte(fullBody), &buf, parser.WithContext(context)); err != nil { return nil, err } metaData := meta.Get(context) diff --git a/internal/notes/views/views.go b/internal/notes/views/views.go index ba590c8..b0e6e68 100644 --- a/internal/notes/views/views.go +++ b/internal/notes/views/views.go @@ -78,12 +78,16 @@ func edit(w http.ResponseWriter, r *http.Request) { } func new(w http.ResponseWriter, r *http.Request) { + user := r.Context().Value(middleware.ContextKey("user")).(string) + title := r.FormValue("title") if len(title) == 0 { title = "" } - note := ¬es.Note{Title: title} + note := ¬es.Note{Title: title, Owner: user} + note.Save() + notes.Notes.Add(note) urlEdit := myurls.Reverse("edit", urls.Repl{"note": note.EncodedTitle()}) http.Redirect(w, r, urlEdit, http.StatusFound) @@ -105,13 +109,20 @@ func delete(w http.ResponseWriter, r *http.Request) { } func save(w http.ResponseWriter, r *http.Request) { - // user := r.Context().Value(middleware.ContextKey("user")).(string) - + user := r.Context().Value(middleware.ContextKey("user")).(string) oldTitle := r.PathValue("note") + note, ok := notes.Notes.GetOne(user, oldTitle) + + if !ok { + http.NotFound(w, r) + } + title := r.FormValue("title") body := r.FormValue("body") - note := ¬es.Note{Title: title, Body: []byte(body)} + log.Printf("About to save to note %+v", note) + note.Title = title + note.Body = []byte(body) note.Save() if oldTitle != note.EncodedTitle() {