Pinterest-like app for saving images, videos, quotes, and embeds. Features: - Go backend with PostgreSQL, SSR templates - Console-based admin auth (login/logout via browser console) - Item types: images, videos (ffmpeg transcoding), quotes, embeds - Media stored as BLOBs in PostgreSQL - OpenGraph metadata extraction for links - Embed detection for YouTube, Vimeo, Twitter/X - Masonry grid layout, item detail pages - Tag system with filtering - Refresh metadata endpoint with change warnings - Replace media endpoint for updating item images/videos
75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"lookbook/internal/data/session"
|
|
)
|
|
|
|
// Router wraps http.ServeMux and automatically injects RequestContext into handlers.
|
|
type Router struct {
|
|
mux *http.ServeMux
|
|
rc *RequestContext
|
|
}
|
|
|
|
func NewRouter(rc *RequestContext) *Router {
|
|
return &Router{
|
|
mux: http.NewServeMux(),
|
|
rc: rc,
|
|
}
|
|
}
|
|
|
|
// Handle registers a handler that returns an error.
|
|
// The RequestContext is automatically injected and error handling is applied.
|
|
func (rt *Router) Handle(pattern string, h Handler) {
|
|
rt.mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
|
rc := &RequestContext{
|
|
DB: rt.rc.DB,
|
|
Logger: rt.rc.Logger,
|
|
TmplCache: rt.rc.TmplCache,
|
|
IsAdmin: rt.loadAuth(r),
|
|
}
|
|
|
|
handler := WithErrorHandling(rc, h)
|
|
handler(w, r)
|
|
})
|
|
}
|
|
|
|
// loadAuth checks if the request has a valid session cookie.
|
|
func (rt *Router) loadAuth(r *http.Request) bool {
|
|
cookie, err := r.Cookie("session_id")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
sess, err := session.QFindBySessionID(ctx, rt.rc.DB, cookie.Value)
|
|
if err != nil {
|
|
rt.rc.Logger.Error("failed to find session", slog.Any("err", err))
|
|
return false
|
|
}
|
|
if sess == nil {
|
|
return false
|
|
}
|
|
|
|
if time.Now().After(sess.ExpiresAt) {
|
|
rt.rc.Logger.Info("session expired", slog.String("session_id", cookie.Value))
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// HandleStd registers a standard http.Handler (for static files, etc.)
|
|
func (rt *Router) HandleStd(pattern string, h http.Handler) {
|
|
rt.mux.Handle(pattern, h)
|
|
}
|
|
|
|
func (rt *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
rt.mux.ServeHTTP(w, r)
|
|
}
|