feat: Archivum skeleton — Go/GraphQL backend + Vue 3 PWA frontend
Full project scaffold: multi-stage Dockerfile (ARM64/AMD64), AsciiDoc↔TipTap bridge, Setup Wizard, CodeMirror source editor, Git-backed storage layer, LDAP+JWT auth skeleton, Tailwind mobile-first layout, and VS Code build/push tasks targeting registry at 192.168.0.19:5000. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
70
backend/internal/storage/storage.go
Normal file
70
backend/internal/storage/storage.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Store manages AsciiDoc files on disk.
|
||||
type Store struct {
|
||||
root string
|
||||
}
|
||||
|
||||
func New(root string) (*Store, error) {
|
||||
if err := os.MkdirAll(root, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Store{root: root}, nil
|
||||
}
|
||||
|
||||
// Read returns the content of a document by its slug path (e.g. "guides/install").
|
||||
func (s *Store) Read(slug string) (string, error) {
|
||||
data, err := os.ReadFile(s.filePath(slug))
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return "", ErrNotFound
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// Write persists content to disk, creating parent directories as needed.
|
||||
func (s *Store) Write(slug, content string) error {
|
||||
path := s.filePath(slug)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, []byte(content), 0644)
|
||||
}
|
||||
|
||||
// Delete removes a document from disk.
|
||||
func (s *Store) Delete(slug string) error {
|
||||
return os.Remove(s.filePath(slug))
|
||||
}
|
||||
|
||||
// List returns all document slugs under an optional prefix.
|
||||
func (s *Store) List(prefix string) ([]string, error) {
|
||||
base := filepath.Join(s.root, filepath.FromSlash(prefix))
|
||||
var slugs []string
|
||||
err := filepath.WalkDir(base, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() && strings.HasSuffix(path, ".adoc") {
|
||||
rel, _ := filepath.Rel(s.root, path)
|
||||
slug := strings.TrimSuffix(filepath.ToSlash(rel), ".adoc")
|
||||
slugs = append(slugs, slug)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return slugs, err
|
||||
}
|
||||
|
||||
func (s *Store) filePath(slug string) string {
|
||||
return filepath.Join(s.root, filepath.FromSlash(slug)+".adoc")
|
||||
}
|
||||
|
||||
var ErrNotFound = errors.New("document not found")
|
||||
Reference in New Issue
Block a user