Merge pull request #14 from KristianJBorgwarth/ref/clean-up-handler

chore: clean up create note handler
This commit is contained in:
Kristian 2026-04-06 23:11:26 +02:00 committed by GitHub
commit 586c7dd9c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 91 additions and 83 deletions

View file

@ -0,0 +1,2 @@
// Package filehandling provides utilities for handling files, including reading, writing, and manipulating file contents.
package filehandling

View file

@ -1,9 +1,8 @@
package frontmatter package filehandling
import ( import (
"bytes" "bytes"
"errors" "errors"
"log/slog"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -16,16 +15,7 @@ type FrontMatter struct {
Author string `yaml:"author"` Author string `yaml:"author"`
} }
func ParseTags(file []byte) ([]string, error) { func ParseFrontMatter(file []byte) (*FrontMatter, error) {
fm, err := parseFrontMatter(file)
if err != nil {
return nil, err
}
slog.Debug("parsed front matter", "fm", fm)
return fm.Tags, nil
}
func parseFrontMatter(file []byte) (*FrontMatter, error) {
content := bytes.TrimSpace(file) content := bytes.TrimSpace(file)
if bytes.HasPrefix(content, []byte("---")) { if bytes.HasPrefix(content, []byte("---")) {
content = bytes.TrimSpace(content[3:]) content = bytes.TrimSpace(content[3:])
@ -36,7 +26,6 @@ func parseFrontMatter(file []byte) (*FrontMatter, error) {
if idx := bytes.Index(content, []byte("---")); idx != -1 { if idx := bytes.Index(content, []byte("---")); idx != -1 {
content = bytes.TrimSpace(content[:idx]) content = bytes.TrimSpace(content[:idx])
} }
slog.Debug("yaml content to parse", "content", string(content))
var fm FrontMatter var fm FrontMatter
if err := yaml.Unmarshal(content, &fm); err != nil { if err := yaml.Unmarshal(content, &fm); err != nil {

View file

@ -1,4 +1,4 @@
package frontmatter package filehandling
import ( import (
"bytes" "bytes"

View file

@ -0,0 +1,73 @@
package filehandling
import (
"os"
"strings"
"time"
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/store"
)
type Template struct {
Content []byte
Title string
Slug string
FrontMatter *FrontMatter
}
func NewTemplate(templateName string, title string) (*Template, error) {
var templatePath string
if templateName != "" {
templatePath = store.GetVaultStore().GetTemplatePath(templateName)
}
slug := Slugify(title)
content, err := renderTemplate(templatePath, title, slug)
if err != nil {
return nil, err
}
fm, err := ParseFrontMatter(content)
if err != nil {
return nil, err
}
return &Template{
Content: content,
Title: title,
Slug: slug,
FrontMatter: fm,
}, nil
}
func renderTemplate(templatePath string, title string, slug string) ([]byte, error) {
template, err := readTemplate(templatePath, title)
if err != nil {
return nil, err
}
r := strings.NewReplacer(
"{{title}}", title,
"{{date}}", time.Now().Format("2006-01-02"),
"{{slug}}", slug,
"{{file}}", slug+".md",
)
return []byte(r.Replace(string(template))), nil
}
func readTemplate(templatePath string, title string) ([]byte, error) {
if templatePath == "" {
return createDefaultTemplate(title), nil
}
template, err := os.ReadFile(templatePath)
if err != nil {
return nil, err
}
return template, nil
}
func createDefaultTemplate(title string) []byte {
return []byte("---\ntitle: " + title + "\ndate: " + time.Now().Format("2006-01-02") + "\n---\n")
}

View file

@ -1,2 +0,0 @@
// Package frontmatter contains utilities for parsing front matter from documents.
package frontmatter

View file

@ -5,9 +5,8 @@ import (
"encoding/json" "encoding/json"
"path/filepath" "path/filepath"
"github.com/KristianJBorgwarth/dendrite.daemon/core/frontmatter" filehandling "github.com/KristianJBorgwarth/dendrite.daemon/core/file_handling"
"github.com/KristianJBorgwarth/dendrite.daemon/core/models" "github.com/KristianJBorgwarth/dendrite.daemon/core/models"
"github.com/KristianJBorgwarth/dendrite.daemon/core/template"
"github.com/KristianJBorgwarth/dendrite.daemon/core/utils" "github.com/KristianJBorgwarth/dendrite.daemon/core/utils"
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories" "github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/store" "github.com/KristianJBorgwarth/dendrite.daemon/persistence/store"
@ -34,24 +33,12 @@ func (h *CreateNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (an
return nil, err return nil, err
} }
slug := frontmatter.Slugify(cmd.Title) template, err := filehandling.NewTemplate(cmd.TemplateName, cmd.Title)
var templatePath string
if cmd.TemplateName != "" {
templatePath = store.GetVaultStore().GetTemplatePath(cmd.TemplateName)
}
notePath := filepath.Join(store.GetVaultStore().Config.VaultPath(), cmd.Directory, slug+".md")
data, err := template.RenderTemplate(templatePath, cmd.Title, slug)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tags, err := frontmatter.ParseTags(data) notePath := filepath.Join(store.GetVaultStore().Config.VaultPath(), cmd.Directory, template.Slug+".md")
if err != nil {
return nil, err
}
tx, err := h.uow.Begin() tx, err := h.uow.Begin()
if err != nil { if err != nil {
@ -63,12 +50,12 @@ func (h *CreateNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (an
tagRepo := repositories.NewTagRepository(tx) tagRepo := repositories.NewTagRepository(tx)
noteRepo := repositories.NewNoteRepository(tx) noteRepo := repositories.NewNoteRepository(tx)
dbTags, err := tagRepo.GetByNames(ctx, tags) dbTags, err := tagRepo.GetByNames(ctx, template.FrontMatter.Tags)
if err != nil { if err != nil {
return nil, err return nil, err
} }
newTags := utils.Filter(tags, func(name string) bool { newTags := utils.Filter(template.FrontMatter.Tags, func(name string) bool {
for _, t := range dbTags { for _, t := range dbTags {
if t.Name() == name { if t.Name() == name {
return false return false
@ -88,7 +75,7 @@ func (h *CreateNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (an
tagModels = append(tagModels, dbTags...) tagModels = append(tagModels, dbTags...)
note := models.CreateNote(notePath, cmd.Title, slug) note := models.CreateNote(notePath, cmd.Title, template.Slug)
if err = noteRepo.Upsert(ctx, note); err != nil { if err = noteRepo.Upsert(ctx, note); err != nil {
return nil, err return nil, err
@ -98,7 +85,7 @@ func (h *CreateNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (an
return nil, err return nil, err
} }
h.uow.FileStore.Stage(notePath, data) h.uow.FileStore.Stage(notePath, template.Content)
if err = h.uow.Commit(); err != nil { if err = h.uow.Commit(); err != nil {
return nil, err return nil, err

View file

@ -1,2 +0,0 @@
// Package template provides implementations for generating notes from templates
package template

View file

@ -1,40 +0,0 @@
package template
import (
"os"
"strings"
"time"
)
func RenderTemplate(templatePath string, title string, slug string) ([]byte, error) {
template, err := readTemplate(templatePath, title)
if err != nil {
return nil, err
}
r := strings.NewReplacer(
"{{title}}", title,
"{{date}}", time.Now().Format("2006-01-02"),
"{{slug}}", slug,
"{{file}}", slug+".md",
)
return []byte(r.Replace(string(template))), nil
}
func readTemplate(templatePath string, title string) ([]byte, error) {
if templatePath == "" {
return createDefaultTemplate(title), nil
}
template, err := os.ReadFile(templatePath)
if err != nil {
return nil, err
}
return template, nil
}
func createDefaultTemplate(title string) []byte {
return []byte("---\ntitle: " + title + "\ndate: " + time.Now().Format("2006-01-02") + "\n---\n")
}

View file

@ -1,9 +1,9 @@
package frontmatter_test package filehandling
import ( import (
"testing" "testing"
"github.com/KristianJBorgwarth/dendrite.daemon/core/frontmatter" filehandling "github.com/KristianJBorgwarth/dendrite.daemon/core/file_handling"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -15,10 +15,11 @@ tags: ["test", "note"]
--- ---
This is the content of the note.` This is the content of the note.`
result, err := frontmatter.ParseTags([]byte(input)) result, err := filehandling.ParseFrontMatter([]byte(input))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, []string{"test", "note"}, result) assert.Equal(t, "My Note", result.Title)
assert.Equal(t, []string{"test", "note"}, result.Tags)
} }
func TestParseTags_MissingDelimiter_ReturnsError(t *testing.T) { func TestParseTags_MissingDelimiter_ReturnsError(t *testing.T) {
@ -26,7 +27,7 @@ func TestParseTags_MissingDelimiter_ReturnsError(t *testing.T) {
tags: ["test", "note"] tags: ["test", "note"]
This is the content of the note.` This is the content of the note.`
_, err := frontmatter.ParseTags([]byte(input)) _, err := filehandling.ParseFrontMatter([]byte(input))
assert.ErrorContains(t, err, "missing front matter delimiter") assert.ErrorContains(t, err, "missing front matter delimiter")
} }