feat: convert change-email from modal to standalone page + Stripe customer.updated webhook
All checks were successful
Deploy to Production / Deploy to Server (push) Successful in 1m8s
All checks were successful
Deploy to Production / Deploy to Server (push) Successful in 1m8s
- Add /change-email as a proper standalone page (public/src/change-email.html) with API key input, new email input, verification code flow, and success state - Update footer partial: change "/#change-email" link to "/change-email" on all pages - Remove email change modal HTML and hash-handler JS from index page source - Add /change-email to sitemap.xml - Rebuild all HTML files via build-html.cjs - Add updateEmailByCustomer() to src/services/keys.ts - Add customer.updated webhook handler in src/routes/billing.ts to sync email changes made via Stripe dashboard back to DocFast
This commit is contained in:
parent
5099bae41f
commit
8f3b1a9660
12 changed files with 674 additions and 121 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { Router, Request, Response } from "express";
|
||||
import Stripe from "stripe";
|
||||
import { createProKey, downgradeByCustomer } from "../services/keys.js";
|
||||
import { createProKey, downgradeByCustomer, updateEmailByCustomer } from "../services/keys.js";
|
||||
import logger from "../services/logger.js";
|
||||
|
||||
function escapeHtml(s: string): string {
|
||||
|
|
@ -210,6 +210,18 @@ router.post("/webhook", async (req: Request, res: Response) => {
|
|||
logger.info({ customerId }, "customer.subscription.deleted: downgraded key to free tier");
|
||||
break;
|
||||
}
|
||||
case "customer.updated": {
|
||||
const customer = event.data.object as Stripe.Customer;
|
||||
const customerId = customer.id;
|
||||
const newEmail = customer.email;
|
||||
if (customerId && newEmail) {
|
||||
const updated = await updateEmailByCustomer(customerId, newEmail);
|
||||
if (updated) {
|
||||
logger.info({ customerId, newEmail }, "Customer email synced from Stripe");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,3 +129,11 @@ export async function updateKeyEmail(apiKey: string, newEmail: string): Promise<
|
|||
await pool.query("UPDATE api_keys SET email = $1 WHERE key = $2", [newEmail, apiKey]);
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function updateEmailByCustomer(stripeCustomerId: string, newEmail: string): Promise<boolean> {
|
||||
const entry = keysCache.find(k => k.stripeCustomerId === stripeCustomerId);
|
||||
if (!entry) return false;
|
||||
entry.email = newEmail;
|
||||
await pool.query(UPDATE api_keys SET email = $1 WHERE stripe_customer_id = $2, [newEmail, stripeCustomerId]);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue