dealroom/internal/handler/handler.go

206 lines
6.0 KiB
Go

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 ""
}