Files
cv-site/internal/middleware/preferences.go
T
juanatsap 30ed21ff7a refactor: use 'c' alias for constants package
- Update all imports from 'constants' to 'c' for brevity
- Replace all 'constants.' references with 'c.'
- Fix remaining hardcoded content-type headers in httputil
- Fix remaining hardcoded User-Agent and Accept headers
- Rename CSRF receiver from 'c' to 'csrf' to avoid conflict
- Add ContentTypePlainSimple constant for Accept header matching
- Fix JSONCached to use proper integer formatting
2025-12-06 16:31:42 +00:00

170 lines
5.0 KiB
Go

package middleware
import (
"context"
"net/http"
"os"
c "github.com/juanatsap/cv-site/internal/constants"
)
// 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, c.CookieCVLength, c.CVLengthShort),
CVIcons: getPreferenceCookie(r, c.CookieCVIcons, c.CVIconsShow),
CVLanguage: getPreferenceCookie(r, c.CookieCVLanguage, c.LangEnglish),
CVTheme: getPreferenceCookie(r, c.CookieCVTheme, c.CVThemeDefault),
ColorTheme: getPreferenceCookie(r, c.CookieColorTheme, c.ColorThemeLight),
}
// Migrate old preference values (one-time auto-migration)
if prefs.CVLength == "extended" {
prefs.CVLength = c.CVLengthLong
}
switch prefs.CVIcons {
case "true":
prefs.CVIcons = c.CVIconsShow
case "false":
prefs.CVIcons = c.CVIconsHide
}
// 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: c.CVLengthShort,
CVIcons: c.CVIconsShow,
CVLanguage: c.LangEnglish,
CVTheme: c.CVThemeDefault,
ColorTheme: c.ColorThemeLight,
}
}
return prefs
}
// ==============================================================================
// CONTEXT HELPER FUNCTIONS
// Convenience functions for accessing specific preference values
// ==============================================================================
// GetLanguage retrieves the user's language preference
func GetLanguage(r *http.Request) string {
return GetPreferences(r).CVLanguage
}
// GetCVLength retrieves the user's CV length preference
func GetCVLength(r *http.Request) string {
return GetPreferences(r).CVLength
}
// GetCVIcons retrieves the user's icon visibility preference
func GetCVIcons(r *http.Request) string {
return GetPreferences(r).CVIcons
}
// GetCVTheme retrieves the user's CV theme preference
func GetCVTheme(r *http.Request) string {
return GetPreferences(r).CVTheme
}
// GetColorTheme retrieves the user's color theme preference
func GetColorTheme(r *http.Request) string {
return GetPreferences(r).ColorTheme
}
// IsLongCV returns true if the user prefers long CV format
func IsLongCV(r *http.Request) bool {
return GetCVLength(r) == c.CVLengthLong
}
// IsShortCV returns true if the user prefers short CV format
func IsShortCV(r *http.Request) bool {
return GetCVLength(r) == c.CVLengthShort
}
// ShowIcons returns true if icons should be visible
func ShowIcons(r *http.Request) bool {
return GetCVIcons(r) == c.CVIconsShow
}
// HideIcons returns true if icons should be hidden
func HideIcons(r *http.Request) bool {
return GetCVIcons(r) == c.CVIconsHide
}
// IsCleanTheme returns true if clean theme is selected
func IsCleanTheme(r *http.Request) bool {
return GetCVTheme(r) == c.CVThemeClean
}
// IsDefaultTheme returns true if default theme is selected
func IsDefaultTheme(r *http.Request) bool {
return GetCVTheme(r) == c.CVThemeDefault
}
// IsDarkMode returns true if dark mode is enabled
func IsDarkMode(r *http.Request) bool {
return GetColorTheme(r) == c.ColorThemeDark
}
// IsLightMode returns true if light mode is enabled
func IsLightMode(r *http.Request) bool {
return GetColorTheme(r) == c.ColorThemeLight
}
// 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: c.CookiePath,
MaxAge: c.CookieMaxAge,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Secure: isProductionMode(), // Secure in production with HTTPS
})
}
// isProductionMode checks if the application is running in production
func isProductionMode() bool {
env := os.Getenv(c.EnvVarGOEnv)
return env == c.EnvProduction || env == "prod"
}
// 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
}