Files
marka/server/internal/handler/handler.go
Max Richter 4bfd2b9450
All checks were successful
Build and Push Server / build-and-push (push) Successful in 2m51s
fix: return content of written article
2025-10-31 19:18:45 +01:00

126 lines
2.9 KiB
Go

// Package handler provides the HTTP handler for the marka server
package handler
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"git.max-richter.dev/max/marka/renderer"
"git.max-richter.dev/max/marka/server/internal/adapters"
)
type Handler struct {
adapter adapters.FileAdapter
apiKey string
}
func (h *Handler) get(w http.ResponseWriter, target string) {
entry, err := h.adapter.Read(target)
if err != nil {
if errors.Is(err, adapters.ErrNotFound) {
writeError(w, http.StatusNotFound, err)
return
}
writeError(w, http.StatusInternalServerError, err)
return
}
if entry.Type == "file" {
// For non-markdown files, content is []byte, write it directly
if contentBytes, ok := entry.Content.([]byte); ok {
w.Header().Set("Content-Type", entry.MIME)
w.Write(contentBytes)
return
}
// For markdown files, content is parsed, return the whole Entry as JSON
writeJSON(w, http.StatusOK, entry)
return
}
// For directories, return the whole Entry as JSON
if entry.Type == "dir" {
writeJSON(w, http.StatusOK, entry)
return
}
writeError(w, http.StatusInternalServerError, errors.New("unknown entry type"))
}
func (h *Handler) post(w http.ResponseWriter, r *http.Request, target string) {
if h.apiKey != "" {
if r.Header.Get("Authentication") != h.apiKey {
writeError(w, http.StatusUnauthorized, errors.New("invalid api key"))
return
}
} else {
writeError(w, http.StatusUnauthorized, errors.New("invalid api key"))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
defer r.Body.Close()
contentType := r.Header.Get("Content-Type")
isJSON := strings.HasPrefix(contentType, "application/json")
var contentToWrite []byte
if strings.HasSuffix(target, ".md") && isJSON {
renderedContent, err := renderer.RenderFile(body)
if err != nil {
writeError(w, http.StatusInternalServerError, fmt.Errorf("failed to render file: %w", err))
return
}
contentToWrite = renderedContent
} else {
contentToWrite = body
}
if err := h.adapter.Write(target, contentToWrite); err != nil {
writeError(w, http.StatusInternalServerError, fmt.Errorf("failed to write file: %w", err))
return
}
var data map[string]any
if err := json.Unmarshal(body, &data); err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
writeJSON(w, http.StatusOK, data)
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
reqPath := r.URL.Path
if reqPath == "" {
reqPath = "/"
}
target := cleanURLLike(reqPath)
fmt.Printf("[serve] %s %s\n", r.Method, target)
switch r.Method {
case http.MethodGet:
h.get(w, target)
case http.MethodPost:
h.post(w, r, target)
default:
writeError(w, http.StatusMethodNotAllowed, errors.New("method not allowed"))
}
}
func NewHandler(adapter adapters.FileAdapter, apiKey string) http.Handler {
return &Handler{
adapter: adapter,
apiKey: apiKey,
}
}