package handler import ( "database/sql" "net/http" "dealroom/internal/model" ) type Handler struct { db *sql.DB config *Config } type Config struct { BaseURL string SessionKey string K25APIURL string K25APIKey string SMTPHost string SMTPUser string SMTPPass string } func New(db *sql.DB, _ interface{}, config *Config) *Handler { return &Handler{ db: db, config: config, } } func (h *Handler) RegisterRoutes(mux *http.ServeMux) { // Static files mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) // Auth mux.HandleFunc("/login", h.handleLoginPage) mux.HandleFunc("/auth/login", h.handleLogin) mux.HandleFunc("/auth/demo", h.handleDemoLogin) mux.HandleFunc("/auth/logout", h.handleLogout) // Pages (auth required) mux.HandleFunc("/", h.requireAuth(h.handleDashboard)) mux.HandleFunc("/deals", h.requireAuth(h.handleDealRooms)) mux.HandleFunc("/deals/", h.requireAuth(h.handleDealRoom)) mux.HandleFunc("/requests", h.requireAuth(h.handleRequestList)) mux.HandleFunc("/contacts", h.requireAuth(h.handleContacts)) mux.HandleFunc("/audit", h.requireAuth(h.handleAuditLog)) mux.HandleFunc("/analytics", h.requireAuth(h.handleAnalytics)) // HTMX partials mux.HandleFunc("/htmx/request-comment", h.requireAuth(h.handleUpdateComment)) } // Middleware func (h *Handler) requireAuth(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("session") if err != nil { http.Redirect(w, r, "/login", http.StatusSeeOther) return } var profile model.Profile err = h.db.QueryRow(` SELECT p.id, p.email, p.full_name, p.avatar_url, p.organization_id, p.role FROM sessions s JOIN profiles p ON s.user_id = p.id WHERE s.token = ? AND s.expires_at > datetime('now') `, cookie.Value).Scan(&profile.ID, &profile.Email, &profile.FullName, &profile.AvatarURL, &profile.OrganizationID, &profile.Role) if err != nil { http.SetCookie(w, &http.Cookie{Name: "session", Value: "", MaxAge: -1, Path: "/"}) http.Redirect(w, r, "/login", http.StatusSeeOther) return } ctx := setProfile(r.Context(), &profile) next.ServeHTTP(w, r.WithContext(ctx)) } }