Skip to content

Commit

Permalink
feat: optionally require plans for provisioning (#1087)
Browse files Browse the repository at this point in the history
We need this to ship billing, to stop users without a payment provider
plan from provisioning new spaces.

I've added a flag to the `ProviderServiceContext` that lets us disable
this requirement - this is extremely useful in testing and will be
helpful as we roll this feature out - ie, w3infra can disable this
requirement until we are ready to launch.
  • Loading branch information
Travis Vachon authored Nov 7, 2023
1 parent 6418b4b commit b24731b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 4 deletions.
18 changes: 15 additions & 3 deletions packages/upload-api/src/provider-add.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const provide = (ctx) =>
*/
export const add = async (
{ capability, invocation },
{ provisionsStorage: provisions, rateLimitsStorage: rateLimits }
{ provisionsStorage: provisions, rateLimitsStorage: rateLimits, plansStorage, requirePaymentPlan }
) => {
const {
nb: { consumer, provider },
Expand All @@ -40,15 +40,27 @@ export const add = async (
[mailtoDidToDomain(accountMailtoDID), mailtoDidToEmail(accountMailtoDID)],
0
)

if (rateLimitResult.error) {
return {
error: {
name: 'AccountBlocked',
message: `Account identified by ${accountDID} is blocked`,
message: `Account identified by ${accountMailtoDID} is blocked`,
},
}
}

if (requirePaymentPlan) {
const planGetResult = await plansStorage.get(accountMailtoDID)
if (!planGetResult.ok?.product) {
return {
error: {
name: 'AccountPlanMissing',
message: `Account identified by ${accountMailtoDID} has not selected a payment plan`,
},
}
}
}

if (!provisions.services.includes(provider)) {
return {
error: {
Expand Down
2 changes: 2 additions & 0 deletions packages/upload-api/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ export interface SpaceServiceContext {
export interface ProviderServiceContext {
provisionsStorage: Provisions
rateLimitsStorage: RateLimits
plansStorage: PlansStorage
requirePaymentPlan?: boolean
}

export interface SubscriptionServiceContext {
Expand Down
29 changes: 29 additions & 0 deletions packages/upload-api/test/handlers/provider-add.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,35 @@ describe(`provider/add`, () => {
cleanupContext(context)
}
})

it('provider/add fails if plans are required and a plan has not been configured', async () => {
const { space, agent, account, ...context } = await setup({
requirePaymentPlan: true
})
const { service } = context

try {
const proofs = await createAuthorization({ agent, service, account })

const addResult = await Provider.add
.invoke({
issuer: agent,
audience: service,
with: account.did(),
nb: {
provider: 'did:web:web3.storage',
consumer: space.did(),
},
proofs,
})
.execute(context.connection)

assert.ok(addResult.out.error, 'Expected error provisioning without adding a plan')
assert.equal(addResult.out.error.message, `Account identified by ${account.did()} has not selected a payment plan`)
} finally {
cleanupContext(context)
}
})
})

/**
Expand Down
5 changes: 4 additions & 1 deletion packages/upload-api/test/helpers/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import { UsageStorage } from '../storage/usage-storage.js'
/**
* @param {object} options
* @param {string[]} [options.providers]
* @param {boolean} [options.requirePaymentPlan]
* @param {import('http')} [options.http]
* @param {{fail(error:unknown): unknown}} [options.assert]
* @returns {Promise<Types.UcantoServerTestContext>}
*/
export const createContext = async (options = {}) => {
export const createContext = async (options = { requirePaymentPlan: false }) => {
const requirePaymentPlan = options.requirePaymentPlan
const storeTable = new StoreTable()
const uploadTable = new UploadTable()
const carStoreBucket = await CarStoreBucket.activate(options)
Expand Down Expand Up @@ -81,6 +83,7 @@ export const createContext = async (options = {}) => {
pieceStore,
receiptStore,
taskStore,
requirePaymentPlan,
...createRevocationChecker({ revocationsStorage }),
}

Expand Down

0 comments on commit b24731b

Please sign in to comment.