98 lines
2.6 KiB
Go
98 lines
2.6 KiB
Go
// Package block provides functionality to load HTML blocks with associated content, JavaScript, and CSS from the filesystem.
|
|
// API Endpoint:
|
|
//
|
|
// /api/block/{blockPath}
|
|
//
|
|
// Example:
|
|
//
|
|
// /api/block/header would load the block located at {BlockDir}/header/
|
|
package block
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"git.oblat.lv/alex/triggerssmith/internal/config"
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
type Block struct {
|
|
Content string `json:"content"`
|
|
JS string `json:"js"`
|
|
CSS string `json:"css"`
|
|
}
|
|
|
|
type blockHandler struct {
|
|
cfg *config.Config
|
|
}
|
|
|
|
func Route(config *config.Config) func(chi.Router) {
|
|
h := &blockHandler{
|
|
cfg: config,
|
|
}
|
|
return func(r chi.Router) {
|
|
r.Get("/*", h.handleBlock)
|
|
}
|
|
}
|
|
|
|
func (h *blockHandler) handleBlock(w http.ResponseWriter, r *http.Request) {
|
|
if !h.cfg.Server.BlockConfig.Enabled {
|
|
http.Error(w, "Block serving is disabled", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
blockPath := r.URL.Path[len("/api/block/"):]
|
|
block, err := LoadBlock(blockPath, h.cfg)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(block.ToJSON()))
|
|
}
|
|
|
|
// LoadBlock loads a block from the filesystem given its path and configuration.
|
|
// It reads the content, JavaScript, and CSS files associated with the block.
|
|
// If err is not nil, it indicates a failure in reading the block files.
|
|
func LoadBlock(path string, cfg *config.Config) (*Block, error) {
|
|
slog.Debug("loading block", slog.String("path", path))
|
|
path = filepath.Join(cfg.Server.BlockConfig.BlockDir, path)
|
|
var block Block
|
|
var err error
|
|
contentPath := filepath.Join(path, "content.md")
|
|
jsPath := filepath.Join(path, "script.js")
|
|
cssPath := filepath.Join(path, "style.css")
|
|
if b, err := os.ReadFile(contentPath); err == nil {
|
|
block.Content = string(b)
|
|
} else {
|
|
slog.Warn("failed to read block content", slog.String("path", contentPath), slog.String("err", err.Error()))
|
|
}
|
|
|
|
if b, err := os.ReadFile(jsPath); err == nil {
|
|
block.JS = string(b)
|
|
} else {
|
|
slog.Warn("failed to read block JS", slog.String("path", contentPath), slog.String("err", err.Error()))
|
|
}
|
|
|
|
if b, err := os.ReadFile(cssPath); err == nil {
|
|
block.CSS = string(b)
|
|
} else {
|
|
slog.Warn("failed to read block CSS", slog.String("path", contentPath), slog.String("err", err.Error()))
|
|
}
|
|
|
|
return &block, err
|
|
}
|
|
|
|
func (b *Block) ToJSON() string {
|
|
jsonData, err := json.Marshal(b)
|
|
if err != nil {
|
|
slog.Error("failed to marshal block to JSON", slog.String("err", err.Error()))
|
|
return "{}"
|
|
}
|
|
return string(jsonData)
|
|
}
|