feat(note/save): setup save note (#17)
* feat(file): added file type * feat(file_handler): added filehandler with placeholder func * ref(links): updated link model and table * feat(links): added link extration on file save * feat(note_repo): added get by slug query
This commit is contained in:
parent
f2fc6ee0ee
commit
c0591b6c7e
4 changed files with 119 additions and 4 deletions
82
core/file_handling/file.go
Normal file
82
core/file_handling/file.go
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package filehandling
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
Title string
|
||||||
|
Slug string
|
||||||
|
FrontMatter FrontMatter
|
||||||
|
Content []string
|
||||||
|
Links []ExtractedLink
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtractedLink struct {
|
||||||
|
Raw string
|
||||||
|
Display string
|
||||||
|
TargetSlug string
|
||||||
|
Line int
|
||||||
|
Col int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFile(path string) (*File, error) {
|
||||||
|
body, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body = bytes.TrimSpace(body)
|
||||||
|
|
||||||
|
fm, err := ParseFrontMatter(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &File{
|
||||||
|
Title: fm.Title,
|
||||||
|
Slug: strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)),
|
||||||
|
FrontMatter: *fm,
|
||||||
|
Content: strings.Split(string(body), "\n"),
|
||||||
|
Links: ExtractLinks(body),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var linkRegex = regexp.MustCompile(`\[\[([^\]|]+)(?:\|([^\]]+))?\]\]`)
|
||||||
|
|
||||||
|
func ExtractLinks(body []byte) []ExtractedLink {
|
||||||
|
var links []ExtractedLink
|
||||||
|
|
||||||
|
lineStart := 0
|
||||||
|
lineNum := 1
|
||||||
|
|
||||||
|
for i := 0; i <= len(body); i++ {
|
||||||
|
if i == len(body) || body[i] == '\n' {
|
||||||
|
line := body[lineStart:i]
|
||||||
|
matches := linkRegex.FindAllSubmatchIndex(line, -1)
|
||||||
|
for _, m := range matches {
|
||||||
|
raw := string(line[m[0]:m[1]])
|
||||||
|
slug := string(line[m[2]:m[3]])
|
||||||
|
var display string
|
||||||
|
if m[4] != -1 {
|
||||||
|
display = string(line[m[4]:m[5]])
|
||||||
|
}
|
||||||
|
links = append(links, ExtractedLink{
|
||||||
|
TargetSlug: slug,
|
||||||
|
Raw: raw,
|
||||||
|
Display: display,
|
||||||
|
Line: lineNum,
|
||||||
|
Col: m[0] + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
lineStart = i + 1
|
||||||
|
lineNum++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return links
|
||||||
|
}
|
||||||
|
|
@ -4,14 +4,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
filehandling "github.com/KristianJBorgwarth/dendrite.daemon/core/file_handling"
|
||||||
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
|
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
|
||||||
)
|
)
|
||||||
|
|
||||||
type saveNoteCommand struct {
|
type saveNoteCommand struct {
|
||||||
Title string `json:"title"`
|
Path string `json:"path"`
|
||||||
Content string `json:"content"`
|
|
||||||
Directory string `json:"directory"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SaveNoteHandler struct {
|
type SaveNoteHandler struct {
|
||||||
|
|
@ -29,5 +27,27 @@ func (h *SaveNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (any,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file, err := filehandling.ReadFile(cmd.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := h.uow.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer h.uow.Rollback()
|
||||||
|
tagRepo := repositories.NewTagRepository(tx)
|
||||||
|
noteRepo := repositories.NewNoteRepository(tx)
|
||||||
|
|
||||||
|
|
||||||
|
note, err := noteRepo.GetBySlug(ctx, file.Slug)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
dendrite
BIN
dendrite
Binary file not shown.
|
|
@ -30,3 +30,16 @@ func (r *noteRepository) Insert(ctx context.Context, note *models.Note) error {
|
||||||
_, err := r.Transaction.ExecContext(ctx, query, note.ID(), note.Title(), note.Path(), note.Slug())
|
_, err := r.Transaction.ExecContext(ctx, query, note.ID(), note.Title(), note.Path(), note.Slug())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *noteRepository) GetBySlug(ctx context.Context, slug string) (*models.Note, error) {
|
||||||
|
query := `SELECT id, title, path, slug, created_at, updated_at FROM notes WHERE slug = ?`
|
||||||
|
row := r.Transaction.QueryRowContext(ctx, query, slug)
|
||||||
|
|
||||||
|
var id, title, path, createdAt, updatedAt string
|
||||||
|
err := row.Scan(&id, &title, &path, &slug, &createdAt, &updatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return models.NewNote(id, path, title, slug, createdAt, updatedAt), nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue