You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.7 KiB
81 lines
2.7 KiB
package router
|
|
|
|
import (
|
|
"database/sql"
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"person-home/internal/auth"
|
|
"person-home/internal/handlers"
|
|
)
|
|
|
|
func New(db *sql.DB, jwtSecret []byte, uploadDir string, embeddedFrontend http.FileSystem) http.Handler {
|
|
mux := http.NewServeMux()
|
|
|
|
// Public handlers
|
|
projectH := &handlers.ProjectHandler{DB: db}
|
|
mux.HandleFunc("GET /api/projects", projectH.List)
|
|
mux.HandleFunc("GET /api/projects/{id}", projectH.Get)
|
|
mux.HandleFunc("GET /api/tags", projectH.Tags)
|
|
|
|
// Settings (public)
|
|
settingsH := &handlers.SettingsHandler{DB: db}
|
|
mux.HandleFunc("GET /api/settings", settingsH.Get)
|
|
|
|
// Auth handler
|
|
authH := &handlers.AuthHandler{DB: db, JWTSecret: jwtSecret}
|
|
mux.HandleFunc("POST /api/auth/login", authH.Login)
|
|
|
|
// Admin handlers (with auth middleware)
|
|
adminH := &handlers.AdminHandler{DB: db, UploadDir: uploadDir}
|
|
adminMux := http.NewServeMux()
|
|
adminMux.HandleFunc("GET /api/admin/projects", adminH.List)
|
|
adminMux.HandleFunc("POST /api/admin/projects", adminH.Create)
|
|
adminMux.HandleFunc("PUT /api/admin/projects/{id}", adminH.Update)
|
|
adminMux.HandleFunc("DELETE /api/admin/projects/{id}", adminH.Delete)
|
|
adminMux.HandleFunc("POST /api/admin/upload", adminH.Upload)
|
|
adminMux.HandleFunc("GET /api/admin/export", adminH.Export)
|
|
adminMux.HandleFunc("PUT /api/admin/settings", settingsH.Update)
|
|
mux.Handle("/api/admin/", auth.AdminOnly(jwtSecret)(adminMux))
|
|
|
|
// Uploaded images
|
|
fs := http.FileServer(http.Dir(uploadDir))
|
|
mux.Handle("GET /uploads/", http.StripPrefix("/uploads/", fs))
|
|
|
|
// SPA fallback: serve embedded frontend or dev proxy
|
|
if embeddedFrontend != nil {
|
|
mux.Handle("/", http.FileServer(embeddedFrontend))
|
|
}
|
|
|
|
return slogMiddleware(corsMiddleware(mux))
|
|
}
|
|
|
|
func slogMiddleware(next http.Handler) http.Handler {
|
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
start := time.Now()
|
|
next.ServeHTTP(w, r)
|
|
logger.Info("request", "method", r.Method, "path", r.URL.Path, "duration", time.Since(start))
|
|
})
|
|
}
|
|
|
|
func corsMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
origin := os.Getenv("CORS_ORIGIN")
|
|
if origin == "" {
|
|
origin = "http://localhost:5173"
|
|
}
|
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
w.Header().Set("Access-Control-Max-Age", "86400")
|
|
|
|
if r.Method == http.MethodOptions {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|