Store and save metadata in frontmatter

This commit is contained in:
Maximilian Friedersdorff 2025-08-08 21:10:10 +01:00
parent 03b6bb12ca
commit de66fb0b77
2 changed files with 81 additions and 7 deletions

View file

@ -3,6 +3,7 @@
package notes package notes
import ( import (
"bufio"
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"errors" "errors"
@ -23,6 +24,7 @@ import (
"github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text" "github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util" "github.com/yuin/goldmark/util"
"gopkg.in/yaml.v2"
) )
// Note is the central data structure. It can be Saved, Rendered and Loaded // 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] 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 { func fmtPath(path string) string {
return fmt.Sprintf("%s.%s", path, conf.Conf.Extension) 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 // Save a note to a path derived from the title
func (n *Note) Save() error { func (n *Note) Save() error {
frontmatter, err := n.marshalFrontmatter()
if err != nil {
return err
}
filename := filepath.Join(conf.Conf.NotesDir, fmtPath(n.EncodedTitle())) 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 // 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 // LoadNote from the disk. The path is derived from the title
func LoadNote(encodedTitle string) (*Note, error) { func LoadNote(encodedTitle string) (*Note, error) {
filename := filepath.Join(conf.Conf.NotesDir, fmtPath(encodedTitle)) filename := filepath.Join(conf.Conf.NotesDir, fmtPath(encodedTitle))
body, err := os.ReadFile(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return nil, err 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) title := DecodeTitle(encodedTitle)
var buf bytes.Buffer var buf bytes.Buffer
context := parser.NewContext() 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 return nil, err
} }
metaData := meta.Get(context) metaData := meta.Get(context)

View file

@ -78,12 +78,16 @@ func edit(w http.ResponseWriter, r *http.Request) {
} }
func new(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") title := r.FormValue("title")
if len(title) == 0 { if len(title) == 0 {
title = "<New Note>" title = "<New Note>"
} }
note := &notes.Note{Title: title} note := &notes.Note{Title: title, Owner: user}
note.Save()
notes.Notes.Add(note)
urlEdit := myurls.Reverse("edit", urls.Repl{"note": note.EncodedTitle()}) urlEdit := myurls.Reverse("edit", urls.Repl{"note": note.EncodedTitle()})
http.Redirect(w, r, urlEdit, http.StatusFound) 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) { 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") oldTitle := r.PathValue("note")
note, ok := notes.Notes.GetOne(user, oldTitle)
if !ok {
http.NotFound(w, r)
}
title := r.FormValue("title") title := r.FormValue("title")
body := r.FormValue("body") body := r.FormValue("body")
note := &notes.Note{Title: title, Body: []byte(body)} log.Printf("About to save to note %+v", note)
note.Title = title
note.Body = []byte(body)
note.Save() note.Save()
if oldTitle != note.EncodedTitle() { if oldTitle != note.EncodedTitle() {