From 41c385a6d4ecdee40e599b1821de2b197b11cde0 Mon Sep 17 00:00:00 2001 From: e-schneid <99349687+e-schneid@users.noreply.github.com> Date: Thu, 13 Oct 2022 11:56:44 -0700 Subject: [PATCH] feat: display name and email in stripe (#2010) --- packages/api/src/user.js | 18 ++++++++++++++---- packages/api/src/utils/billing-types.ts | 7 ++++++- packages/api/src/utils/billing.js | 10 ++++++---- packages/api/src/utils/stripe.js | 7 +++++-- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/packages/api/src/user.js b/packages/api/src/user.js index 04d5940fa5..c82902ba8e 100644 --- a/packages/api/src/user.js +++ b/packages/api/src/user.js @@ -16,7 +16,7 @@ import { magicLinkBypassForE2ETestingInTestmode } from './magic.link.js' import { CustomerNotFound, getPaymentSettings, initializeBillingForNewUser, isStoragePriceName, savePaymentSettings } from './utils/billing.js' /** - * @typedef {{ _id: string, issuer: string }} User + * @typedef {{ _id: string, issuer: string, name?: string, email?: string }} User * @typedef {{ _id: string, name: string }} AuthToken * @typedef {{ user: User, authToken?: AuthToken }} Auth * @typedef {Request & { auth: Auth }} AuthenticatedRequest @@ -112,13 +112,15 @@ const createMagicLinkRequestAuthenticator = (env) => async (request) => { * @param {object} user * @param {string} user.id * @param {string} user.issuer + * @param {import('../src/utils/billing-types').UserCreationOptions} [userCreationOptions] */ -async function initializeNewUser (ctx, user) { +async function initializeNewUser (ctx, user, userCreationOptions) { await initializeBillingForNewUser( { customers: ctx.customers, subscriptions: ctx.subscriptions, - user: { ...user, id: user.id.toString() } + user: { ...user, id: user.id.toString() }, + userCreationOptions } ) } @@ -154,7 +156,11 @@ async function loginOrRegister (request, env) { user = await env.db.upsertUser(parsed) // initialize billing, etc, but only if the user was newly inserted if (user.inserted) { - await initializeNewUser(env, { ...user, id: user.id }) + await initializeNewUser( + env, + { ...user, id: user.id }, + { name: parsed.name, email: parsed.email } + ) } } else if (env.MODE === READ_ONLY) { user = await env.db.getUser(parsed.issuer, {}) @@ -701,6 +707,10 @@ export async function userPaymentPut (request, env) { subscription: { storage: subscriptionStorage } + }, + { + name: request.auth.user.name, + email: request.auth.user.email } ) const userPaymentSettingsUrl = '/user/payment' diff --git a/packages/api/src/utils/billing-types.ts b/packages/api/src/utils/billing-types.ts index cbb12cf5e7..079947e9b9 100644 --- a/packages/api/src/utils/billing-types.ts +++ b/packages/api/src/utils/billing-types.ts @@ -42,7 +42,7 @@ export interface Customer { } export interface CustomersService { - getOrCreateForUser(user: BillingUser): Promise + getOrCreateForUser(user: BillingUser, userCreationOptions?: UserCreationOptions): Promise } export type StoragePriceName = 'free' | 'lite' | 'pro' @@ -102,3 +102,8 @@ export interface UserCustomerService { getUserCustomer: (userId: string) => Promise upsertUserCustomer: (userId: string, customerId: string) => Promise } + +export interface UserCreationOptions { + email?: string + name?: string +} \ No newline at end of file diff --git a/packages/api/src/utils/billing.js b/packages/api/src/utils/billing.js index 542499191c..4a626f0508 100644 --- a/packages/api/src/utils/billing.js +++ b/packages/api/src/utils/billing.js @@ -14,10 +14,11 @@ * @param {object} paymentSettings * @param {Pick} paymentSettings.paymentMethod * @param {import('./billing-types').W3PlatformSubscription} paymentSettings.subscription + * @param {import('./billing-types').UserCreationOptions} [userCreationOptions] */ -export async function savePaymentSettings (ctx, paymentSettings) { +export async function savePaymentSettings (ctx, paymentSettings, userCreationOptions) { const { billing, customers, user } = ctx - const customer = await customers.getOrCreateForUser(user) + const customer = await customers.getOrCreateForUser(user, userCreationOptions) await billing.savePaymentMethod(customer.id, paymentSettings.paymentMethod.id) await ctx.subscriptions.saveSubscription(customer.id, paymentSettings.subscription) } @@ -28,10 +29,11 @@ export async function savePaymentSettings (ctx, paymentSettings) { * @param {import('./billing-types').CustomersService} ctx.customers * @param {import('./billing-types').SubscriptionsService} ctx.subscriptions * @param {import('./billing-types').BillingUser} ctx.user + * @param {import('./billing-types').UserCreationOptions} [ctx.userCreationOptions] */ export async function initializeBillingForNewUser (ctx) { - const { customers, user } = ctx - const customer = await customers.getOrCreateForUser(user) + const { customers, user, userCreationOptions } = ctx + const customer = await customers.getOrCreateForUser(user, userCreationOptions) await ctx.subscriptions.saveSubscription(customer.id, { storage: { price: storagePriceNames.free diff --git a/packages/api/src/utils/stripe.js b/packages/api/src/utils/stripe.js index 83ca407ffd..9a81d14f74 100644 --- a/packages/api/src/utils/stripe.js +++ b/packages/api/src/utils/stripe.js @@ -183,15 +183,18 @@ export class StripeCustomersService { /** * @param {import('./billing-types').BillingUser} user + * @param {import('./billing-types').UserCreationOptions} [options] * @returns {Promise} */ - async getOrCreateForUser (user) { + async getOrCreateForUser (user, options) { const existingCustomer = await this.userCustomerService.getUserCustomer(user.id.toString()) if (existingCustomer) return existingCustomer const createdCustomer = await this.stripe.customers.create({ metadata: { 'web3.storage/user.id': user.id - } + }, + name: options?.name, + email: options?.email }) await this.userCustomerService.upsertUserCustomer(user.id.toString(), createdCustomer.id) return createdCustomer