dealroom/internal/handler/handler.go

127 lines
4.8 KiB
Go

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("/signup", h.handleSignupPage)
mux.HandleFunc("/auth/login", h.handleLogin)
mux.HandleFunc("/auth/signup", h.handleSignup)
mux.HandleFunc("/auth/logout", h.handleLogout)
mux.HandleFunc("/auth/view-toggle", h.requireAuth(h.handleViewToggle))
// 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))
// Admin CRUD
mux.HandleFunc("/admin", h.requireAdmin(h.handleAdmin))
mux.HandleFunc("/admin/contacts", h.requireAdmin(h.handleAdminContacts))
mux.HandleFunc("/admin/contacts/edit", h.requireAdmin(h.handleAdminContactForm))
mux.HandleFunc("/admin/contacts/save", h.requireAdmin(h.handleAdminContactSave))
mux.HandleFunc("/admin/contacts/delete", h.requireAdmin(h.handleAdminContactDelete))
mux.HandleFunc("/admin/deals", h.requireAdmin(h.handleAdminDeals))
mux.HandleFunc("/admin/deals/edit", h.requireAdmin(h.handleAdminDealForm))
mux.HandleFunc("/admin/deals/save", h.requireAdmin(h.handleAdminDealSave))
mux.HandleFunc("/admin/deals/delete", h.requireAdmin(h.handleAdminDealDelete))
mux.HandleFunc("/admin/users", h.requireAdmin(h.handleAdminUsers))
mux.HandleFunc("/admin/users/edit", h.requireAdmin(h.handleAdminUserForm))
mux.HandleFunc("/admin/users/save", h.requireAdmin(h.handleAdminUserSave))
mux.HandleFunc("/admin/users/delete", h.requireAdmin(h.handleAdminUserDelete))
mux.HandleFunc("/admin/organizations", h.requireAdmin(h.handleAdminOrgs))
mux.HandleFunc("/admin/organizations/edit", h.requireAdmin(h.handleAdminOrgForm))
mux.HandleFunc("/admin/organizations/save", h.requireAdmin(h.handleAdminOrgSave))
mux.HandleFunc("/admin/organizations/delete", h.requireAdmin(h.handleAdminOrgDelete))
// Team & Invites
mux.HandleFunc("/team", h.requireAuth(h.handleTeam))
mux.HandleFunc("/invites/create", h.requireAuth(h.handleInviteCreate))
mux.HandleFunc("/invites/accept", h.handleInviteAcceptPage)
mux.HandleFunc("/invites/accept-submit", h.handleInviteAccept)
// Deal creation & folder management
mux.HandleFunc("/deals/create", h.requireAuth(h.handleCreateDeal))
mux.HandleFunc("/deals/folders/create", h.requireAuth(h.handleFolderCreate))
mux.HandleFunc("/deals/folders/rename", h.requireAuth(h.handleFolderRename))
mux.HandleFunc("/deals/folders/delete", h.requireAuth(h.handleFolderDelete))
mux.HandleFunc("/deals/folders/reorder", h.requireAuth(h.handleFolderReorder))
// File management
mux.HandleFunc("/deals/files/upload", h.requireAuth(h.handleFileUpload))
mux.HandleFunc("/deals/files/delete", h.requireAuth(h.handleFileDelete))
mux.HandleFunc("/deals/files/download/", h.requireAuth(h.handleFileDownload))
mux.HandleFunc("/deals/files/comments/", h.requireAuth(h.handleFileComments))
// 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
}
// Check view-as-buyer toggle (only applies to sellers)
if profile.Role == "owner" || profile.Role == "admin" {
if c, err := r.Cookie("view_as_buyer"); err == nil && c.Value == "1" {
profile.ViewAsBuyer = true
}
}
ctx := setProfile(r.Context(), &profile)
next.ServeHTTP(w, r.WithContext(ctx))
}
}