package handler import ( "crypto/rand" "encoding/hex" "net/http" "time" "dealroom/templates" "golang.org/x/crypto/bcrypt" ) func (h *Handler) handleLoginPage(w http.ResponseWriter, r *http.Request) { // If already logged in, redirect to dashboard cookie, err := r.Cookie("session") if err == nil && cookie.Value != "" { var count int h.db.QueryRow("SELECT COUNT(*) FROM sessions WHERE token = ? AND expires_at > datetime('now')", cookie.Value).Scan(&count) if count > 0 { http.Redirect(w, r, "/", http.StatusSeeOther) return } } templates.Login().Render(r.Context(), w) } func (h *Handler) handleLogin(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Redirect(w, r, "/login", http.StatusSeeOther) return } email := r.FormValue("email") password := r.FormValue("password") var userID string var passHash string err := h.db.QueryRow("SELECT id, password_hash FROM profiles WHERE email = ?", email).Scan(&userID, &passHash) if err != nil || bcrypt.CompareHashAndPassword([]byte(passHash), []byte(password)) != nil { http.Redirect(w, r, "/login?error=invalid", http.StatusSeeOther) return } h.createSession(w, userID) http.Redirect(w, r, "/", http.StatusSeeOther) } func hashPassword(password string) (string, error) { hash, err := bcrypt.GenerateFromPassword([]byte(password), 12) if err != nil { return "", err } return string(hash), nil } func (h *Handler) handleLogout(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("session") if err == nil { h.db.Exec("DELETE FROM sessions WHERE token = ?", cookie.Value) } http.SetCookie(w, &http.Cookie{Name: "session", Value: "", MaxAge: -1, Path: "/"}) http.Redirect(w, r, "/login", http.StatusSeeOther) } func (h *Handler) createSession(w http.ResponseWriter, userID string) { token := generateToken() expires := time.Now().Add(24 * time.Hour) h.db.Exec("INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)", token, userID, expires) http.SetCookie(w, &http.Cookie{ Name: "session", Value: token, Path: "/", Expires: expires, HttpOnly: true, SameSite: http.SameSiteLaxMode, }) } func (h *Handler) handleViewToggle(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } profile := getProfile(r.Context()) if profile.Role != "owner" && profile.Role != "admin" { http.Error(w, "Forbidden", http.StatusForbidden) return } // Toggle the cookie current := false if c, err := r.Cookie("view_as_buyer"); err == nil && c.Value == "1" { current = true } value := "1" if current { value = "" } http.SetCookie(w, &http.Cookie{ Name: "view_as_buyer", Value: value, Path: "/", HttpOnly: true, SameSite: http.SameSiteLaxMode, }) // Redirect back to referrer or dashboard ref := r.Header.Get("Referer") if ref == "" { ref = "/" } http.Redirect(w, r, ref, http.StatusSeeOther) } func generateToken() string { b := make([]byte, 32) rand.Read(b) return hex.EncodeToString(b) } func (h *Handler) handleSignupPage(w http.ResponseWriter, r *http.Request) { // If already logged in, redirect to dashboard cookie, err := r.Cookie("session") if err == nil && cookie.Value != "" { var count int h.db.QueryRow("SELECT COUNT(*) FROM sessions WHERE token = ? AND expires_at > datetime('now')", cookie.Value).Scan(&count) if count > 0 { http.Redirect(w, r, "/", http.StatusSeeOther) return } } templates.Signup().Render(r.Context(), w) } func (h *Handler) handleSignup(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Redirect(w, r, "/signup", http.StatusSeeOther) return } // Parse form err := r.ParseForm() if err != nil { http.Redirect(w, r, "/signup", http.StatusSeeOther) return } orgName := r.FormValue("org_name") orgType := r.FormValue("org_type") if orgType == "" { orgType = "company" } name := r.FormValue("name") email := r.FormValue("email") password := r.FormValue("password") // Create organization orgID := generateID("org") _, err = h.db.Exec(`INSERT INTO organizations (id, name, slug, org_type) VALUES (?, ?, ?, ?)`, orgID, orgName, orgName, orgType) if err != nil { http.Redirect(w, r, "/signup", http.StatusSeeOther) return } // Create user hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) userID := generateID("user") _, err = h.db.Exec(`INSERT INTO profiles (id, email, full_name, role, organization_id, password_hash) VALUES (?, ?, ?, ?, ?, ?)`, userID, email, name, "owner", orgID, string(hashedPassword)) if err != nil { http.Redirect(w, r, "/signup", http.StatusSeeOther) return } // Auto login h.createSession(w, userID) http.Redirect(w, r, "/", http.StatusSeeOther) }