Store title in frontmatter, make fname uid only

This commit is contained in:
Maximilian Friedersdorff 2025-08-23 21:09:39 +01:00
parent de66fb0b77
commit bb775ec55f
2 changed files with 39 additions and 46 deletions

View file

@ -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)
}

View file

@ -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 = &notes.Note{Title: title}
note = &notes.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 = "<New Note>"
}
note := &notes.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})},
)
}