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

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)
})
}