Skip to content

Commit

Permalink
Add subscribeToStripe server method
Browse files Browse the repository at this point in the history
Generalize the `subscribeTeamToStripe` method so that it works for user
attribution ids too.

Implement the `subscribeTeamToStripe` method in terms of the new general
method.
  • Loading branch information
Andrew Farries committed Sep 13, 2022
1 parent 752210b commit 4b2e3e2
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 13 deletions.
1 change: 1 addition & 0 deletions components/gitpod-protocol/src/gitpod-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
findStripeSubscriptionIdForTeam(teamId: string): Promise<string | undefined>;
createOrUpdateStripeCustomerForTeam(teamId: string, currency: string): Promise<void>;
createOrUpdateStripeCustomerForUser(currency: string): Promise<void>;
subscribeToStripe(attributionId: string, setupIntentId: string): Promise<void>;
subscribeTeamToStripe(teamId: string, setupIntentId: string): Promise<void>;
getStripePortalUrl(attributionId: string): Promise<string>;
getStripePortalUrlForTeam(teamId: string): Promise<string>;
Expand Down
44 changes: 31 additions & 13 deletions components/server/ee/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2124,32 +2124,50 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
}

protected defaultSpendingLimit = 100;
async subscribeTeamToStripe(ctx: TraceContext, teamId: string, setupIntentId: string): Promise<void> {
this.checkAndBlockUser("subscribeTeamToStripe");
const team = await this.guardTeamOperation(teamId, "update");
await this.ensureStripeApiIsAllowed({ team });
async subscribeToStripe(ctx: TraceContext, attributionId: string, setupIntentId: string): Promise<void> {
const attrId = AttributionId.parse(attributionId);
if (attrId === undefined) {
log.error(`Invalid attribution id: ${attributionId}`);
throw new ResponseError(ErrorCodes.BAD_REQUEST, `Invalid attibution id: ${attributionId}`);
}

const user = this.checkAndBlockUser("subscribeToStripe");

let customer: Stripe.Customer | undefined;
try {
let customer = await this.stripeService.findCustomerByTeamId(team!.id);
if (attrId.kind === "team") {
const team = await this.guardTeamOperation(attrId.teamId, "update");
await this.ensureStripeApiIsAllowed({ team });
customer = await this.stripeService.findCustomerByTeamId(team!.id);
} else {
await this.ensureStripeApiIsAllowed({ user });
customer = await this.stripeService.findCustomerByUserId(user.id);
}
if (!customer) {
throw new Error(`No Stripe customer profile for team '${team.id}'`);
throw new Error(`No Stripe customer profile for '${attributionId}'`);
}

await this.stripeService.setDefaultPaymentMethodForCustomer(customer, setupIntentId);
await this.stripeService.createSubscriptionForCustomer(customer);

const attributionId: AttributionId = { kind: "team", teamId };

// Creating a cost center for this team
await this.usageServiceClientProvider.getDefault().setCostCenter({
id: attributionId,
id: attrId,
spendingLimit: this.defaultSpendingLimit,
billingStrategy: "stripe",
});
} catch (error) {
log.error(`Failed to subscribe team '${teamId}' to Stripe`, error);
throw new ResponseError(ErrorCodes.INTERNAL_SERVER_ERROR, `Failed to subscribe team '${teamId}' to Stripe`);
log.error(`Failed to subscribe '${attributionId}' to Stripe`, error);
throw new ResponseError(
ErrorCodes.INTERNAL_SERVER_ERROR,
`Failed to subscribe '${attributionId}' to Stripe`,
);
}
}

async subscribeTeamToStripe(ctx: TraceContext, teamId: string, setupIntentId: string): Promise<void> {
const attributionId: AttributionId = { kind: "team", teamId: teamId };
return this.subscribeToStripe(ctx, AttributionId.render(attributionId), setupIntentId);
}

async getStripePortalUrl(ctx: TraceContext, attributionId: string): Promise<string> {
const attrId = AttributionId.parse(attributionId);
if (attrId === undefined) {
Expand Down
1 change: 1 addition & 0 deletions components/server/src/auth/rate-limiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ const defaultFunctions: FunctionsConfig = {
findStripeSubscriptionIdForTeam: { group: "default", points: 1 },
createOrUpdateStripeCustomerForTeam: { group: "default", points: 1 },
createOrUpdateStripeCustomerForUser: { group: "default", points: 1 },
subscribeToStripe: { group: "default", points: 1 },
subscribeTeamToStripe: { group: "default", points: 1 },
getStripePortalUrl: { group: "default", points: 1 },
getStripePortalUrlForTeam: { group: "default", points: 1 },
Expand Down
3 changes: 3 additions & 0 deletions components/server/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3233,6 +3233,9 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
async subscribeTeamToStripe(ctx: TraceContext, teamId: string, setupIntentId: string): Promise<void> {
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
}
async subscribeToStripe(ctx: TraceContext, attributionId: string, setupIntentId: string): Promise<void> {
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
}
async getStripePortalUrlForTeam(ctx: TraceContext, teamId: string): Promise<string> {
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
}
Expand Down

0 comments on commit 4b2e3e2

Please sign in to comment.