@jskit-ai/users-core 0.1.48 → 0.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.descriptor.mjs +7 -7
- package/package.json +7 -17
- package/src/server/common/services/authProfileSyncService.js +28 -7
- package/src/server/common/support/realtimeServiceEvents.js +1 -59
- package/src/server/profileSyncLifecycleContributorRegistry.js +56 -0
- package/src/server/registerUsersBootstrap.js +0 -1
- package/src/server/registerUsersCore.js +2 -14
- package/src/server/usersBootstrapContributor.js +2 -64
- package/src/shared/index.js +2 -99
- package/src/shared/settings.js +1 -119
- package/test/authProfileSyncService.test.js +19 -10
- package/test/registerServiceRealtimeEvents.test.js +0 -86
- package/test/registerUsersCore.test.js +6 -15
- package/test/repositoryContracts.test.js +1 -9
- package/test/resourcesCanonical.test.js +0 -16
- package/test/settingsFieldRegistriesSingleton.test.js +0 -5
- package/test/usersBootstrapContributor.test.js +2 -26
- package/test/usersRouteResources.test.js +0 -16
- package/src/server/UsersWorkspacesServiceProvider.js +0 -44
- package/src/server/common/contributors/workspaceActionContextContributor.js +0 -88
- package/src/server/common/contributors/workspaceAuthPolicyContextResolver.js +0 -34
- package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +0 -78
- package/src/server/common/formatters/workspaceFormatter.js +0 -53
- package/src/server/common/repositories/workspaceInvitesRepository.js +0 -208
- package/src/server/common/repositories/workspaceMembershipsRepository.js +0 -190
- package/src/server/common/repositories/workspacesRepository.js +0 -202
- package/src/server/common/services/workspaceContextService.js +0 -281
- package/src/server/common/support/workspaceRoutePaths.js +0 -17
- package/src/server/common/validators/routeParamsValidator.js +0 -62
- package/src/server/registerWorkspaceBootstrap.js +0 -27
- package/src/server/registerWorkspaceCore.js +0 -73
- package/src/server/registerWorkspaceRepositories.js +0 -26
- package/src/server/support/resolveWorkspace.js +0 -16
- package/src/server/support/workspaceActionSurfaces.js +0 -118
- package/src/server/support/workspaceInvitationsPolicy.js +0 -45
- package/src/server/support/workspaceRouteInput.js +0 -22
- package/src/server/workspaceBootstrapContributor.js +0 -212
- package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +0 -133
- package/src/server/workspaceDirectory/registerWorkspaceDirectory.js +0 -19
- package/src/server/workspaceDirectory/workspaceDirectoryActions.js +0 -133
- package/src/server/workspaceMembers/bootWorkspaceMembers.js +0 -236
- package/src/server/workspaceMembers/registerWorkspaceMembers.js +0 -108
- package/src/server/workspaceMembers/workspaceMembersActions.js +0 -186
- package/src/server/workspaceMembers/workspaceMembersService.js +0 -222
- package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +0 -62
- package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +0 -119
- package/src/server/workspacePendingInvitations/workspacePendingInvitationsActions.js +0 -74
- package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +0 -138
- package/src/server/workspaceSettings/bootWorkspaceSettings.js +0 -76
- package/src/server/workspaceSettings/registerWorkspaceSettings.js +0 -62
- package/src/server/workspaceSettings/workspaceSettingsActions.js +0 -72
- package/src/server/workspaceSettings/workspaceSettingsRepository.js +0 -154
- package/src/server/workspaceSettings/workspaceSettingsService.js +0 -66
- package/src/shared/resources/workspaceMembersResource.js +0 -354
- package/src/shared/resources/workspacePendingInvitationsResource.js +0 -82
- package/src/shared/resources/workspaceResource.js +0 -176
- package/src/shared/resources/workspaceSettingsFields.js +0 -59
- package/src/shared/resources/workspaceSettingsResource.js +0 -169
- package/src/shared/roles.js +0 -161
- package/src/shared/support/usersApiPaths.js +0 -43
- package/src/shared/support/usersVisibility.js +0 -42
- package/src/shared/support/workspacePathModel.js +0 -145
- package/src/shared/tenancyMode.js +0 -35
- package/src/shared/tenancyProfile.js +0 -73
- package/test/registerWorkspaceDirectory.test.js +0 -31
- package/test/registerWorkspaceSettings.test.js +0 -40
- package/test/roles.test.js +0 -159
- package/test/tenancyProfile.test.js +0 -67
- package/test/usersApiPaths.test.js +0 -49
- package/test/usersRouteValidators.test.js +0 -49
- package/test/usersVisibility.test.js +0 -27
- package/test/workspaceActionContextContributor.test.js +0 -344
- package/test/workspaceActionSurfaces.test.js +0 -85
- package/test/workspaceAuthPolicyContextResolver.test.js +0 -119
- package/test/workspaceBootstrapContributor.test.js +0 -154
- package/test/workspaceInvitationsPolicy.test.js +0 -71
- package/test/workspaceInvitesRepository.test.js +0 -111
- package/test/workspaceMembersService.test.js +0 -398
- package/test/workspacePathModel.test.js +0 -93
- package/test/workspacePendingInvitationsResource.test.js +0 -38
- package/test/workspacePendingInvitationsService.test.js +0 -151
- package/test/workspaceRouteVisibilityResolver.test.js +0 -83
- package/test/workspaceService.test.js +0 -546
- package/test/workspaceSettingsActions.test.js +0 -52
- package/test/workspaceSettingsRepository.test.js +0 -202
- package/test/workspaceSettingsResource.test.js +0 -169
- package/test/workspaceSettingsService.test.js +0 -140
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import "../test-support/registerDefaultSettingsFields.js";
|
|
4
|
-
import { toIsoString } from "@jskit-ai/database-runtime/shared";
|
|
5
|
-
import { resolveWorkspaceThemePalettes } from "../src/shared/settings.js";
|
|
6
|
-
import { createRepository } from "../src/server/workspaceSettings/workspaceSettingsRepository.js";
|
|
7
|
-
|
|
8
|
-
function createDefaultWorkspaceSettings() {
|
|
9
|
-
return true;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const DEFAULT_WORKSPACE_THEME = resolveWorkspaceThemePalettes({});
|
|
13
|
-
const STUB_CREATED_AT = "2026-03-09 00:26:35.710";
|
|
14
|
-
|
|
15
|
-
function createKnexStub(rowOverrides = {}) {
|
|
16
|
-
const state = {
|
|
17
|
-
insertedRow: null,
|
|
18
|
-
updatePayload: null,
|
|
19
|
-
row: {
|
|
20
|
-
workspace_id: 1,
|
|
21
|
-
light_primary_color: DEFAULT_WORKSPACE_THEME.light.color,
|
|
22
|
-
light_secondary_color: DEFAULT_WORKSPACE_THEME.light.secondaryColor,
|
|
23
|
-
light_surface_color: DEFAULT_WORKSPACE_THEME.light.surfaceColor,
|
|
24
|
-
light_surface_variant_color: DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor,
|
|
25
|
-
dark_primary_color: DEFAULT_WORKSPACE_THEME.dark.color,
|
|
26
|
-
dark_secondary_color: DEFAULT_WORKSPACE_THEME.dark.secondaryColor,
|
|
27
|
-
dark_surface_color: DEFAULT_WORKSPACE_THEME.dark.surfaceColor,
|
|
28
|
-
dark_surface_variant_color: DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor,
|
|
29
|
-
invites_enabled: 1,
|
|
30
|
-
created_at: STUB_CREATED_AT,
|
|
31
|
-
updated_at: STUB_CREATED_AT,
|
|
32
|
-
...rowOverrides
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
function tableBuilder(tableName) {
|
|
37
|
-
assert.equal(tableName, "workspace_settings");
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
insert(payload) {
|
|
41
|
-
state.insertedRow = { ...payload };
|
|
42
|
-
state.row = {
|
|
43
|
-
workspace_id: payload.workspace_id,
|
|
44
|
-
light_primary_color: payload.light_primary_color,
|
|
45
|
-
light_secondary_color: payload.light_secondary_color,
|
|
46
|
-
light_surface_color: payload.light_surface_color,
|
|
47
|
-
light_surface_variant_color: payload.light_surface_variant_color,
|
|
48
|
-
dark_primary_color: payload.dark_primary_color,
|
|
49
|
-
dark_secondary_color: payload.dark_secondary_color,
|
|
50
|
-
dark_surface_color: payload.dark_surface_color,
|
|
51
|
-
dark_surface_variant_color: payload.dark_surface_variant_color,
|
|
52
|
-
invites_enabled: payload.invites_enabled,
|
|
53
|
-
created_at: "2026-03-10 00:00:00.000",
|
|
54
|
-
updated_at: "2026-03-10 00:00:00.000"
|
|
55
|
-
};
|
|
56
|
-
return Promise.resolve([1]);
|
|
57
|
-
},
|
|
58
|
-
where(criteria) {
|
|
59
|
-
assert.equal(typeof criteria, "object");
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
first() {
|
|
63
|
-
return Promise.resolve(state.row ? { ...state.row } : null);
|
|
64
|
-
},
|
|
65
|
-
update(payload) {
|
|
66
|
-
state.updatePayload = payload;
|
|
67
|
-
if (Object.hasOwn(payload, "invites_enabled")) {
|
|
68
|
-
state.row.invites_enabled = payload.invites_enabled;
|
|
69
|
-
}
|
|
70
|
-
if (Object.hasOwn(payload, "light_primary_color")) {
|
|
71
|
-
state.row.light_primary_color = payload.light_primary_color;
|
|
72
|
-
}
|
|
73
|
-
if (Object.hasOwn(payload, "light_secondary_color")) {
|
|
74
|
-
state.row.light_secondary_color = payload.light_secondary_color;
|
|
75
|
-
}
|
|
76
|
-
if (Object.hasOwn(payload, "light_surface_color")) {
|
|
77
|
-
state.row.light_surface_color = payload.light_surface_color;
|
|
78
|
-
}
|
|
79
|
-
if (Object.hasOwn(payload, "light_surface_variant_color")) {
|
|
80
|
-
state.row.light_surface_variant_color = payload.light_surface_variant_color;
|
|
81
|
-
}
|
|
82
|
-
if (Object.hasOwn(payload, "dark_primary_color")) {
|
|
83
|
-
state.row.dark_primary_color = payload.dark_primary_color;
|
|
84
|
-
}
|
|
85
|
-
if (Object.hasOwn(payload, "dark_secondary_color")) {
|
|
86
|
-
state.row.dark_secondary_color = payload.dark_secondary_color;
|
|
87
|
-
}
|
|
88
|
-
if (Object.hasOwn(payload, "dark_surface_color")) {
|
|
89
|
-
state.row.dark_surface_color = payload.dark_surface_color;
|
|
90
|
-
}
|
|
91
|
-
if (Object.hasOwn(payload, "dark_surface_variant_color")) {
|
|
92
|
-
state.row.dark_surface_variant_color = payload.dark_surface_variant_color;
|
|
93
|
-
}
|
|
94
|
-
if (Object.hasOwn(payload, "updated_at")) {
|
|
95
|
-
state.row.updated_at = payload.updated_at;
|
|
96
|
-
}
|
|
97
|
-
return Promise.resolve(1);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return { knexStub: tableBuilder, state };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
test("workspaceSettingsRepository.findByWorkspaceId maps the stored row", async () => {
|
|
108
|
-
const { knexStub } = createKnexStub();
|
|
109
|
-
const repository = createRepository(knexStub, {
|
|
110
|
-
defaultInvitesEnabled: createDefaultWorkspaceSettings()
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const record = await repository.findByWorkspaceId("1");
|
|
114
|
-
|
|
115
|
-
assert.deepEqual(record, {
|
|
116
|
-
workspaceId: "1",
|
|
117
|
-
lightPrimaryColor: DEFAULT_WORKSPACE_THEME.light.color,
|
|
118
|
-
lightSecondaryColor: DEFAULT_WORKSPACE_THEME.light.secondaryColor,
|
|
119
|
-
lightSurfaceColor: DEFAULT_WORKSPACE_THEME.light.surfaceColor,
|
|
120
|
-
lightSurfaceVariantColor: DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor,
|
|
121
|
-
darkPrimaryColor: DEFAULT_WORKSPACE_THEME.dark.color,
|
|
122
|
-
darkSecondaryColor: DEFAULT_WORKSPACE_THEME.dark.secondaryColor,
|
|
123
|
-
darkSurfaceColor: DEFAULT_WORKSPACE_THEME.dark.surfaceColor,
|
|
124
|
-
darkSurfaceVariantColor: DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor,
|
|
125
|
-
invitesEnabled: true,
|
|
126
|
-
createdAt: toIsoString(STUB_CREATED_AT),
|
|
127
|
-
updatedAt: toIsoString(STUB_CREATED_AT)
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates invitesEnabled only", async () => {
|
|
132
|
-
const { knexStub, state } = createKnexStub();
|
|
133
|
-
const repository = createRepository(knexStub, {
|
|
134
|
-
defaultInvitesEnabled: createDefaultWorkspaceSettings()
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const updated = await repository.updateSettingsByWorkspaceId("1", {
|
|
138
|
-
invitesEnabled: false
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
assert.equal(state.updatePayload.invites_enabled, false);
|
|
142
|
-
assert.equal(updated.invitesEnabled, false);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test("workspaceSettingsRepository.ensureForWorkspaceId inserts the injected defaults exactly", async () => {
|
|
146
|
-
const { knexStub, state } = createKnexStub();
|
|
147
|
-
state.row = null;
|
|
148
|
-
const repository = createRepository(knexStub, {
|
|
149
|
-
defaultInvitesEnabled: false
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const record = await repository.ensureForWorkspaceId("5");
|
|
153
|
-
|
|
154
|
-
assert.equal(state.insertedRow.workspace_id, "5");
|
|
155
|
-
assert.equal(state.insertedRow.light_primary_color, DEFAULT_WORKSPACE_THEME.light.color);
|
|
156
|
-
assert.equal(state.insertedRow.light_secondary_color, DEFAULT_WORKSPACE_THEME.light.secondaryColor);
|
|
157
|
-
assert.equal(state.insertedRow.light_surface_color, DEFAULT_WORKSPACE_THEME.light.surfaceColor);
|
|
158
|
-
assert.equal(
|
|
159
|
-
state.insertedRow.light_surface_variant_color,
|
|
160
|
-
DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor
|
|
161
|
-
);
|
|
162
|
-
assert.equal(state.insertedRow.dark_primary_color, DEFAULT_WORKSPACE_THEME.dark.color);
|
|
163
|
-
assert.equal(state.insertedRow.dark_secondary_color, DEFAULT_WORKSPACE_THEME.dark.secondaryColor);
|
|
164
|
-
assert.equal(state.insertedRow.dark_surface_color, DEFAULT_WORKSPACE_THEME.dark.surfaceColor);
|
|
165
|
-
assert.equal(
|
|
166
|
-
state.insertedRow.dark_surface_variant_color,
|
|
167
|
-
DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor
|
|
168
|
-
);
|
|
169
|
-
assert.equal(state.insertedRow.invites_enabled, false);
|
|
170
|
-
assert.equal(record.lightPrimaryColor, DEFAULT_WORKSPACE_THEME.light.color);
|
|
171
|
-
assert.equal(record.lightSecondaryColor, DEFAULT_WORKSPACE_THEME.light.secondaryColor);
|
|
172
|
-
assert.equal(record.lightSurfaceColor, DEFAULT_WORKSPACE_THEME.light.surfaceColor);
|
|
173
|
-
assert.equal(record.lightSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor);
|
|
174
|
-
assert.equal(record.darkPrimaryColor, DEFAULT_WORKSPACE_THEME.dark.color);
|
|
175
|
-
assert.equal(record.darkSecondaryColor, DEFAULT_WORKSPACE_THEME.dark.secondaryColor);
|
|
176
|
-
assert.equal(record.darkSurfaceColor, DEFAULT_WORKSPACE_THEME.dark.surfaceColor);
|
|
177
|
-
assert.equal(record.darkSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor);
|
|
178
|
-
assert.equal(record.invitesEnabled, false);
|
|
179
|
-
assert.equal(record.workspaceId, "5");
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates workspace settings columns", async () => {
|
|
183
|
-
const { knexStub, state } = createKnexStub();
|
|
184
|
-
const repository = createRepository(knexStub, {
|
|
185
|
-
defaultInvitesEnabled: true
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const updated = await repository.updateSettingsByWorkspaceId("1", {
|
|
189
|
-
lightPrimaryColor: "#123abc"
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
assert.equal(state.updatePayload.light_primary_color, "#123ABC");
|
|
193
|
-
assert.equal(updated.lightPrimaryColor, "#123ABC");
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
test("workspaceSettingsRepository can be constructed without validating app config shape", () => {
|
|
197
|
-
const { knexStub } = createKnexStub();
|
|
198
|
-
|
|
199
|
-
const repository = createRepository(knexStub);
|
|
200
|
-
|
|
201
|
-
assert.ok(repository);
|
|
202
|
-
});
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { validateOperationSection } from "@jskit-ai/http-runtime/shared/validators/operationValidation";
|
|
4
|
-
import "../test-support/registerDefaultSettingsFields.js";
|
|
5
|
-
import { resolveWorkspaceThemePalettes } from "../src/shared/settings.js";
|
|
6
|
-
import { workspaceSettingsResource } from "../src/shared/resources/workspaceSettingsResource.js";
|
|
7
|
-
import { createWorkspaceRoleCatalog } from "../src/shared/roles.js";
|
|
8
|
-
|
|
9
|
-
function createRoleCatalog() {
|
|
10
|
-
return createWorkspaceRoleCatalog({
|
|
11
|
-
roleCatalog: {
|
|
12
|
-
workspace: {
|
|
13
|
-
defaultInviteRole: "member"
|
|
14
|
-
},
|
|
15
|
-
roles: {
|
|
16
|
-
owner: {
|
|
17
|
-
assignable: false,
|
|
18
|
-
permissions: ["*"]
|
|
19
|
-
},
|
|
20
|
-
admin: {
|
|
21
|
-
assignable: true,
|
|
22
|
-
permissions: [
|
|
23
|
-
"workspace.roles.view",
|
|
24
|
-
"workspace.settings.view",
|
|
25
|
-
"workspace.settings.update",
|
|
26
|
-
"workspace.members.view",
|
|
27
|
-
"workspace.members.invite",
|
|
28
|
-
"workspace.members.manage",
|
|
29
|
-
"workspace.invites.revoke"
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
member: {
|
|
33
|
-
assignable: true,
|
|
34
|
-
permissions: ["workspace.settings.view"]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function parseBody(operation, payload = {}) {
|
|
42
|
-
return validateOperationSection({
|
|
43
|
-
operation,
|
|
44
|
-
section: "bodyValidator",
|
|
45
|
-
value: payload
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
test("workspace settings patch body normalizes valid payload before validation", () => {
|
|
50
|
-
const parsed = parseBody(workspaceSettingsResource.operations.patch, {
|
|
51
|
-
lightPrimaryColor: "#0f6b54",
|
|
52
|
-
lightSecondaryColor: "#0b4d3c",
|
|
53
|
-
lightSurfaceColor: "#eef5f3",
|
|
54
|
-
lightSurfaceVariantColor: "#ddeae7",
|
|
55
|
-
darkPrimaryColor: "#123456",
|
|
56
|
-
darkSecondaryColor: "#234567",
|
|
57
|
-
darkSurfaceColor: "#345678",
|
|
58
|
-
darkSurfaceVariantColor: "#456789",
|
|
59
|
-
invitesEnabled: false
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
assert.equal(parsed.ok, true);
|
|
63
|
-
assert.deepEqual(parsed.fieldErrors, {});
|
|
64
|
-
assert.deepEqual(parsed.value, {
|
|
65
|
-
lightPrimaryColor: "#0F6B54",
|
|
66
|
-
lightSecondaryColor: "#0B4D3C",
|
|
67
|
-
lightSurfaceColor: "#EEF5F3",
|
|
68
|
-
lightSurfaceVariantColor: "#DDEAE7",
|
|
69
|
-
darkPrimaryColor: "#123456",
|
|
70
|
-
darkSecondaryColor: "#234567",
|
|
71
|
-
darkSurfaceColor: "#345678",
|
|
72
|
-
darkSurfaceVariantColor: "#456789",
|
|
73
|
-
invitesEnabled: false
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("workspace settings patch body ignores unknown fields after normalization", () => {
|
|
78
|
-
const parsed = parseBody(workspaceSettingsResource.operations.patch, {
|
|
79
|
-
avatarUrl: "https://example.com/avatar.png"
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
assert.equal(parsed.ok, true);
|
|
83
|
-
assert.deepEqual(parsed.fieldErrors, {});
|
|
84
|
-
assert.deepEqual(parsed.value, {});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("workspace settings create body requires full-write fields", () => {
|
|
88
|
-
const parsed = parseBody(workspaceSettingsResource.operations.create, {});
|
|
89
|
-
|
|
90
|
-
assert.equal(parsed.ok, false);
|
|
91
|
-
assert.equal(parsed.fieldErrors.lightPrimaryColor, "Light primary color is required.");
|
|
92
|
-
assert.equal(parsed.fieldErrors.lightSecondaryColor, "Light secondary color is required.");
|
|
93
|
-
assert.equal(parsed.fieldErrors.lightSurfaceColor, "Light surface color is required.");
|
|
94
|
-
assert.equal(parsed.fieldErrors.lightSurfaceVariantColor, "Light surface variant color is required.");
|
|
95
|
-
assert.equal(parsed.fieldErrors.darkPrimaryColor, "Dark primary color is required.");
|
|
96
|
-
assert.equal(parsed.fieldErrors.darkSecondaryColor, "Dark secondary color is required.");
|
|
97
|
-
assert.equal(parsed.fieldErrors.darkSurfaceColor, "Dark surface color is required.");
|
|
98
|
-
assert.equal(parsed.fieldErrors.darkSurfaceVariantColor, "Dark surface variant color is required.");
|
|
99
|
-
assert.equal(parsed.fieldErrors.invitesEnabled, "invitesEnabled is required.");
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("workspace settings output normalizes raw service payloads", () => {
|
|
103
|
-
const expectedTheme = resolveWorkspaceThemePalettes({
|
|
104
|
-
lightPrimaryColor: "#0F6B54"
|
|
105
|
-
});
|
|
106
|
-
const normalized = workspaceSettingsResource.operations.view.outputValidator.normalize({
|
|
107
|
-
workspace: {
|
|
108
|
-
id: "7",
|
|
109
|
-
slug: " mercury ",
|
|
110
|
-
ownerUserId: "9"
|
|
111
|
-
},
|
|
112
|
-
settings: {
|
|
113
|
-
lightPrimaryColor: "#0f6b54",
|
|
114
|
-
invitesEnabled: false
|
|
115
|
-
},
|
|
116
|
-
roleCatalog: createRoleCatalog()
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
assert.deepEqual(normalized, {
|
|
120
|
-
workspace: {
|
|
121
|
-
id: "7",
|
|
122
|
-
slug: "mercury",
|
|
123
|
-
ownerUserId: "9"
|
|
124
|
-
},
|
|
125
|
-
settings: {
|
|
126
|
-
lightPrimaryColor: "#0F6B54",
|
|
127
|
-
lightSecondaryColor: expectedTheme.light.secondaryColor,
|
|
128
|
-
lightSurfaceColor: expectedTheme.light.surfaceColor,
|
|
129
|
-
lightSurfaceVariantColor: expectedTheme.light.surfaceVariantColor,
|
|
130
|
-
darkPrimaryColor: expectedTheme.dark.color,
|
|
131
|
-
darkSecondaryColor: expectedTheme.dark.secondaryColor,
|
|
132
|
-
darkSurfaceColor: expectedTheme.dark.surfaceColor,
|
|
133
|
-
darkSurfaceVariantColor: expectedTheme.dark.surfaceVariantColor,
|
|
134
|
-
invitesEnabled: false,
|
|
135
|
-
invitesAvailable: true,
|
|
136
|
-
invitesEffective: false
|
|
137
|
-
},
|
|
138
|
-
roleCatalog: {
|
|
139
|
-
collaborationEnabled: true,
|
|
140
|
-
defaultInviteRole: "member",
|
|
141
|
-
roles: [
|
|
142
|
-
{
|
|
143
|
-
id: "owner",
|
|
144
|
-
assignable: false,
|
|
145
|
-
permissions: ["*"]
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
id: "admin",
|
|
149
|
-
assignable: true,
|
|
150
|
-
permissions: [
|
|
151
|
-
"workspace.roles.view",
|
|
152
|
-
"workspace.settings.view",
|
|
153
|
-
"workspace.settings.update",
|
|
154
|
-
"workspace.members.view",
|
|
155
|
-
"workspace.members.invite",
|
|
156
|
-
"workspace.members.manage",
|
|
157
|
-
"workspace.invites.revoke"
|
|
158
|
-
]
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
id: "member",
|
|
162
|
-
assignable: true,
|
|
163
|
-
permissions: ["workspace.settings.view"]
|
|
164
|
-
}
|
|
165
|
-
],
|
|
166
|
-
assignableRoleIds: ["admin", "member"]
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
});
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import "../test-support/registerDefaultSettingsFields.js";
|
|
4
|
-
import { resolveWorkspaceThemePalettes } from "../src/shared/settings.js";
|
|
5
|
-
import { createService } from "../src/server/workspaceSettings/workspaceSettingsService.js";
|
|
6
|
-
|
|
7
|
-
function authorizedOptions(permissions = []) {
|
|
8
|
-
return {
|
|
9
|
-
context: {
|
|
10
|
-
actor: {
|
|
11
|
-
id: 1
|
|
12
|
-
},
|
|
13
|
-
permissions
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function createFixture({ workspaceInvitationsEnabled = true } = {}) {
|
|
19
|
-
const defaultTheme = resolveWorkspaceThemePalettes({
|
|
20
|
-
lightPrimaryColor: "#0F6B54"
|
|
21
|
-
});
|
|
22
|
-
const state = {
|
|
23
|
-
settingsPatch: null,
|
|
24
|
-
workspace: {
|
|
25
|
-
id: 7,
|
|
26
|
-
slug: "tonymobily3",
|
|
27
|
-
name: "TonyMobily3",
|
|
28
|
-
ownerUserId: 9
|
|
29
|
-
},
|
|
30
|
-
settings: {
|
|
31
|
-
lightPrimaryColor: defaultTheme.light.color,
|
|
32
|
-
lightSecondaryColor: defaultTheme.light.secondaryColor,
|
|
33
|
-
lightSurfaceColor: defaultTheme.light.surfaceColor,
|
|
34
|
-
lightSurfaceVariantColor: defaultTheme.light.surfaceVariantColor,
|
|
35
|
-
darkPrimaryColor: defaultTheme.dark.color,
|
|
36
|
-
darkSecondaryColor: defaultTheme.dark.secondaryColor,
|
|
37
|
-
darkSurfaceColor: defaultTheme.dark.surfaceColor,
|
|
38
|
-
darkSurfaceVariantColor: defaultTheme.dark.surfaceVariantColor,
|
|
39
|
-
invitesEnabled: true
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const service = createService({
|
|
44
|
-
workspaceInvitationsEnabled,
|
|
45
|
-
workspaceSettingsRepository: {
|
|
46
|
-
async ensureForWorkspaceId(workspaceId) {
|
|
47
|
-
assert.equal(Number(workspaceId), 7);
|
|
48
|
-
return { ...state.settings };
|
|
49
|
-
},
|
|
50
|
-
async updateSettingsByWorkspaceId(workspaceId, patch) {
|
|
51
|
-
assert.equal(Number(workspaceId), 7);
|
|
52
|
-
state.settingsPatch = { ...patch };
|
|
53
|
-
state.settings = {
|
|
54
|
-
...state.settings,
|
|
55
|
-
...patch
|
|
56
|
-
};
|
|
57
|
-
return state.settings;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
return { service, state };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
test("workspaceSettingsService.getWorkspaceSettings returns the stored invitesEnabled flag", async () => {
|
|
66
|
-
const { service, state } = createFixture();
|
|
67
|
-
|
|
68
|
-
const response = await service.getWorkspaceSettings(
|
|
69
|
-
state.workspace,
|
|
70
|
-
authorizedOptions(["workspace.settings.view"])
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
assert.deepEqual(response.settings, {
|
|
74
|
-
lightPrimaryColor: "#0F6B54",
|
|
75
|
-
lightSecondaryColor: "#48A9A6",
|
|
76
|
-
lightSurfaceColor: "#FFFFFF",
|
|
77
|
-
lightSurfaceVariantColor: "#424242",
|
|
78
|
-
darkPrimaryColor: "#2196F3",
|
|
79
|
-
darkSecondaryColor: "#54B6B2",
|
|
80
|
-
darkSurfaceColor: "#212121",
|
|
81
|
-
darkSurfaceVariantColor: "#C8C8C8",
|
|
82
|
-
invitesEnabled: true,
|
|
83
|
-
invitesAvailable: true,
|
|
84
|
-
invitesEffective: true
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("workspaceSettingsService.updateWorkspaceSettings writes editable fields through workspaceSettingsRepository only", async () => {
|
|
89
|
-
const { service, state } = createFixture();
|
|
90
|
-
|
|
91
|
-
const response = await service.updateWorkspaceSettings(
|
|
92
|
-
state.workspace,
|
|
93
|
-
{
|
|
94
|
-
invitesEnabled: false
|
|
95
|
-
},
|
|
96
|
-
authorizedOptions(["workspace.settings.update"])
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
assert.deepEqual(state.settingsPatch, {
|
|
100
|
-
invitesEnabled: false
|
|
101
|
-
});
|
|
102
|
-
assert.deepEqual(response.settings, {
|
|
103
|
-
lightPrimaryColor: "#0F6B54",
|
|
104
|
-
lightSecondaryColor: "#48A9A6",
|
|
105
|
-
lightSurfaceColor: "#FFFFFF",
|
|
106
|
-
lightSurfaceVariantColor: "#424242",
|
|
107
|
-
darkPrimaryColor: "#2196F3",
|
|
108
|
-
darkSecondaryColor: "#54B6B2",
|
|
109
|
-
darkSurfaceColor: "#212121",
|
|
110
|
-
darkSurfaceVariantColor: "#C8C8C8",
|
|
111
|
-
invitesEnabled: false,
|
|
112
|
-
invitesAvailable: true,
|
|
113
|
-
invitesEffective: false
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test("workspaceSettingsService disables invite settings in output when app policy disables invitations", async () => {
|
|
118
|
-
const { service, state } = createFixture({
|
|
119
|
-
workspaceInvitationsEnabled: false
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const response = await service.getWorkspaceSettings(
|
|
123
|
-
state.workspace,
|
|
124
|
-
authorizedOptions(["workspace.settings.view"])
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
assert.deepEqual(response.settings, {
|
|
128
|
-
lightPrimaryColor: "#0F6B54",
|
|
129
|
-
lightSecondaryColor: "#48A9A6",
|
|
130
|
-
lightSurfaceColor: "#FFFFFF",
|
|
131
|
-
lightSurfaceVariantColor: "#424242",
|
|
132
|
-
darkPrimaryColor: "#2196F3",
|
|
133
|
-
darkSecondaryColor: "#54B6B2",
|
|
134
|
-
darkSurfaceColor: "#212121",
|
|
135
|
-
darkSurfaceVariantColor: "#C8C8C8",
|
|
136
|
-
invitesEnabled: false,
|
|
137
|
-
invitesAvailable: false,
|
|
138
|
-
invitesEffective: false
|
|
139
|
-
});
|
|
140
|
-
});
|