package handlers import ( "log" "net/http" "strings" ) func (a *App) handleLanding(w http.ResponseWriter, r *http.Request) { data := map[string]any{ "AppURL": a.cfg.AppURL, } if err := a.tmpl.ExecuteTemplate(w, "landing.html", data); err != nil { log.Printf("template error: %v", err) http.Error(w, "internal error", http.StatusInternalServerError) } } func (a *App) handleCreateCheckout(w http.ResponseWriter, r *http.Request) { email := r.FormValue("email") if email == "" { http.Error(w, "email required", http.StatusBadRequest) return } sess, err := a.stripe.CreateCheckoutSession(email) if err != nil { log.Printf("stripe checkout error: %v", err) http.Error(w, "failed to create checkout", http.StatusInternalServerError) return } http.Redirect(w, r, sess.URL, http.StatusSeeOther) } func (a *App) handleSuccess(w http.ResponseWriter, r *http.Request) { sessionID := r.URL.Query().Get("session_id") if sessionID == "" { http.Redirect(w, r, "/", http.StatusSeeOther) return } sess, err := a.stripe.GetCheckoutSession(sessionID) if err != nil { log.Printf("stripe get session error: %v", err) http.Error(w, "could not verify payment", http.StatusInternalServerError) return } if sess.PaymentStatus != "paid" { http.Redirect(w, r, "/", http.StatusSeeOther) return } email := sess.CustomerDetails.Email customerID := sess.Customer.ID username := sanitizeUsername(email) // Create the LLDAP user but do NOT add to group or deploy stack yet. // That happens on /activate after the user has set their own password. result, err := a.ldap.ProvisionUser(username, email, customerID) if err != nil { log.Printf("ldap provision failed for %s: %v", email, err) http.Error(w, "account creation failed, contact support", http.StatusInternalServerError) return } data := map[string]any{ "Username": result.Username, "Password": result.Password, "IsNew": result.IsNew, "Email": email, "LoginURL": a.cfg.AutheliaURL, "ResetURL": a.cfg.AutheliaURL + "/#/reset-password/step1", "ActivateURL": a.cfg.AppURL + "/activate", "DashboardURL": a.cfg.AppURL + "/dashboard", } if err := a.tmpl.ExecuteTemplate(w, "welcome.html", data); err != nil { log.Printf("template error: %v", err) http.Error(w, "internal error", http.StatusInternalServerError) } } func (a *App) handlePortal(w http.ResponseWriter, r *http.Request) { customerID := r.FormValue("customer_id") if customerID == "" { http.Error(w, "customer_id required", http.StatusBadRequest) return } sess, err := a.stripe.CreatePortalSession(customerID) if err != nil { log.Printf("stripe portal error: %v", err) http.Error(w, "failed to create portal session", http.StatusInternalServerError) return } http.Redirect(w, r, sess.URL, http.StatusSeeOther) } func sanitizeUsername(email string) string { parts := strings.SplitN(email, "@", 2) name := strings.ToLower(parts[0]) name = strings.Map(func(r rune) rune { if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_' { return r } return '-' }, name) return name }