Skip to content

Commit 9be2634

Browse files
Andrew Farriesroboquat
authored andcommitted
Add getStripePortalUrl method to server
1 parent 015987a commit 9be2634

File tree

5 files changed

+54
-0
lines changed

5 files changed

+54
-0
lines changed

components/gitpod-protocol/src/gitpod-service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
295295
createOrUpdateStripeCustomerForTeam(teamId: string, currency: string): Promise<void>;
296296
createOrUpdateStripeCustomerForUser(currency: string): Promise<void>;
297297
subscribeTeamToStripe(teamId: string, setupIntentId: string): Promise<void>;
298+
getStripePortalUrl(attributionId: string): Promise<string>;
298299
getStripePortalUrlForTeam(teamId: string): Promise<string>;
299300
getUsageLimitForTeam(teamId: string): Promise<number | undefined>;
300301
setUsageLimitForTeam(teamId: string, spendingLimit: number): Promise<void>;

components/server/ee/src/user/stripe-service.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,18 @@ export class StripeService {
130130
return session.url;
131131
}
132132

133+
async getPortalUrlForUser(user: User): Promise<string> {
134+
const customer = await this.findCustomerByUserId(user.id);
135+
if (!customer) {
136+
throw new Error(`No Stripe Customer ID found for user '${user.id}'`);
137+
}
138+
const session = await this.getStripe().billingPortal.sessions.create({
139+
customer: customer.id,
140+
return_url: this.config.hostUrl.with(() => ({ pathname: `/billing` })).toString(),
141+
});
142+
return session.url;
143+
}
144+
133145
async findUncancelledSubscriptionByCustomer(customerId: string): Promise<Stripe.Subscription | undefined> {
134146
const result = await this.getStripe().subscriptions.list({
135147
customer: customerId,

components/server/ee/src/workspace/gitpod-server-impl.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,6 +2150,43 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
21502150
}
21512151
}
21522152

2153+
async getStripePortalUrl(ctx: TraceContext, attributionId: string): Promise<string> {
2154+
const attrId = AttributionId.parse(attributionId);
2155+
if (attrId === undefined) {
2156+
log.error(`Invalid attribution id: ${attributionId}`);
2157+
throw new ResponseError(ErrorCodes.BAD_REQUEST, `Invalid attibution id: ${attributionId}`);
2158+
}
2159+
2160+
const user = this.checkAndBlockUser("getStripePortalUrl");
2161+
2162+
let url: string;
2163+
if (attrId.kind === "user") {
2164+
await this.ensureStripeApiIsAllowed({ user });
2165+
try {
2166+
url = await this.stripeService.getPortalUrlForUser(user);
2167+
} catch (error) {
2168+
log.error(`Failed to get Stripe portal URL for user '${user.id}'`, error);
2169+
throw new ResponseError(
2170+
ErrorCodes.INTERNAL_SERVER_ERROR,
2171+
`Failed to get Stripe portal URL for user '${user.id}'`,
2172+
);
2173+
}
2174+
} else {
2175+
const team = await this.guardTeamOperation(attrId.teamId, "update");
2176+
await this.ensureStripeApiIsAllowed({ team });
2177+
try {
2178+
url = await this.stripeService.getPortalUrlForTeam(team);
2179+
} catch (error) {
2180+
log.error(`Failed to get Stripe portal URL for team '${team.id}'`, error);
2181+
throw new ResponseError(
2182+
ErrorCodes.INTERNAL_SERVER_ERROR,
2183+
`Failed to get Stripe portal URL for team '${team.id}'`,
2184+
);
2185+
}
2186+
}
2187+
return url;
2188+
}
2189+
21532190
async getStripePortalUrlForTeam(ctx: TraceContext, teamId: string): Promise<string> {
21542191
this.checkAndBlockUser("getStripePortalUrlForTeam");
21552192
const team = await this.guardTeamOperation(teamId, "update");

components/server/src/auth/rate-limiter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ const defaultFunctions: FunctionsConfig = {
211211
createOrUpdateStripeCustomerForTeam: { group: "default", points: 1 },
212212
createOrUpdateStripeCustomerForUser: { group: "default", points: 1 },
213213
subscribeTeamToStripe: { group: "default", points: 1 },
214+
getStripePortalUrl: { group: "default", points: 1 },
214215
getStripePortalUrlForTeam: { group: "default", points: 1 },
215216
listUsage: { group: "default", points: 1 },
216217
getBillingModeForTeam: { group: "default", points: 1 },

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3236,6 +3236,9 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
32363236
async getStripePortalUrlForTeam(ctx: TraceContext, teamId: string): Promise<string> {
32373237
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
32383238
}
3239+
async getStripePortalUrl(ctx: TraceContext, attributionId: string): Promise<string> {
3240+
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
3241+
}
32393242

32403243
async listUsage(ctx: TraceContext, req: ListUsageRequest): Promise<ListUsageResponse> {
32413244
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);

0 commit comments

Comments
 (0)