package middleware import ( "context" "net/http" ) // contextKey is a private type for context keys to avoid collisions type contextKey string const ( // PreferencesKey is the context key for user preferences PreferencesKey contextKey = "preferences" ) // Preferences holds user preference values from cookies type Preferences struct { CVLength string // "short" or "long" CVIcons string // "show" or "hide" CVLanguage string // "en" or "es" CVTheme string // "default" or "clean" ColorTheme string // "light" or "dark" } // PreferencesMiddleware reads user preferences from cookies and stores them in context // This eliminates the need for handlers to manually read cookies func PreferencesMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { prefs := &Preferences{ CVLength: getPreferenceCookie(r, "cv-length", "short"), CVIcons: getPreferenceCookie(r, "cv-icons", "show"), CVLanguage: getPreferenceCookie(r, "cv-language", "en"), CVTheme: getPreferenceCookie(r, "cv-theme", "default"), ColorTheme: getPreferenceCookie(r, "color-theme", "light"), } // Migrate old preference values (one-time auto-migration) if prefs.CVLength == "extended" { prefs.CVLength = "long" } switch prefs.CVIcons { case "true": prefs.CVIcons = "show" case "false": prefs.CVIcons = "hide" } // Store preferences in context ctx := context.WithValue(r.Context(), PreferencesKey, prefs) next.ServeHTTP(w, r.WithContext(ctx)) }) } // GetPreferences retrieves preferences from request context func GetPreferences(r *http.Request) *Preferences { prefs, ok := r.Context().Value(PreferencesKey).(*Preferences) if !ok { // Return default preferences if not found return &Preferences{ CVLength: "short", CVIcons: "show", CVLanguage: "en", CVTheme: "default", ColorTheme: "light", } } return prefs } // SetPreferenceCookie sets a preference cookie (1 year expiry) func SetPreferenceCookie(w http.ResponseWriter, name string, value string) { http.SetCookie(w, &http.Cookie{ Name: name, Value: value, Path: "/", MaxAge: 365 * 24 * 60 * 60, // 1 year HttpOnly: true, SameSite: http.SameSiteStrictMode, Secure: false, // Set to true in production with HTTPS }) } // getPreferenceCookie gets a preference cookie value, returns default if not found func getPreferenceCookie(r *http.Request, name string, defaultValue string) string { cookie, err := r.Cookie(name) if err != nil { return defaultValue } return cookie.Value }