mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-20 09:14:16 +00:00
108 lines
2.7 KiB
Go
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)
|
|
}
|