Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/service/json-rpc-organization-client.ts
2500 views
1
/**
2
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { PartialMessage, PlainMessage } from "@bufbuild/protobuf";
8
import { CallOptions, PromiseClient } from "@connectrpc/connect";
9
import { OrganizationService } from "@gitpod/public-api/lib/gitpod/v1/organization_connect";
10
import {
11
CreateOrganizationRequest,
12
CreateOrganizationResponse,
13
DeleteOrganizationMemberRequest,
14
DeleteOrganizationMemberResponse,
15
DeleteOrganizationRequest,
16
DeleteOrganizationResponse,
17
GetOrganizationInvitationRequest,
18
GetOrganizationInvitationResponse,
19
GetOrganizationMaintenanceModeRequest,
20
GetOrganizationMaintenanceModeResponse,
21
GetOrganizationRequest,
22
GetOrganizationResponse,
23
GetOrganizationSettingsRequest,
24
GetOrganizationSettingsResponse,
25
GetMaintenanceNotificationRequest,
26
GetMaintenanceNotificationResponse,
27
JoinOrganizationRequest,
28
JoinOrganizationResponse,
29
ListOrganizationMembersRequest,
30
ListOrganizationMembersResponse,
31
ListOrganizationWorkspaceClassesRequest,
32
ListOrganizationWorkspaceClassesResponse,
33
ListOrganizationsRequest,
34
ListOrganizationsResponse,
35
OrganizationSettings,
36
ResetOrganizationInvitationRequest,
37
ResetOrganizationInvitationResponse,
38
SetOrganizationMaintenanceModeRequest,
39
SetOrganizationMaintenanceModeResponse,
40
SetMaintenanceNotificationRequest,
41
SetMaintenanceNotificationResponse,
42
UpdateOrganizationMemberRequest,
43
UpdateOrganizationMemberResponse,
44
UpdateOrganizationRequest,
45
UpdateOrganizationResponse,
46
UpdateOrganizationSettingsRequest,
47
UpdateOrganizationSettingsResponse,
48
} from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
49
import { getGitpodService } from "./service";
50
import { converter } from "./public-api";
51
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
52
53
export class JsonRpcOrganizationClient implements PromiseClient<typeof OrganizationService> {
54
async createOrganization(
55
request: PartialMessage<CreateOrganizationRequest>,
56
options?: CallOptions | undefined,
57
): Promise<CreateOrganizationResponse> {
58
if (!request.name) {
59
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "name is required");
60
}
61
const result = await getGitpodService().server.createTeam(request.name);
62
return new CreateOrganizationResponse({
63
organization: converter.toOrganization(result),
64
});
65
}
66
67
async listOrganizationWorkspaceClasses(
68
request: PartialMessage<ListOrganizationWorkspaceClassesRequest>,
69
options?: CallOptions | undefined,
70
): Promise<ListOrganizationWorkspaceClassesResponse> {
71
if (!request.organizationId) {
72
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
73
}
74
const list = await getGitpodService().server.getOrgWorkspaceClasses(request.organizationId);
75
return new ListOrganizationWorkspaceClassesResponse({
76
workspaceClasses: list.map((e) => converter.toWorkspaceClass(e)),
77
});
78
}
79
80
async getOrganization(
81
request: PartialMessage<GetOrganizationRequest>,
82
options?: CallOptions | undefined,
83
): Promise<GetOrganizationResponse> {
84
if (!request.organizationId) {
85
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "id is required");
86
}
87
const result = await getGitpodService().server.getTeam(request.organizationId);
88
89
return new GetOrganizationResponse({
90
organization: converter.toOrganization(result),
91
});
92
}
93
94
async updateOrganization(
95
request: PartialMessage<UpdateOrganizationRequest>,
96
options?: CallOptions | undefined,
97
): Promise<UpdateOrganizationResponse> {
98
if (!request.organizationId) {
99
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
100
}
101
if (!request.name) {
102
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "name is required");
103
}
104
await getGitpodService().server.updateTeam(request.organizationId, {
105
name: request.name,
106
});
107
return new UpdateOrganizationResponse();
108
}
109
110
async listOrganizations(
111
request: PartialMessage<ListOrganizationsRequest>,
112
options?: CallOptions | undefined,
113
): Promise<ListOrganizationsResponse> {
114
const result = await getGitpodService().server.getTeams();
115
return new ListOrganizationsResponse({
116
organizations: result.map((team) => converter.toOrganization(team)),
117
});
118
}
119
120
async deleteOrganization(
121
request: PartialMessage<DeleteOrganizationRequest>,
122
options?: CallOptions | undefined,
123
): Promise<DeleteOrganizationResponse> {
124
if (!request.organizationId) {
125
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
126
}
127
await getGitpodService().server.deleteTeam(request.organizationId);
128
return new DeleteOrganizationResponse();
129
}
130
131
async getOrganizationInvitation(
132
request: PartialMessage<GetOrganizationInvitationRequest>,
133
options?: CallOptions | undefined,
134
): Promise<GetOrganizationInvitationResponse> {
135
if (!request.organizationId) {
136
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
137
}
138
const result = await getGitpodService().server.getGenericInvite(request.organizationId);
139
return new GetOrganizationInvitationResponse({
140
invitationId: result.id,
141
});
142
}
143
144
async joinOrganization(
145
request: PartialMessage<JoinOrganizationRequest>,
146
options?: CallOptions | undefined,
147
): Promise<JoinOrganizationResponse> {
148
if (!request.invitationId) {
149
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "invitationId is required");
150
}
151
const result = await getGitpodService().server.joinTeam(request.invitationId);
152
return new JoinOrganizationResponse({
153
organizationId: result.id,
154
});
155
}
156
157
async resetOrganizationInvitation(
158
request: PartialMessage<ResetOrganizationInvitationRequest>,
159
options?: CallOptions | undefined,
160
): Promise<ResetOrganizationInvitationResponse> {
161
if (!request.organizationId) {
162
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
163
}
164
const newInvite = await getGitpodService().server.resetGenericInvite(request.organizationId);
165
return new ResetOrganizationInvitationResponse({
166
invitationId: newInvite.id,
167
});
168
}
169
170
async listOrganizationMembers(
171
request: PartialMessage<ListOrganizationMembersRequest>,
172
options?: CallOptions | undefined,
173
): Promise<ListOrganizationMembersResponse> {
174
if (!request.organizationId) {
175
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
176
}
177
const result = await getGitpodService().server.getTeamMembers(request.organizationId);
178
return new ListOrganizationMembersResponse({
179
members: result.map((member) => converter.toOrganizationMember(member)),
180
});
181
}
182
183
async updateOrganizationMember(
184
request: PartialMessage<UpdateOrganizationMemberRequest>,
185
options?: CallOptions | undefined,
186
): Promise<UpdateOrganizationMemberResponse> {
187
if (!request.organizationId) {
188
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
189
}
190
if (!request.userId) {
191
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "userId is required");
192
}
193
if (!request.role) {
194
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "role is required");
195
}
196
await getGitpodService().server.setTeamMemberRole(
197
request.organizationId,
198
request.userId,
199
converter.fromOrgMemberRole(request.role),
200
);
201
return new UpdateOrganizationMemberResponse();
202
}
203
204
async deleteOrganizationMember(
205
request: PartialMessage<DeleteOrganizationMemberRequest>,
206
options?: CallOptions | undefined,
207
): Promise<DeleteOrganizationMemberResponse> {
208
if (!request.organizationId) {
209
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
210
}
211
if (!request.userId) {
212
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "userId is required");
213
}
214
await getGitpodService().server.removeTeamMember(request.organizationId, request.userId);
215
return new DeleteOrganizationMemberResponse();
216
}
217
218
async getOrganizationSettings(
219
request: PartialMessage<GetOrganizationSettingsRequest>,
220
options?: CallOptions | undefined,
221
): Promise<GetOrganizationSettingsResponse> {
222
if (!request.organizationId) {
223
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
224
}
225
const result = await getGitpodService().server.getOrgSettings(request.organizationId);
226
return new GetOrganizationSettingsResponse({
227
settings: converter.toOrganizationSettings(result),
228
});
229
}
230
231
async updateOrganizationSettings(
232
request: PartialMessage<UpdateOrganizationSettingsRequest>,
233
options?: CallOptions | undefined,
234
): Promise<UpdateOrganizationSettingsResponse> {
235
if (!request.organizationId) {
236
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
237
}
238
239
if (
240
request.restrictedEditorNames &&
241
request.restrictedEditorNames.length > 0 &&
242
!request.updateRestrictedEditorNames
243
) {
244
throw new ApplicationError(
245
ErrorCodes.BAD_REQUEST,
246
"updateRestrictedEditorNames is required to be true to update restrictedEditorNames",
247
);
248
}
249
250
if (
251
request.allowedWorkspaceClasses &&
252
request.allowedWorkspaceClasses.length > 0 &&
253
!request.updateAllowedWorkspaceClasses
254
) {
255
throw new ApplicationError(
256
ErrorCodes.BAD_REQUEST,
257
"updateAllowedWorkspaceClasses is required to be true to update allowedWorkspaceClasses",
258
);
259
}
260
261
if (
262
request.pinnedEditorVersions &&
263
Object.keys(request.pinnedEditorVersions).length > 0 &&
264
!request.updatePinnedEditorVersions
265
) {
266
throw new ApplicationError(
267
ErrorCodes.BAD_REQUEST,
268
"updatePinnedEditorVersions is required to be true to update pinnedEditorVersions",
269
);
270
}
271
272
if (request.roleRestrictions && request.roleRestrictions.length > 0 && !request.updateRoleRestrictions) {
273
throw new ApplicationError(
274
ErrorCodes.BAD_REQUEST,
275
"updateRoleRestrictions is required to be true when updating roleRestrictions",
276
);
277
}
278
if (
279
request.onboardingSettings?.recommendedRepositories &&
280
request.onboardingSettings.recommendedRepositories.length > 0 &&
281
!request.onboardingSettings.updateRecommendedRepositories
282
) {
283
throw new ApplicationError(
284
ErrorCodes.BAD_REQUEST,
285
"recommendedRepositories can only be set when updateRecommendedRepositories is true",
286
);
287
}
288
289
// gpl: We accept the little bit of uncertainty here because a) the partial/not-partial mismatch is only about
290
// technical/private fields and b) this path should not be exercised anymore anyway.
291
const update = converter.fromOrganizationSettings(request as PlainMessage<OrganizationSettings>);
292
293
await getGitpodService().server.updateOrgSettings(request.organizationId, update);
294
return new UpdateOrganizationSettingsResponse();
295
}
296
297
async getOrganizationMaintenanceMode(
298
request: PartialMessage<GetOrganizationMaintenanceModeRequest>,
299
options?: CallOptions | undefined,
300
): Promise<GetOrganizationMaintenanceModeResponse> {
301
if (!request.organizationId) {
302
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
303
}
304
const result = await getGitpodService().server.getTeam(request.organizationId);
305
return new GetOrganizationMaintenanceModeResponse({
306
enabled: !!result.maintenanceMode,
307
});
308
}
309
310
async setOrganizationMaintenanceMode(
311
request: PartialMessage<SetOrganizationMaintenanceModeRequest>,
312
options?: CallOptions | undefined,
313
): Promise<SetOrganizationMaintenanceModeResponse> {
314
if (!request.organizationId) {
315
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
316
}
317
const result = await getGitpodService().server.updateTeam(request.organizationId, {
318
maintenanceMode: request.enabled,
319
});
320
return new SetOrganizationMaintenanceModeResponse({
321
enabled: !!result.maintenanceMode,
322
});
323
}
324
325
async getMaintenanceNotification(
326
request: PartialMessage<GetMaintenanceNotificationRequest>,
327
options?: CallOptions | undefined,
328
): Promise<GetMaintenanceNotificationResponse> {
329
if (!request.organizationId) {
330
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
331
}
332
const result = await getGitpodService().server.getTeam(request.organizationId);
333
return new GetMaintenanceNotificationResponse({
334
isEnabled: result.maintenanceNotification?.enabled || false,
335
message: result.maintenanceNotification?.message || "",
336
});
337
}
338
339
async setMaintenanceNotification(
340
request: PartialMessage<SetMaintenanceNotificationRequest>,
341
options?: CallOptions | undefined,
342
): Promise<SetMaintenanceNotificationResponse> {
343
if (!request.organizationId) {
344
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
345
}
346
const result = await getGitpodService().server.updateTeam(request.organizationId, {
347
maintenanceNotification: {
348
enabled: !!request.isEnabled,
349
message: request.customMessage,
350
},
351
});
352
return new SetMaintenanceNotificationResponse({
353
isEnabled: result.maintenanceNotification?.enabled || false,
354
message: result.maintenanceNotification?.message || "",
355
});
356
}
357
}
358
359