Skip to content

Commit

Permalink
feat: display name and email in stripe (#2010)
Browse files Browse the repository at this point in the history
  • Loading branch information
e-schneid committed Oct 13, 2022
1 parent 477cf73 commit 41c385a
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 11 deletions.
18 changes: 14 additions & 4 deletions packages/api/src/user.js
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
)
}
Expand Down Expand Up @@ -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, {})
Expand Down Expand Up @@ -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'
Expand Down
7 changes: 6 additions & 1 deletion packages/api/src/utils/billing-types.ts
Expand Up @@ -42,7 +42,7 @@ export interface Customer {
}

export interface CustomersService {
getOrCreateForUser(user: BillingUser): Promise<Customer>
getOrCreateForUser(user: BillingUser, userCreationOptions?: UserCreationOptions): Promise<Customer>
}

export type StoragePriceName = 'free' | 'lite' | 'pro'
Expand Down Expand Up @@ -102,3 +102,8 @@ export interface UserCustomerService {
getUserCustomer: (userId: string) => Promise<null|{ id: string }>
upsertUserCustomer: (userId: string, customerId: string) => Promise<void>
}

export interface UserCreationOptions {
email?: string
name?: string
}
10 changes: 6 additions & 4 deletions packages/api/src/utils/billing.js
Expand Up @@ -14,10 +14,11 @@
* @param {object} paymentSettings
* @param {Pick<import('./billing-types').PaymentMethod, 'id'>} 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)
}
Expand All @@ -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
Expand Down
7 changes: 5 additions & 2 deletions packages/api/src/utils/stripe.js
Expand Up @@ -183,15 +183,18 @@ export class StripeCustomersService {

/**
* @param {import('./billing-types').BillingUser} user
* @param {import('./billing-types').UserCreationOptions} [options]
* @returns {Promise<Customer>}
*/
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
Expand Down

0 comments on commit 41c385a

Please sign in to comment.