package handler import ( "context" "database/sql" "net/http" "dealroom/internal/rbac" "dealroom/internal/store" "github.com/gorilla/sessions" ) // Handler contains dependencies for HTTP handlers type Handler struct { db *sql.DB store *store.Store rbac *rbac.Engine sessions *sessions.CookieStore config *Config } // Config holds configuration for handlers type Config struct { BaseURL string SessionKey string K25APIURL string K25APIKey string SMTPHost string SMTPUser string SMTPPass string } // New creates a new handler instance func New(db *sql.DB, fileStore *store.Store, config *Config) *Handler { return &Handler{ db: db, store: fileStore, rbac: rbac.New(db), sessions: sessions.NewCookieStore([]byte(config.SessionKey)), config: config, } } // RegisterRoutes sets up all HTTP routes func (h *Handler) RegisterRoutes(mux *http.ServeMux) { // Static files mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) // Authentication routes mux.HandleFunc("/auth/login", h.handleLogin) mux.HandleFunc("/auth/verify/", h.handleVerifyLogin) mux.HandleFunc("/auth/logout", h.handleLogout) mux.HandleFunc("/auth/me", h.handleMe) // Page routes mux.HandleFunc("/", h.handleDashboard) mux.HandleFunc("/login", h.handleLoginPage) mux.HandleFunc("/deal-rooms/", h.handleDealRoom) mux.HandleFunc("/documents/", h.handleDocument) mux.HandleFunc("/admin", h.requireAuth(h.requireAdmin(h.handleAdmin))) mux.HandleFunc("/profile", h.requireAuth(h.handleProfile)) mux.HandleFunc("/activity", h.requireAuth(h.handleActivity)) // API routes mux.HandleFunc("/api/deal-rooms", h.requireAuth(h.handleAPIEndpoint("deal-rooms"))) mux.HandleFunc("/api/deal-rooms/", h.requireAuth(h.handleAPIEndpoint("deal-rooms"))) mux.HandleFunc("/api/entries", h.requireAuth(h.handleAPIEndpoint("entries"))) mux.HandleFunc("/api/entries/", h.requireAuth(h.handleAPIEndpoint("entries"))) mux.HandleFunc("/api/search", h.requireAuth(h.handleSearch)) mux.HandleFunc("/api/activity/", h.requireAuth(h.handleAPIActivity)) } // Middleware func (h *Handler) requireAuth(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, _ := h.sessions.Get(r, "dealroom") userID, ok := session.Values["user_id"].(string) if !ok || userID == "" { if isAPIRequest(r) { http.Error(w, "Authentication required", http.StatusUnauthorized) return } http.Redirect(w, r, "/login", http.StatusSeeOther) return } // Add user ID to request context ctx := r.Context() ctx = setUserID(ctx, userID) next.ServeHTTP(w, r.WithContext(ctx)) } } func (h *Handler) requireAdmin(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { userID := getUserID(r.Context()) // Check if user is admin var role string err := h.db.QueryRow("SELECT role FROM users WHERE id = ?", userID).Scan(&role) if err != nil || role != "admin" { http.Error(w, "Admin access required", http.StatusForbidden) return } next.ServeHTTP(w, r) } } // Placeholder handlers - to be implemented func (h *Handler) handleLogin(w http.ResponseWriter, r *http.Request) { // TODO: Implement magic link login http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleVerifyLogin(w http.ResponseWriter, r *http.Request) { // TODO: Implement login verification http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleLogout(w http.ResponseWriter, r *http.Request) { session, _ := h.sessions.Get(r, "dealroom") session.Values["user_id"] = "" session.Save(r, w) http.Redirect(w, r, "/login", http.StatusSeeOther) } func (h *Handler) handleMe(w http.ResponseWriter, r *http.Request) { // TODO: Return current user info http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleDashboard(w http.ResponseWriter, r *http.Request) { // TODO: Render dashboard template http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleLoginPage(w http.ResponseWriter, r *http.Request) { // TODO: Render login template http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleDealRoom(w http.ResponseWriter, r *http.Request) { // TODO: Handle deal room pages http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleDocument(w http.ResponseWriter, r *http.Request) { // TODO: Handle document viewing http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleAdmin(w http.ResponseWriter, r *http.Request) { // TODO: Render admin panel http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleProfile(w http.ResponseWriter, r *http.Request) { // TODO: Render user profile http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleActivity(w http.ResponseWriter, r *http.Request) { // TODO: Render activity feed http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleAPIEndpoint(endpoint string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // TODO: Implement REST API endpoints http.Error(w, "Not implemented", http.StatusNotImplemented) } } func (h *Handler) handleSearch(w http.ResponseWriter, r *http.Request) { // TODO: Implement search API http.Error(w, "Not implemented", http.StatusNotImplemented) } func (h *Handler) handleAPIActivity(w http.ResponseWriter, r *http.Request) { // TODO: Implement activity API http.Error(w, "Not implemented", http.StatusNotImplemented) } // Helper functions func isAPIRequest(r *http.Request) bool { return r.Header.Get("Accept") == "application/json" || r.Header.Get("Content-Type") == "application/json" || r.URL.Path[:5] == "/api/" } // Context helpers would go in a separate context.go file func setUserID(ctx context.Context, userID string) context.Context { // TODO: Implement context helpers return ctx } func getUserID(ctx context.Context) string { // TODO: Implement context helpers return "" }