From bb775ec55fd191402917882beabb96921f27028e Mon Sep 17 00:00:00 2001 From: Maximilian Friedersdorff Date: Sat, 23 Aug 2025 21:09:39 +0100 Subject: [PATCH] Store title in frontmatter, make fname uid only --- internal/notes/notes.go | 53 +++++++++++++++++------------------ internal/notes/views/views.go | 32 +++++++++------------ 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/internal/notes/notes.go b/internal/notes/notes.go index e8c9564..9480f5a 100644 --- a/internal/notes/notes.go +++ b/internal/notes/notes.go @@ -5,7 +5,7 @@ package notes import ( "bufio" "bytes" - "encoding/base64" + "crypto/rand" "errors" "fmt" "html/template" @@ -35,6 +35,7 @@ type Note struct { Body []byte Owner string Viewers []string + Uid string } type NoteStore struct { @@ -71,15 +72,15 @@ func Init() error { log.Printf("Looking in %s", notesDir) for _, f := range files { if !f.IsDir() { - encodedTitle := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) - note, err := LoadNote(encodedTitle) + uid := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) + note, err := LoadNote(uid) if err != nil { return err } title := note.Title - log.Printf("Found note %s (title '%s', owner %s)", encodedTitle, title, note.Owner) + log.Printf("Found note %s (title '%s', owner %s)", uid, title, note.Owner) Notes.notes[note.Owner] = append(Notes.notes[note.Owner], note) @@ -96,11 +97,11 @@ func (ns *NoteStore) Get(owner string) []*Note { return ns.notes[owner] } -func (ns *NoteStore) GetOne(owner string, encodedTitle string) (*Note, bool) { +func (ns *NoteStore) GetOne(owner string, uid string) (*Note, bool) { notes := ns.Get(owner) for _, note := range notes { - if note.EncodedTitle() == encodedTitle { + if note.Uid == uid { log.Printf("Found single note during GetOne %+v", note) return note, true } @@ -120,11 +121,19 @@ func (n *Note) marshalFrontmatter() ([]byte, error) { frontmatter := make(map[string]interface{}) frontmatter["owner"] = n.Owner frontmatter["viewers"] = n.Viewers + frontmatter["title"] = n.Title marshaled, err := yaml.Marshal(&frontmatter) return marshaled, err } +func NewNote(title string, owner string) *Note { + note := &Note{Title: title, Owner: owner, Uid: rand.Text()} + note.Save() + Notes.Add(note) + return note +} + // Save a note to a path derived from the title func (n *Note) Save() error { frontmatter, err := n.marshalFrontmatter() @@ -132,7 +141,7 @@ func (n *Note) Save() error { return err } - filename := filepath.Join(conf.Conf.NotesDir, fmtPath(n.EncodedTitle())) + filename := filepath.Join(conf.Conf.NotesDir, fmtPath(n.Uid)) return os.WriteFile( filename, []byte(fmt.Sprintf("---\n%s---\n%s", frontmatter, n.Body)), @@ -153,8 +162,8 @@ 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)) +func LoadNote(uid string) (*Note, error) { + filename := filepath.Join(conf.Conf.NotesDir, fmtPath(uid)) f, err := os.Open(filename) if err != nil { return nil, err @@ -186,8 +195,6 @@ func LoadNote(encodedTitle string) (*Note, error) { body = append(body, '\n') } - title := DecodeTitle(encodedTitle) - var buf bytes.Buffer context := parser.NewContext() if err := md.Convert([]byte(fullBody), &buf, parser.WithContext(context)); err != nil { @@ -201,7 +208,12 @@ func LoadNote(encodedTitle string) (*Note, error) { return nil, errors.New("invalid note, missing 'owner' in frontmatter") } - note := &Note{Title: title, Body: body, Owner: owner} + title, ok := metaData["title"].(string) + if !ok { + return nil, errors.New("invalid note, missing 'title' in frontmatter") + } + + note := &Note{Title: title, Body: body, Owner: owner, Uid: uid} viewers := metaData["viewers"].([]interface{}) @@ -217,15 +229,11 @@ func LoadNote(encodedTitle string) (*Note, error) { return note, nil } -func DeleteNote(title string) error { - filename := filepath.Join(conf.Conf.NotesDir, fmtPath(title)) +func DeleteNote(uid string) error { + filename := filepath.Join(conf.Conf.NotesDir, fmtPath(uid)) return os.Remove(filename) } -func (n *Note) EncodedTitle() string { - return base64.StdEncoding.EncodeToString([]byte(n.Title)) -} - type toggleCheckboxTransformer struct{ nthBox int } func (t *toggleCheckboxTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) { @@ -288,12 +296,3 @@ func (n *Note) ToggleBox(nthBox int) { n.Body = buf.Bytes() n.Save() } - -func DecodeTitle(encodedTitle string) string { - title, err := base64.StdEncoding.DecodeString(encodedTitle) - if err != nil { - log.Printf("Couldn't decode base64 string '%s': %s", encodedTitle, err) - } - - return string(title) -} diff --git a/internal/notes/views/views.go b/internal/notes/views/views.go index b0e6e68..f7e3e3c 100644 --- a/internal/notes/views/views.go +++ b/internal/notes/views/views.go @@ -58,16 +58,16 @@ func view(w http.ResponseWriter, r *http.Request) { } func edit(w http.ResponseWriter, r *http.Request) { - // user := r.Context().Value(middleware.ContextKey("user")).(string) + user := r.Context().Value(middleware.ContextKey("user")).(string) - encodedTitle := r.PathValue("note") - note, err := notes.LoadNote(encodedTitle) + uid := r.PathValue("note") + note, err := notes.LoadNote(uid) if err != nil { - title := notes.DecodeTitle(encodedTitle) - note = ¬es.Note{Title: title} + note = ¬es.Note{Title: "", Uid: uid} + note = notes.NewNote("", user) } - urlSave := myurls.Reverse("save", urls.Repl{"note": encodedTitle}) + urlSave := myurls.Reverse("save", urls.Repl{"note": uid}) context := templ.Ctx{"note": note, "urlSave": urlSave, "text": string(note.Body)} err = templ.RenderTemplate(w, r, "edit.tmpl.html", context) if err != nil { @@ -85,11 +85,9 @@ func new(w http.ResponseWriter, r *http.Request) { title = "" } - note := ¬es.Note{Title: title, Owner: user} - note.Save() - notes.Notes.Add(note) + note := notes.NewNote(title, user) - urlEdit := myurls.Reverse("edit", urls.Repl{"note": note.EncodedTitle()}) + urlEdit := myurls.Reverse("edit", urls.Repl{"note": note.Uid}) http.Redirect(w, r, urlEdit, http.StatusFound) } @@ -110,8 +108,8 @@ func delete(w http.ResponseWriter, r *http.Request) { func save(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) - oldTitle := r.PathValue("note") - note, ok := notes.Notes.GetOne(user, oldTitle) + uid := r.PathValue("note") + note, ok := notes.Notes.GetOne(user, uid) if !ok { http.NotFound(w, r) @@ -125,11 +123,7 @@ func save(w http.ResponseWriter, r *http.Request) { note.Body = []byte(body) note.Save() - if oldTitle != note.EncodedTitle() { - notes.DeleteNote(oldTitle) - } - - http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.EncodedTitle()}), http.StatusFound) + http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.Uid}), http.StatusFound) } func togglebox(w http.ResponseWriter, r *http.Request) { @@ -150,7 +144,7 @@ func togglebox(w http.ResponseWriter, r *http.Request) { note.ToggleBox(nthBox) - http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.EncodedTitle()}), http.StatusFound) + http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.Uid}), http.StatusFound) } type titleAndURL struct { @@ -170,7 +164,7 @@ func list(w http.ResponseWriter, r *http.Request) { for _, note := range ns { titlesAndUrls = append( titlesAndUrls, - titleAndURL{Title: note.Title, URL: myurls.Reverse("view", urls.Repl{"note": note.EncodedTitle()})}, + titleAndURL{Title: note.Title, URL: myurls.Reverse("view", urls.Repl{"note": note.Uid})}, ) }