Files
at-container-registry/pkg/appview/handlers/subscription.go
T

108 lines
2.7 KiB
Go

package handlers
import (
"log/slog"
"net/http"
"atcr.io/pkg/appview/middleware"
"atcr.io/pkg/billing"
)
// SubscriptionDisplay is the template-friendly subscription data.
type SubscriptionDisplay struct {
UserDID string
CurrentTier string
PaymentsEnabled bool
Tiers []TierDisplay
SubscriptionID string
BillingInterval string
HideBilling bool
}
// TierDisplay is a template-friendly tier.
type TierDisplay struct {
ID string
Name string
Description string
Features []string
PriceCentsMonthly int
PriceCentsYearly int
PriceMonthly string // e.g. "$5/mo"
PriceYearly string // e.g. "$50/yr"
IsCurrent bool
}
// SubscriptionCheckoutHandler redirects to Stripe checkout.
type SubscriptionCheckoutHandler struct {
BaseUIHandler
}
func (h *SubscriptionCheckoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user := middleware.GetUser(r)
if user == nil {
http.Redirect(w, r, "/auth/oauth/login?return_to=/settings%23storage", http.StatusFound)
return
}
if h.BillingManager == nil || !h.BillingManager.Enabled() {
http.Error(w, "Billing not available", http.StatusNotFound)
return
}
tier := r.URL.Query().Get("tier")
if tier == "" {
http.Error(w, "tier parameter required", http.StatusBadRequest)
return
}
interval := r.URL.Query().Get("interval")
if interval == "" {
interval = "monthly"
}
resp, err := h.BillingManager.CreateCheckoutSession(r, user.DID, user.Handle, &billing.CheckoutSessionRequest{
Tier: tier,
Interval: interval,
})
if err != nil {
slog.Warn("Failed to create checkout session", "did", user.DID, "tier", tier, "error", err)
http.Error(w, "Failed to create checkout session", http.StatusInternalServerError)
return
}
http.Redirect(w, r, resp.CheckoutURL, http.StatusFound)
}
// SubscriptionPortalHandler redirects to Stripe billing portal.
type SubscriptionPortalHandler struct {
BaseUIHandler
}
func (h *SubscriptionPortalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user := middleware.GetUser(r)
if user == nil {
http.Redirect(w, r, "/auth/oauth/login?return_to=/settings%23storage", http.StatusFound)
return
}
if h.BillingManager == nil || !h.BillingManager.Enabled() {
http.Error(w, "Billing not available", http.StatusNotFound)
return
}
scheme := "https"
if r.TLS == nil {
scheme = "http"
}
returnURL := scheme + "://" + h.SiteURL + "/settings#storage"
resp, err := h.BillingManager.GetBillingPortalURL(user.DID, returnURL)
if err != nil {
slog.Warn("Failed to get billing portal URL", "did", user.DID, "error", err)
http.Error(w, "Failed to get billing portal", http.StatusInternalServerError)
return
}
http.Redirect(w, r, resp.PortalURL, http.StatusFound)
}