-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: stop creating a Stripe account during web3.storage account creat…
…ion (#2226) Fixes #2225 This eliminates a race condition causing the creation of multiple customers in Stripe. New customers are now treated as if they're in the free tier without actually giving them a stripe customer.
- Loading branch information
Showing
5 changed files
with
54 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ import userUploads from './fixtures/pgrest/get-user-uploads.js' | |
import { AuthorizationTestContext } from './contexts/authorization.js' | ||
import { userLoginPost } from '../src/user.js' | ||
import { Magic } from '@magic-sdk/admin' | ||
import { createMockCustomerService, createMockSubscriptionsService, createMockUserCustomerService, storagePriceNames } from '../src/utils/billing.js' | ||
import { createMockCustomerService, createMockSubscriptionsService, createMockUserCustomerService } from '../src/utils/billing.js' | ||
|
||
describe('GET /user/account', () => { | ||
it('error if not authenticated with magic.link', async () => { | ||
|
@@ -422,41 +422,7 @@ describe('GET /user/pins', () => { | |
}) | ||
|
||
describe('userLoginPost', function () { | ||
it('brand new users have a storageSubscription with price=free', async function () { | ||
const user1Authentication = { | ||
issuer: `user1-${Math.random().toString().slice(2)}`, | ||
publicAddress: `user1-${Math.random().toString().slice(2)}`, | ||
email: '[email protected]' | ||
} | ||
const env = { | ||
MODE: /** @type {const} */ ('rw'), | ||
db: getDBClient(), | ||
magic: new Magic(process.env.MAGIC_SECRET_KEY), | ||
authenticateRequest: async () => user1Authentication, | ||
customers: createMockCustomerService(), | ||
subscriptions: createMockSubscriptionsService() | ||
} | ||
const request = new Request(new URL('/user/login', endpoint).toString(), { | ||
method: 'post', | ||
body: JSON.stringify({ | ||
data: {} | ||
}) | ||
}) | ||
const response = await userLoginPost(request, env) | ||
assert.equal(response.status, 200, 'response.status is as expected') | ||
|
||
// now ensure it has desired subscription | ||
const gotUser = await env.db.getUser(user1Authentication.issuer, {}) | ||
const gotSubscription = await env.subscriptions.getSubscription( | ||
(await env.customers.getOrCreateForUser({ id: gotUser._id })).id | ||
) | ||
assert.ok(!(gotSubscription instanceof Error), 'gotSubscription is not an error') | ||
assert.ok(gotSubscription, 'gotSubscription is truthy') | ||
assert.equal(gotSubscription.storage?.price, storagePriceNames.free) | ||
}) | ||
it('login to email-originating user updates customer contact', async function () { | ||
// we're going to create the user by doing userLoginPost the first time | ||
// then on the second time we'll expect the customer to be updated | ||
const user1Name1 = 'user1+1' | ||
const user1Authentication1 = { | ||
issuer: `user1-${Math.random().toString().slice(2)}`, | ||
|
@@ -471,34 +437,22 @@ describe('userLoginPost', function () { | |
customers: createMockCustomerService(userCustomerService), | ||
subscriptions: createMockSubscriptionsService() | ||
} | ||
const getCustomerForUserIssuer = async (issuer) => { | ||
const user = await env.db.getUser(issuer, {}) | ||
const customer = await userCustomerService.getUserCustomer(user._id) | ||
return customer | ||
} | ||
const createUserLoginRequest = () => new Request(new URL('/user/login', endpoint).toString(), { | ||
method: 'post', | ||
body: JSON.stringify({ | ||
data: {} | ||
}) | ||
}) | ||
// do first userLoginPost request, which should create the user for the first time | ||
const response1 = await userLoginPost(createUserLoginRequest(), { | ||
...env, | ||
authenticateRequest: async () => user1Authentication1 | ||
}) | ||
assert.equal(response1.status, 200, 'response.status is as expected') | ||
// the user has been created | ||
|
||
// after this first login, we expect the customer contact to have been set | ||
const customer1 = await getCustomerForUserIssuer(user1Authentication1.issuer) | ||
const contact1 = customer1 && await env.customers.getContact(customer1.id) | ||
assert.deepEqual(contact1, { | ||
name: user1Name1, | ||
email: user1Authentication1.email | ||
}, 'user1 contact saved based on request authentication in first userLoginPost') | ||
// create the user | ||
const { id } = await env.db.upsertUser({ ...user1Authentication1, name: user1Name1 }) | ||
// create the customer for the user | ||
await env.customers.getOrCreateForUser( | ||
{ id }, | ||
{ email: user1Authentication1.email, name: user1Name1 } | ||
) | ||
|
||
// now we're going to make the same userLoginPost request again, logging in to that same user.issuer, but with a new email | ||
// now we're going to make a userLoginPost request but with a new email | ||
const name2 = 'user1+2' | ||
/** @type {import('../src/user.js').IssuedAuthentication} */ | ||
const user1Authentication2 = { | ||
|
@@ -569,29 +523,17 @@ describe('userLoginPost', function () { | |
name: 'User 1' | ||
} | ||
} | ||
// do first userLoginPost request, which should create the user for the first time | ||
const response1 = await userLoginPost(createUserLoginViaGithubRequest(githubUserOauth1), { | ||
...env, | ||
authenticateRequest: async () => user1Authentication1 | ||
}) | ||
assert.equal(response1.status, 200, 'response.status is as expected') | ||
|
||
// the user has been created | ||
// let's make sure the customer contact was created based on the github oauth info | ||
const getCustomerForUserIssuer = async (issuer) => { | ||
const user = await env.db.getUser(issuer, {}) | ||
const customer = await userCustomerService.getUserCustomer(user._id) | ||
return customer | ||
} | ||
const customer1 = await getCustomerForUserIssuer(user1Authentication1.issuer) | ||
assert.ok(!(customer1 instanceof Error), 'no error finding customer for user after first login') | ||
assert.ok(customer1, 'user has a customer after first login') | ||
const contact1 = await env.customers.getContact(customer1.id) | ||
assert.ok(!(contact1 instanceof Error), 'no error finding contact for customer after first login') | ||
assert.deepEqual(contact1.email, user1Authentication1.email, 'customer contact has email from authentication after first login') | ||
assert.deepEqual(contact1.name, githubUserOauth1.userInfo.name, 'customer contact has name from userLoginPost request body after first login') | ||
|
||
// now we're going to make the same request again, logging in to that user, but with a new email and name | ||
// create the user | ||
const { id } = await env.db.upsertUser({ | ||
...user1Authentication1, | ||
name: githubUserOauth1.userInfo.name | ||
}) | ||
// create the customer for the user | ||
const customer1 = await env.customers.getOrCreateForUser( | ||
{ id }, | ||
{ email: user1Authentication1.email, name: githubUserOauth1.userInfo.name } | ||
) | ||
|
||
const name2 = { | ||
emailLocalName: 'user1+2', | ||
formatted: 'User 1+2' | ||
|