Upgrade dialog looks nice now

This commit is contained in:
binwiederhier 2023-01-17 19:40:03 -05:00
parent 695c1349e8
commit 4092f7fd51
9 changed files with 160 additions and 85 deletions

View file

@ -49,7 +49,6 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, _ *http.Request, v *vis
return err
}
limits, stats := info.Limits, info.Stats
response := &apiAccountResponse{
Limits: &apiAccountLimits{
Basis: string(limits.Basis),

View file

@ -24,12 +24,30 @@ const (
stripeBodyBytesLimit = 16384
)
var (
errNotAPaidTier = errors.New("tier does not have Stripe price identifier")
)
func (s *Server) handleAccountBillingTiersGet(w http.ResponseWriter, r *http.Request, v *visitor) error {
tiers, err := v.userManager.Tiers()
if err != nil {
return err
}
response := make([]*apiAccountBillingTier, 0)
freeTier := defaultVisitorLimits(s.config)
response := []*apiAccountBillingTier{
{
// Free tier: no code, name or price
Limits: &apiAccountLimits{
Messages: freeTier.MessagesLimit,
MessagesExpiryDuration: int64(freeTier.MessagesExpiryDuration.Seconds()),
Emails: freeTier.EmailsLimit,
Reservations: freeTier.ReservationsLimit,
AttachmentTotalSize: freeTier.AttachmentTotalSizeLimit,
AttachmentFileSize: freeTier.AttachmentFileSizeLimit,
AttachmentExpiryDuration: int64(freeTier.AttachmentExpiryDuration.Seconds()),
},
},
}
for _, tier := range tiers {
if tier.StripePriceID == "" {
continue
@ -48,10 +66,18 @@ func (s *Server) handleAccountBillingTiersGet(w http.ResponseWriter, r *http.Req
s.priceCache[tier.StripePriceID] = priceStr // FIXME race, make this sync.Map or something
}
response = append(response, &apiAccountBillingTier{
Code: tier.Code,
Name: tier.Name,
Price: priceStr,
Features: tier.Features,
Code: tier.Code,
Name: tier.Name,
Price: priceStr,
Limits: &apiAccountLimits{
Messages: tier.MessagesLimit,
MessagesExpiryDuration: int64(tier.MessagesExpiryDuration.Seconds()),
Emails: tier.EmailsLimit,
Reservations: tier.ReservationsLimit,
AttachmentTotalSize: tier.AttachmentTotalSizeLimit,
AttachmentFileSize: tier.AttachmentFileSizeLimit,
AttachmentExpiryDuration: int64(tier.AttachmentExpiryDuration.Seconds()),
},
})
}
w.Header().Set("Content-Type", "application/json")
@ -75,9 +101,8 @@ func (s *Server) handleAccountBillingSubscriptionCreate(w http.ResponseWriter, r
tier, err := s.userManager.Tier(req.Tier)
if err != nil {
return err
}
if tier.StripePriceID == "" {
return errors.New("invalid tier") //FIXME
} else if tier.StripePriceID == "" {
return errNotAPaidTier
}
log.Info("Stripe: No existing subscription, creating checkout flow")
var stripeCustomerID *string
@ -92,10 +117,11 @@ func (s *Server) handleAccountBillingSubscriptionCreate(w http.ResponseWriter, r
}
successURL := s.config.BaseURL + apiAccountBillingSubscriptionCheckoutSuccessTemplate
params := &stripe.CheckoutSessionParams{
Customer: stripeCustomerID, // A user may have previously deleted their subscription
ClientReferenceID: &v.user.Name,
SuccessURL: &successURL,
Mode: stripe.String(string(stripe.CheckoutSessionModeSubscription)),
Customer: stripeCustomerID, // A user may have previously deleted their subscription
ClientReferenceID: &v.user.Name,
SuccessURL: &successURL,
Mode: stripe.String(string(stripe.CheckoutSessionModeSubscription)),
AllowPromotionCodes: stripe.Bool(true),
LineItems: []*stripe.CheckoutSessionLineItemParams{
{
Price: stripe.String(tier.StripePriceID),
@ -212,6 +238,11 @@ func (s *Server) handleAccountBillingSubscriptionDelete(w http.ResponseWriter, r
return err
}
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
if err := json.NewEncoder(w).Encode(newSuccessResponse()); err != nil {
return err
}
return nil
}

View file

@ -241,7 +241,7 @@ type apiAccountTier struct {
}
type apiAccountLimits struct {
Basis string `json:"basis"` // "ip", "role" or "tier"
Basis string `json:"basis,omitempty"` // "ip", "role" or "tier"
Messages int64 `json:"messages"`
MessagesExpiryDuration int64 `json:"messages_expiry_duration"`
Emails int64 `json:"emails"`
@ -305,10 +305,10 @@ type apiConfigResponse struct {
}
type apiAccountBillingTier struct {
Code string `json:"code"`
Name string `json:"name"`
Price string `json:"price"`
Features string `json:"features"`
Code string `json:"code,omitempty"`
Name string `json:"name,omitempty"`
Price string `json:"price,omitempty"`
Limits *apiAccountLimits `json:"limits"`
}
type apiAccountBillingSubscriptionCreateResponse struct {

View file

@ -212,7 +212,7 @@ func (v *visitor) ResetStats() {
}
func (v *visitor) Limits() *visitorLimits {
limits := &visitorLimits{}
limits := defaultVisitorLimits(v.config)
if v.user != nil && v.user.Tier != nil {
limits.Basis = visitorLimitBasisTier
limits.MessagesLimit = v.user.Tier.MessagesLimit
@ -222,15 +222,6 @@ func (v *visitor) Limits() *visitorLimits {
limits.AttachmentTotalSizeLimit = v.user.Tier.AttachmentTotalSizeLimit
limits.AttachmentFileSizeLimit = v.user.Tier.AttachmentFileSizeLimit
limits.AttachmentExpiryDuration = v.user.Tier.AttachmentExpiryDuration
} else {
limits.Basis = visitorLimitBasisIP
limits.MessagesLimit = replenishDurationToDailyLimit(v.config.VisitorRequestLimitReplenish)
limits.MessagesExpiryDuration = v.config.CacheDuration
limits.EmailsLimit = replenishDurationToDailyLimit(v.config.VisitorEmailLimitReplenish)
limits.ReservationsLimit = 0 // No reservations for anonymous users, or users without a tier
limits.AttachmentTotalSizeLimit = v.config.VisitorAttachmentTotalSizeLimit
limits.AttachmentFileSizeLimit = v.config.AttachmentFileSizeLimit
limits.AttachmentExpiryDuration = v.config.AttachmentExpiryDuration
}
return limits
}
@ -288,3 +279,16 @@ func replenishDurationToDailyLimit(duration time.Duration) int64 {
func dailyLimitToRate(limit int64) rate.Limit {
return rate.Limit(limit) * rate.Every(24*time.Hour)
}
func defaultVisitorLimits(conf *Config) *visitorLimits {
return &visitorLimits{
Basis: visitorLimitBasisIP,
MessagesLimit: replenishDurationToDailyLimit(conf.VisitorRequestLimitReplenish),
MessagesExpiryDuration: conf.CacheDuration,
EmailsLimit: replenishDurationToDailyLimit(conf.VisitorEmailLimitReplenish),
ReservationsLimit: 0, // No reservations for anonymous users, or users without a tier
AttachmentTotalSizeLimit: conf.VisitorAttachmentTotalSizeLimit,
AttachmentFileSizeLimit: conf.AttachmentFileSizeLimit,
AttachmentExpiryDuration: conf.AttachmentExpiryDuration,
}
}