Skip to content

Commit d7fbf86

Browse files
author
Andrew Farries
committed
Add getUsageLimitFor and setUsageLimitFor
Add two new methods to the server API for getting and setting usage limits. Both new functions take an attributionId and work for both users and teams. For backwards compatibility, leave the `getUsageLimitForTeam` and `setUsageLimitForTeam` methods as they are still used by the dashboard, but change them to be implemented in terms of the more general `get/set` methods.
1 parent 7a0efe9 commit d7fbf86

File tree

4 files changed

+58
-17
lines changed

4 files changed

+58
-17
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
295295
createOrUpdateStripeCustomerForUser(currency: string): Promise<void>;
296296
subscribeTeamToStripe(teamId: string, setupIntentId: string): Promise<void>;
297297
getStripePortalUrlForTeam(teamId: string): Promise<string>;
298+
getUsageLimit(attributionId: string): Promise<number | undefined>;
299+
setUsageLimit(attributionId: string, usageLimit: number): Promise<void>;
298300
getUsageLimitForTeam(teamId: string): Promise<number | undefined>;
299301
setUsageLimitForTeam(teamId: string, spendingLimit: number): Promise<void>;
300302

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

+46-17
Original file line numberDiff line numberDiff line change
@@ -2146,35 +2146,64 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
21462146
}
21472147
}
21482148

2149-
async getUsageLimitForTeam(ctx: TraceContext, teamId: string): Promise<number | undefined> {
2150-
const user = this.checkAndBlockUser("getUsageLimitForTeam");
2151-
const team = await this.guardTeamOperation(teamId, "get");
2152-
await this.ensureStripeApiIsAllowed({ team });
2149+
async getUsageLimit(ctx: TraceContext, attributionId: string): Promise<number | undefined> {
2150+
const attrId = AttributionId.parse(attributionId);
2151+
if (attrId === undefined) {
2152+
log.error(`Invalid attribution id: ${attributionId}`);
2153+
throw new ResponseError(ErrorCodes.BAD_REQUEST, `Invalid attibution id: ${attributionId}`);
2154+
}
21532155

2154-
const attributionId = AttributionId.render({ kind: "team", teamId });
2156+
const user = this.checkAndBlockUser("getUsageLimit");
2157+
switch (attrId.kind) {
2158+
case "team":
2159+
const team = await this.guardTeamOperation(attrId.teamId, "get");
2160+
await this.ensureStripeApiIsAllowed({ team });
2161+
break;
2162+
case "user":
2163+
await this.ensureStripeApiIsAllowed({ user });
2164+
break;
2165+
}
21552166
await this.guardCostCenterAccess(ctx, user.id, attributionId, "get");
2156-
21572167
const costCenter = await this.costCenterDB.findById(attributionId);
21582168
if (costCenter) {
21592169
return costCenter.spendingLimit;
21602170
}
21612171
return undefined;
21622172
}
21632173

2164-
async setUsageLimitForTeam(ctx: TraceContext, teamId: string, usageLimit: number): Promise<void> {
2165-
const user = this.checkAndBlockUser("setUsageLimitForTeam");
2166-
const team = await this.guardTeamOperation(teamId, "update");
2167-
await this.ensureStripeApiIsAllowed({ team });
2174+
async setUsageLimit(ctx: TraceContext, attributionId: string, usageLimit: number): Promise<void> {
2175+
const attrId = AttributionId.parse(attributionId);
2176+
if (attrId === undefined) {
2177+
log.error(`Invalid attribution id: ${attributionId}`);
2178+
throw new ResponseError(ErrorCodes.BAD_REQUEST, `Invalid attibution id: ${attributionId}`);
2179+
}
21682180
if (typeof usageLimit !== "number" || usageLimit < 0) {
2169-
throw new ResponseError(ErrorCodes.BAD_REQUEST, "Unexpected `usageLimit` value.");
2181+
throw new ResponseError(ErrorCodes.BAD_REQUEST, `Unexpected usageLimit value: ${usageLimit}`);
21702182
}
2171-
const attributionId = AttributionId.render({ kind: "team", teamId });
2172-
await this.guardCostCenterAccess(ctx, user.id, attributionId, "update");
21732183

2174-
await this.costCenterDB.storeEntry({
2175-
id: AttributionId.render({ kind: "team", teamId }),
2176-
spendingLimit: usageLimit,
2177-
});
2184+
const user = this.checkAndBlockUser("setUsageLimit");
2185+
switch (attrId.kind) {
2186+
case "team":
2187+
const team = await this.guardTeamOperation(attrId.teamId, "get");
2188+
await this.ensureStripeApiIsAllowed({ team });
2189+
break;
2190+
case "user":
2191+
await this.ensureStripeApiIsAllowed({ user });
2192+
break;
2193+
}
2194+
await this.guardCostCenterAccess(ctx, user.id, attributionId, "get");
2195+
await this.costCenterDB.storeEntry({ id: attributionId, spendingLimit: usageLimit });
2196+
}
2197+
2198+
async getUsageLimitForTeam(ctx: TraceContext, teamId: string): Promise<number | undefined> {
2199+
const attributionId: AttributionId = { kind: "team", teamId: teamId };
2200+
2201+
return this.getUsageLimit(ctx, AttributionId.render(attributionId));
2202+
}
2203+
2204+
async setUsageLimitForTeam(ctx: TraceContext, teamId: string, usageLimit: number): Promise<void> {
2205+
const attributionId: AttributionId = { kind: "team", teamId: teamId };
2206+
return this.setUsageLimit(ctx, AttributionId.render(attributionId), usageLimit);
21782207
}
21792208

21802209
async getNotifications(ctx: TraceContext): Promise<string[]> {

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

+2
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ const defaultFunctions: FunctionsConfig = {
220220
getIDEOptions: { group: "default", points: 1 },
221221
getPrebuildEvents: { group: "default", points: 1 },
222222
setUsageAttribution: { group: "default", points: 1 },
223+
getUsageLimit: { group: "default", points: 1 },
224+
setUsageLimit: { group: "default", points: 1 },
223225
getUsageLimitForTeam: { group: "default", points: 1 },
224226
setUsageLimitForTeam: { group: "default", points: 1 },
225227
getNotifications: { group: "default", points: 1 },

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

+8
Original file line numberDiff line numberDiff line change
@@ -3235,6 +3235,14 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
32353235
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
32363236
}
32373237

3238+
async getUsageLimit(ctx: TraceContext, attributionId: string): Promise<number | undefined> {
3239+
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
3240+
}
3241+
3242+
async setUsageLimit(ctx: TraceContext, attributionId: string, usageLimit: number): Promise<void> {
3243+
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
3244+
}
3245+
32383246
async getUsageLimitForTeam(ctx: TraceContext, teamId: string): Promise<number | undefined> {
32393247
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
32403248
}

0 commit comments

Comments
 (0)