Skip to content

Commit 435c2bb

Browse files
geroplsvenefftinge
authored andcommitted
[server] Cleanup around EntitlementService and BillingMode
1 parent b17895c commit 435c2bb

File tree

9 files changed

+99
-145
lines changed

9 files changed

+99
-145
lines changed

components/dashboard/src/service/service-mock.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
import { createServiceMock, Event, Project, Team, User } from "@gitpod/gitpod-protocol";
8-
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
98

109
const u1: User = {
1110
id: "1234",
@@ -254,9 +253,6 @@ const gitpodServiceMock = createServiceMock({
254253
},
255254
};
256255
},
257-
getBillingModeForUser: async () => {
258-
return BillingMode.NONE;
259-
},
260256
});
261257

262258
export { gitpodServiceMock };

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
236236

237237
listUsage(req: ListUsageRequest): Promise<ListUsageResponse>;
238238

239-
getBillingModeForUser(): Promise<BillingMode>;
240239
getBillingModeForTeam(teamId: string): Promise<BillingMode>;
241240

242241
getLinkedInClientId(): Promise<string>;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ const defaultFunctions: FunctionsConfig = {
177177
getPriceInformation: { group: "default", points: 1 },
178178
listUsage: { group: "default", points: 1 },
179179
getBillingModeForTeam: { group: "default", points: 1 },
180-
getBillingModeForUser: { group: "default", points: 1 },
181180
getLinkedInClientId: { group: "default", points: 1 },
182181
connectWithLinkedIn: { group: "default", points: 1 },
183182

components/server/src/billing/billing-mode.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import { inject, injectable } from "inversify";
88

9-
import { User } from "@gitpod/gitpod-protocol";
109
import { Config } from "../config";
1110
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
1211
import { CostCenter_BillingStrategy } from "@gitpod/usage-api/lib/usage/v1/usage.pb";
@@ -22,7 +21,7 @@ export class BillingModes {
2221
@inject(UsageService) private readonly usageService: UsageService,
2322
) {}
2423

25-
public async getBillingMode(userId: string, organizationId: string, now: Date): Promise<BillingMode> {
24+
public async getBillingMode(userId: string, organizationId: string): Promise<BillingMode> {
2625
if (!this.config.enablePayment) {
2726
// Payment is not enabled. E.g. Dedicated
2827
return { mode: "none" };
@@ -33,7 +32,11 @@ export class BillingModes {
3332
return { mode: "usage-based", paid };
3433
}
3534

36-
async getBillingModeForUser(user: User, now: Date): Promise<BillingMode> {
35+
/**
36+
* @deprecated use getBillingMode(userId, organizationId) instead
37+
* @returns
38+
*/
39+
async getBillingModeForUser(): Promise<BillingMode> {
3740
if (!this.config.enablePayment) {
3841
// Payment is not enabled. E.g. Self-Hosted.
3942
return { mode: "none" };

components/server/src/billing/entitlement-service-ubp.ts

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66

77
import { TeamDB } from "@gitpod/gitpod-db/lib";
88
import {
9-
BillingTier,
10-
Team,
11-
User,
129
WorkspaceInstance,
1310
WorkspaceTimeoutDuration,
1411
WORKSPACE_TIMEOUT_DEFAULT_LONG,
1512
WORKSPACE_TIMEOUT_DEFAULT_SHORT,
1613
WORKSPACE_LIFETIME_LONG,
1714
WORKSPACE_LIFETIME_SHORT,
15+
User,
16+
BillingTier,
17+
Team,
1818
} from "@gitpod/gitpod-protocol";
1919
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
2020
import { inject, injectable } from "inversify";
@@ -38,11 +38,10 @@ export class EntitlementServiceUBP implements EntitlementService {
3838
async mayStartWorkspace(
3939
user: User,
4040
organizationId: string,
41-
date: Date,
4241
runningInstances: Promise<WorkspaceInstance[]>,
4342
): Promise<MayStartWorkspaceResult> {
4443
const hasHitParallelWorkspaceLimit = async (): Promise<HitParallelWorkspaceLimit | undefined> => {
45-
const max = await this.getMaxParallelWorkspaces(user, date);
44+
const max = await this.getMaxParallelWorkspaces(user.id, organizationId);
4645
const current = (await runningInstances).filter((i) => i.status.phase !== "preparing").length;
4746
if (current >= max) {
4847
return {
@@ -54,7 +53,7 @@ export class EntitlementServiceUBP implements EntitlementService {
5453
}
5554
};
5655
const [usageLimitReachedOnCostCenter, hitParallelWorkspaceLimit] = await Promise.all([
57-
this.checkUsageLimitReached(user, organizationId, date),
56+
this.checkUsageLimitReached(user.id, organizationId),
5857
hasHitParallelWorkspaceLimit(),
5958
]);
6059
return {
@@ -63,69 +62,63 @@ export class EntitlementServiceUBP implements EntitlementService {
6362
};
6463
}
6564

66-
private async checkUsageLimitReached(
67-
user: User,
68-
organizationId: string,
69-
date: Date,
70-
): Promise<AttributionId | undefined> {
71-
const result = await this.usageService.checkUsageLimitReached(user.id, organizationId);
65+
private async checkUsageLimitReached(userId: string, organizationId: string): Promise<AttributionId | undefined> {
66+
const result = await this.usageService.checkUsageLimitReached(userId, organizationId);
7267
if (result.reached) {
7368
return result.attributionId;
7469
}
7570
return undefined;
7671
}
7772

78-
private async getMaxParallelWorkspaces(user: User, date: Date): Promise<number> {
79-
if (await this.hasPaidSubscription(user, date)) {
73+
private async getMaxParallelWorkspaces(userId: string, organizationId: string): Promise<number> {
74+
if (await this.hasPaidSubscription(userId, organizationId)) {
8075
return MAX_PARALLEL_WORKSPACES_PAID;
8176
} else {
8277
return MAX_PARALLEL_WORKSPACES_FREE;
8378
}
8479
}
8580

86-
async maySetTimeout(user: User, date: Date): Promise<boolean> {
87-
return this.hasPaidSubscription(user, date);
81+
async maySetTimeout(userId: string, organizationId?: string): Promise<boolean> {
82+
return this.hasPaidSubscription(userId, organizationId);
8883
}
8984

90-
async getDefaultWorkspaceTimeout(user: User, date: Date): Promise<WorkspaceTimeoutDuration> {
91-
if (await this.hasPaidSubscription(user, date)) {
85+
async getDefaultWorkspaceTimeout(userId: string, organizationId: string): Promise<WorkspaceTimeoutDuration> {
86+
if (await this.hasPaidSubscription(userId, organizationId)) {
9287
return WORKSPACE_TIMEOUT_DEFAULT_LONG;
9388
} else {
9489
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
9590
}
9691
}
9792

98-
async getDefaultWorkspaceLifetime(user: User, date: Date): Promise<WorkspaceTimeoutDuration> {
99-
if (await this.hasPaidSubscription(user, date)) {
93+
async getDefaultWorkspaceLifetime(userId: string, organizationId: string): Promise<WorkspaceTimeoutDuration> {
94+
if (await this.hasPaidSubscription(userId, organizationId)) {
10095
return WORKSPACE_LIFETIME_LONG;
10196
} else {
10297
return WORKSPACE_LIFETIME_SHORT;
10398
}
10499
}
105100

106-
/**
107-
* DEPRECATED: With usage-based billing, users can choose exactly how many resources they want to get.
108-
* Thus, we no longer need to "force" extra resources via the `userGetsMoreResources` mechanism.
109-
*/
110-
async userGetsMoreResources(user: User, date: Date = new Date()): Promise<boolean> {
111-
return false;
112-
}
113-
114101
/**
115102
* Returns true if network connections should be limited
116103
* @param user
117104
*/
118-
async limitNetworkConnections(user: User, date: Date): Promise<boolean> {
105+
async limitNetworkConnections(userId: string, organizationId: string): Promise<boolean> {
119106
// gpl: Because with the current payment handling (pay-after-use) having a "paid" plan is not a good enough classifier for trushworthyness atm.
120107
// We're looking into improving this, but for the meantime we limit network connections for everybody to reduce the impact of abuse.
121108
return true;
122109
}
123110

124-
private async hasPaidSubscription(user: User, date: Date): Promise<boolean> {
111+
private async hasPaidSubscription(userId: string, organizationId?: string): Promise<boolean> {
112+
if (organizationId) {
113+
// This is the "stricter", more correct version: We only allow privileges on the Organization that is paying for it
114+
const { billingStrategy } = await this.usageService.getCostCenter(userId, organizationId);
115+
return billingStrategy === CostCenter_BillingStrategy.BILLING_STRATEGY_STRIPE;
116+
}
117+
// This is the old behavior, stemming from our transition to PAYF, where our API did-/doesn't pass organizationId, yet
125118
// Member of paid team?
126-
const teams = await this.teamDB.findTeamsByUser(user.id);
119+
const teams = await this.teamDB.findTeamsByUser(userId);
127120
const isTeamSubscribedPromises = teams.map(async (team: Team) => {
128-
const { billingStrategy } = await this.usageService.getCostCenter(user.id, team.id);
121+
const { billingStrategy } = await this.usageService.getCostCenter(userId, team.id);
129122
return billingStrategy === CostCenter_BillingStrategy.BILLING_STRATEGY_STRIPE;
130123
});
131124
// Return the first truthy promise, or false if all the promises were falsy.
@@ -147,8 +140,8 @@ export class EntitlementServiceUBP implements EntitlementService {
147140
});
148141
}
149142

150-
async getBillingTier(user: User): Promise<BillingTier> {
151-
const hasPaidPlan = await this.hasPaidSubscription(user, new Date());
143+
async getBillingTier(userId: string, organizationId: string): Promise<BillingTier> {
144+
const hasPaidPlan = await this.hasPaidSubscription(userId, organizationId);
152145
return hasPaidPlan ? "paid" : "free";
153146
}
154147
}

0 commit comments

Comments
 (0)