Skip to content

Commit e90ca11

Browse files
committed
[api, server, dashboard] Cleanup UpdateOrganizationSettings API
Tool: gitpod/catfood.gitpod.cloud
1 parent 0e2cafa commit e90ca11

File tree

14 files changed

+1126
-922
lines changed

14 files changed

+1126
-922
lines changed

components/dashboard/src/data/organizations/update-org-settings-mutation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const useUpdateOrgSettingsMutation = () => {
2828

2929
return useMutation<OrganizationSettings, Error, UpdateOrganizationSettingsArgs>({
3030
mutationFn: async (partialUpdate) => {
31-
const update: PartialMessage<UpdateOrganizationSettingsRequest> = {
31+
const update: UpdateOrganizationSettingsArgs = {
3232
...partialUpdate,
3333
};
3434
update.organizationId = organizationId;

components/dashboard/src/service/json-rpc-organization-client.ts

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { PartialMessage } from "@bufbuild/protobuf";
7+
import { PartialMessage, PlainMessage } from "@bufbuild/protobuf";
88
import { CallOptions, PromiseClient } from "@connectrpc/connect";
99
import { OrganizationService } from "@gitpod/public-api/lib/gitpod/v1/organization_connect";
1010
import {
@@ -41,7 +41,6 @@ import {
4141
import { getGitpodService } from "./service";
4242
import { converter } from "./public-api";
4343
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
44-
import { OrgMemberRole, RoleRestrictions } from "@gitpod/gitpod-protocol";
4544

4645
export class JsonRpcOrganizationClient implements PromiseClient<typeof OrganizationService> {
4746
async createOrganization(
@@ -228,56 +227,62 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
228227
if (!request.organizationId) {
229228
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
230229
}
231-
const update: Partial<OrganizationSettings> = {
232-
workspaceSharingDisabled: request?.workspaceSharingDisabled,
233-
defaultWorkspaceImage: request?.defaultWorkspaceImage,
234-
allowedWorkspaceClasses: request?.allowedWorkspaceClasses,
235-
restrictedEditorNames: request?.restrictedEditorNames,
236-
defaultRole: request?.defaultRole,
237-
};
238-
if (request.updatePinnedEditorVersions) {
239-
update.pinnedEditorVersions = request.pinnedEditorVersions;
240-
} else if (request.pinnedEditorVersions && Object.keys(request.pinnedEditorVersions).length > 0) {
230+
231+
if (
232+
request.restrictedEditorNames &&
233+
request.restrictedEditorNames.length > 0 &&
234+
!request.updateRestrictedEditorNames
235+
) {
241236
throw new ApplicationError(
242237
ErrorCodes.BAD_REQUEST,
243-
"updatePinnedEditorVersions is required to be true to update pinnedEditorVersions",
238+
"updateRestrictedEditorNames is required to be true to update restrictedEditorNames",
244239
);
245240
}
246-
if (request.updateRestrictedEditorNames) {
247-
update.restrictedEditorNames = request.restrictedEditorNames;
248-
} else if (request.restrictedEditorNames && request.restrictedEditorNames.length > 0) {
241+
242+
if (
243+
request.allowedWorkspaceClasses &&
244+
request.allowedWorkspaceClasses.length > 0 &&
245+
!request.updateAllowedWorkspaceClasses
246+
) {
249247
throw new ApplicationError(
250248
ErrorCodes.BAD_REQUEST,
251-
"updateRestrictedEditorNames is required to be true to update restrictedEditorNames",
249+
"updateAllowedWorkspaceClasses is required to be true to update allowedWorkspaceClasses",
252250
);
253251
}
254-
const roleRestrictions: RoleRestrictions = {};
255-
if (request.updateRoleRestrictions) {
256-
for (const roleRestriction of request?.roleRestrictions ?? []) {
257-
if (!roleRestriction.role) {
258-
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "role is required");
259-
}
260-
const role = converter.fromOrgMemberRole(roleRestriction.role);
261-
const permissions = roleRestriction?.permissions?.map((p) => converter.fromOrganizationPermission(p));
262252

263-
roleRestrictions[role] = permissions;
264-
}
265-
} else if (request.roleRestrictions && Object.keys(request.roleRestrictions).length > 0) {
253+
if (
254+
request.pinnedEditorVersions &&
255+
Object.keys(request.pinnedEditorVersions).length > 0 &&
256+
!request.updatePinnedEditorVersions
257+
) {
266258
throw new ApplicationError(
267259
ErrorCodes.BAD_REQUEST,
268-
"updateRoleRestrictions is required to be true to update roleRestrictions",
260+
"updatePinnedEditorVersions is required to be true to update pinnedEditorVersions",
269261
);
270262
}
271263

272-
await getGitpodService().server.updateOrgSettings(request.organizationId, {
273-
...update,
274-
defaultRole: request.defaultRole as OrgMemberRole,
275-
timeoutSettings: {
276-
inactivity: converter.toDurationStringOpt(request.timeoutSettings?.inactivity),
277-
denyUserTimeouts: request.timeoutSettings?.denyUserTimeouts,
278-
},
279-
roleRestrictions,
280-
});
264+
if (request.roleRestrictions && request.roleRestrictions.length > 0 && !request.updateRoleRestrictions) {
265+
throw new ApplicationError(
266+
ErrorCodes.BAD_REQUEST,
267+
"updateRoleRestrictions is required to be true when updating roleRestrictions",
268+
);
269+
}
270+
if (
271+
request.onboardingSettings?.recommendedRepositories &&
272+
request.onboardingSettings.recommendedRepositories.length > 0 &&
273+
!request.onboardingSettings.updateRecommendedRepositories
274+
) {
275+
throw new ApplicationError(
276+
ErrorCodes.BAD_REQUEST,
277+
"recommendedRepositories can only be set when updateRecommendedRepositories is true",
278+
);
279+
}
280+
281+
// gpl: We accept the little bit of uncertainty here because a) the partial/not-partial mismatch is only about
282+
// technical/private fields and b) this path should not be exercised anymore anyway.
283+
const update = converter.fromOrganizationSettings(request as PlainMessage<OrganizationSettings>);
284+
285+
await getGitpodService().server.updateOrgSettings(request.organizationId, update);
281286
return new UpdateOrganizationSettingsResponse();
282287
}
283288
}

components/dashboard/src/teams/TeamOnboarding.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ export default function TeamOnboardingPage() {
5454
}
5555
try {
5656
await updateTeamSettings.mutateAsync({
57-
...settings,
5857
...newSettings,
5958
});
6059
toast("Organization settings updated");
@@ -66,7 +65,7 @@ export default function TeamOnboardingPage() {
6665
console.error(error);
6766
}
6867
},
69-
[updateTeamSettings, org?.id, isOwner, settings, toast],
68+
[updateTeamSettings, org?.id, isOwner, toast],
7069
);
7170

7271
const handleUpdateInternalLink = useCallback(

components/gitpod-db/src/typeorm/entity/db-team-settings.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,34 +25,34 @@ export class DBOrgSettings implements OrganizationSettings {
2525
workspaceSharingDisabled?: boolean;
2626

2727
@Column("varchar", { nullable: true })
28-
defaultWorkspaceImage?: string | null;
28+
defaultWorkspaceImage?: string;
2929

3030
@Column("json", { nullable: true })
31-
allowedWorkspaceClasses?: string[] | null;
31+
allowedWorkspaceClasses?: string[];
3232

3333
@Column("json", { nullable: true })
34-
pinnedEditorVersions?: { [key: string]: string } | null;
34+
pinnedEditorVersions?: { [key: string]: string };
3535

3636
@Column("json", { nullable: true })
37-
restrictedEditorNames?: string[] | null;
37+
restrictedEditorNames?: string[];
3838

3939
@Column("varchar", { nullable: true })
40-
defaultRole?: OrgMemberRole | undefined;
40+
defaultRole?: OrgMemberRole;
4141

4242
@Column("json", { nullable: true })
43-
timeoutSettings?: TimeoutSettings | undefined;
43+
timeoutSettings?: TimeoutSettings;
4444

4545
@Column("json", { nullable: true })
46-
roleRestrictions?: RoleRestrictions | undefined;
46+
roleRestrictions?: RoleRestrictions;
4747

4848
@Column({ type: "int", default: 0 })
4949
maxParallelRunningWorkspaces: number;
5050

5151
@Column("json", { nullable: true })
52-
onboardingSettings?: OnboardingSettings | undefined;
52+
onboardingSettings?: OnboardingSettings;
5353

5454
@Column({ type: "boolean", default: false })
55-
annotateGitCommits?: boolean | undefined;
55+
annotateGitCommits?: boolean;
5656

5757
@Column()
5858
deleted: boolean;

components/gitpod-protocol/src/teams-projects-protocol.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,15 @@ export interface Organization {
221221

222222
export interface OrganizationSettings {
223223
workspaceSharingDisabled?: boolean;
224-
// null or empty string to reset to default
225-
defaultWorkspaceImage?: string | null;
224+
// undefined or empty string to reset to default
225+
defaultWorkspaceImage?: string;
226226

227227
// empty array to allow all kind of workspace classes
228-
allowedWorkspaceClasses?: string[] | null;
228+
allowedWorkspaceClasses?: string[];
229229

230-
pinnedEditorVersions?: { [key: string]: string } | null;
230+
pinnedEditorVersions?: { [key: string]: string };
231231

232-
restrictedEditorNames?: string[] | null;
232+
restrictedEditorNames?: string[];
233233

234234
// what role new members will get, default is "member"
235235
defaultRole?: OrgMemberRole;

components/public-api/gitpod/v1/organization.proto

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,22 @@ message OnboardingSettings {
8585
optional WelcomeMessage welcome_message = 4;
8686
}
8787

88+
// KEEP ALIGNED WITH OrganizationSettings shape below!!!
8889
message OrganizationSettings {
89-
bool workspace_sharing_disabled = 1;
90-
string default_workspace_image = 2;
90+
optional bool workspace_sharing_disabled = 1;
91+
optional string default_workspace_image = 2;
9192
repeated string allowed_workspace_classes = 3;
9293
repeated string restricted_editor_names = 4;
9394
map<string, string> pinned_editor_versions = 5;
94-
string default_role = 6;
95-
TimeoutSettings timeout_settings = 7;
95+
optional string default_role = 6;
96+
optional TimeoutSettings timeout_settings = 7;
9697
repeated RoleRestrictionEntry role_restrictions = 8;
9798
// max_parallel_running_workspaces is the maximum number of workspaces that a
9899
// single user can run in parallel. 0 resets to the default, which depends on
99100
// the org plan
100-
int32 max_parallel_running_workspaces = 9;
101-
OnboardingSettings onboarding_settings = 10;
102-
bool annotate_git_commits = 11;
101+
optional int32 max_parallel_running_workspaces = 9;
102+
optional OnboardingSettings onboarding_settings = 10;
103+
optional bool annotate_git_commits = 11;
103104
}
104105

105106
service OrganizationService {

0 commit comments

Comments
 (0)