diff --git a/server/server.go b/server/server.go
index 97c79494..f232e0f5 100644
--- a/server/server.go
+++ b/server/server.go
@@ -42,6 +42,7 @@ import (
- HIGH Self-review
- MEDIUM: Test for expiring messages after reservation removal
- MEDIUM: Test new token endpoints & never-expiring token
+- MEDIUM: Tests for manager.go
- LOW: UI: Flickering upgrade banner when logging in
- LOW: Menu item -> popup click should not open page
- LOW: get rid of reservation id, replace with DELETE X-Topic: ...
diff --git a/server/server_payments.go b/server/server_payments.go
index dcb370f5..d812837f 100644
--- a/server/server_payments.go
+++ b/server/server_payments.go
@@ -121,11 +121,8 @@ func (s *Server) handleAccountBillingSubscriptionCreate(w http.ResponseWriter, r
return errNotAPaidTier
}
logvr(v, r).
+ With(tier).
Tag(tagStripe).
- Fields(log.Context{
- "tier": tier,
- "stripe_price_id": tier.StripePriceID,
- }).
Info("Creating Stripe checkout flow")
var stripeCustomerID *string
if u.Billing.StripeCustomerID != "" {
@@ -196,11 +193,9 @@ func (s *Server) handleAccountBillingSubscriptionCreateSuccess(w http.ResponseWr
}
v.SetUser(u)
logvr(v, r).
+ With(tier).
Tag(tagStripe).
Fields(log.Context{
- "tier_id": tier.ID,
- "tier_name": tier.Name,
- "stripe_price_id": tier.StripePriceID,
"stripe_customer_id": sess.Customer.ID,
"stripe_subscription_id": sub.ID,
"stripe_subscription_status": string(sub.Status),
@@ -273,7 +268,8 @@ func (s *Server) handleAccountBillingSubscriptionUpdate(w http.ResponseWriter, r
}
// handleAccountBillingSubscriptionDelete facilitates downgrading a paid user to a tier-less user,
-// and cancelling the Stripe subscription entirely
+// and cancelling the Stripe subscription entirely. Note that this does not actually change the tier.
+// That is done by a webhook at the period end (in X days).
func (s *Server) handleAccountBillingSubscriptionDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
logvr(v, r).Tag(tagStripe).Info("Deleting Stripe subscription")
u := v.User()
diff --git a/user/types.go b/user/types.go
index 489a1fec..0e21e518 100644
--- a/user/types.go
+++ b/user/types.go
@@ -3,6 +3,7 @@ package user
import (
"errors"
"github.com/stripe/stripe-go/v74"
+ "heckel.io/ntfy/log"
"net/netip"
"regexp"
"time"
@@ -92,6 +93,14 @@ type Tier struct {
StripePriceID string // Price ID for paid tiers (price_...)
}
+func (t *Tier) Context() log.Context {
+ return log.Context{
+ "tier_id": t.ID,
+ "tier_name": t.Name,
+ "stripe_price_id": t.StripePriceID,
+ }
+}
+
// Subscription represents a user's topic subscription
type Subscription struct {
ID string `json:"id"`
diff --git a/web/public/static/langs/en.json b/web/public/static/langs/en.json
index 2f38f3c3..2bfc60df 100644
--- a/web/public/static/langs/en.json
+++ b/web/public/static/langs/en.json
@@ -14,6 +14,7 @@
"login_title": "Sign in to your ntfy account",
"login_form_button_submit": "Sign in",
"login_link_signup": "Sign up",
+ "login_disabled": "Login is disabled",
"action_bar_show_menu": "Show menu",
"action_bar_logo_alt": "ntfy logo",
"action_bar_settings": "Settings",
@@ -46,6 +47,8 @@
"nav_button_subscribe": "Subscribe to topic",
"nav_button_muted": "Notifications muted",
"nav_button_connecting": "connecting",
+ "nav_upgrade_banner_label": "Upgrade to ntfy Pro",
+ "nav_upgrade_banner_description": "Reserve topics, more messages & emails, and larger attachments",
"alert_grant_title": "Notifications are disabled",
"alert_grant_description": "Grant your browser permission to display desktop notifications.",
"alert_grant_button": "Grant now",
diff --git a/web/src/components/Login.js b/web/src/components/Login.js
index 2e2389cc..8b14c53d 100644
--- a/web/src/components/Login.js
+++ b/web/src/components/Login.js
@@ -43,7 +43,7 @@ const Login = () => {
if (!config.enable_login) {
return (
- {t("Login is disabled")}
+ {t("login_disabled")}
);
}
diff --git a/web/src/components/Navigation.js b/web/src/components/Navigation.js
index 4a9bc2c8..f4a20215 100644
--- a/web/src/components/Navigation.js
+++ b/web/src/components/Navigation.js
@@ -177,6 +177,7 @@ const NavList = (props) => {
};
const UpgradeBanner = () => {
+ const { t } = useTranslation();
const [dialogKey, setDialogKey] = useState(0);
const [dialogOpen, setDialogOpen] = useState(false);
@@ -198,8 +199,8 @@ const UpgradeBanner = () => {