@jskit-ai/users-core 0.1.32 → 0.1.35
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 +16 -245
- package/package.json +7 -7
- package/src/server/UsersCoreServiceProvider.js +4 -28
- package/src/server/UsersWorkspacesServiceProvider.js +44 -0
- package/src/server/accountNotifications/accountNotificationsService.js +3 -3
- package/src/server/accountNotifications/registerAccountNotifications.js +1 -1
- package/src/server/accountPreferences/accountPreferencesService.js +3 -3
- package/src/server/accountPreferences/registerAccountPreferences.js +1 -1
- package/src/server/accountProfile/accountProfileActions.js +8 -2
- package/src/server/accountProfile/accountProfileService.js +10 -10
- package/src/server/accountProfile/avatarService.js +9 -9
- package/src/server/accountProfile/bootAccountProfileRoutes.js +5 -3
- package/src/server/accountProfile/registerAccountProfile.js +2 -2
- package/src/server/accountSecurity/accountSecurityService.js +3 -3
- package/src/server/accountSecurity/registerAccountSecurity.js +1 -1
- package/src/server/common/contributors/workspaceActionContextContributor.js +24 -17
- package/src/server/common/registerCommonRepositories.js +3 -22
- package/src/server/common/repositories/userSettingsRepository.js +1 -12
- package/src/server/common/repositories/{userProfilesRepository.js → usersRepository.js} +1 -1
- package/src/server/common/services/accountContextService.js +4 -4
- package/src/server/common/services/authProfileSyncService.js +10 -10
- package/src/server/registerUsersBootstrap.js +22 -0
- package/src/server/registerUsersCore.js +30 -0
- package/src/server/registerWorkspaceBootstrap.js +3 -6
- package/src/server/registerWorkspaceCore.js +5 -17
- package/src/server/registerWorkspaceRepositories.js +26 -0
- package/src/server/usersBootstrapContributor.js +248 -0
- package/src/server/workspaceBootstrapContributor.js +65 -259
- package/src/shared/roles.js +31 -6
- package/src/shared/settings.js +1 -2
- package/templates/migrations/users_core_generic_initial.cjs +69 -0
- package/test/authProfileSyncService.test.js +3 -3
- package/test/avatarService.test.js +2 -2
- package/test/registerUsersCore.test.js +42 -0
- package/test/roles.test.js +90 -5
- package/test/usersBootstrapContributor.test.js +172 -0
- package/test/usersRouteRequestInputValidator.test.js +7 -390
- package/test/workspaceActionContextContributor.test.js +98 -5
- package/test/workspaceBootstrapContributor.test.js +34 -346
- package/test/workspaceMembersService.test.js +4 -2
- package/test/workspaceService.test.js +12 -8
- package/test/workspaceSettingsResource.test.js +4 -2
- package/test-support/registerDefaultSettingsFields.js +1 -1
- package/templates/config/workspaceRoles.js +0 -30
- package/templates/migrations/users_core_initial.cjs +0 -123
- package/templates/migrations/users_core_workspace_settings_single_name_source.cjs +0 -71
- package/templates/migrations/users_core_workspaces_drop_color.cjs +0 -85
- package/templates/packages/main/src/shared/resources/workspaceSettingsFields.js +0 -197
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { AppError } from "@jskit-ai/kernel/server/runtime";
|
|
2
|
+
import { requireServiceMethod } from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
|
|
3
|
+
import { normalizeLowerText, normalizeText } from "@jskit-ai/kernel/shared/actions/textNormalization";
|
|
4
|
+
import {
|
|
5
|
+
TENANCY_MODE_NONE,
|
|
6
|
+
TENANCY_MODE_PERSONAL,
|
|
7
|
+
TENANCY_MODE_WORKSPACES,
|
|
8
|
+
WORKSPACE_SLUG_POLICY_NONE,
|
|
9
|
+
WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
|
|
10
|
+
WORKSPACE_SLUG_POLICY_USER_SELECTED,
|
|
11
|
+
resolveTenancyProfile
|
|
12
|
+
} from "../shared/tenancyProfile.js";
|
|
13
|
+
import { accountAvatarFormatter } from "./common/formatters/accountAvatarFormatter.js";
|
|
14
|
+
import { authenticatedUserValidator } from "./common/validators/authenticatedUserValidator.js";
|
|
15
|
+
import { userSettingsFields } from "../shared/resources/userSettingsFields.js";
|
|
16
|
+
|
|
17
|
+
function getOAuthProviderCatalogPayload(authService) {
|
|
18
|
+
if (!authService || typeof authService.getOAuthProviderCatalog !== "function") {
|
|
19
|
+
return {
|
|
20
|
+
oauthProviders: [],
|
|
21
|
+
oauthDefaultProvider: null
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const catalog = authService.getOAuthProviderCatalog();
|
|
26
|
+
const providers = Array.isArray(catalog?.providers)
|
|
27
|
+
? catalog.providers
|
|
28
|
+
.map((provider) => ({
|
|
29
|
+
id: normalizeLowerText(provider?.id),
|
|
30
|
+
label: normalizeText(provider?.label)
|
|
31
|
+
}))
|
|
32
|
+
.filter((provider) => provider.id && provider.label)
|
|
33
|
+
: [];
|
|
34
|
+
const defaultProvider = normalizeLowerText(catalog?.defaultProvider);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
oauthProviders: providers,
|
|
38
|
+
oauthDefaultProvider: providers.some((provider) => provider.id === defaultProvider) ? defaultProvider : null
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizeBoolean(value, fallback) {
|
|
43
|
+
if (typeof value === "boolean") {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
const normalized = normalizeLowerText(value);
|
|
48
|
+
if (normalized === "true") {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (normalized === "false") {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return fallback;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveAppState(appConfig = {}, { workspaceInvitationsEnabled = false } = {}) {
|
|
59
|
+
const features = {
|
|
60
|
+
workspaceSwitching: normalizeBoolean(appConfig.workspaceSwitching, false),
|
|
61
|
+
workspaceInvites: workspaceInvitationsEnabled === true,
|
|
62
|
+
assistantEnabled: normalizeBoolean(appConfig.assistantEnabled, false),
|
|
63
|
+
assistantRequiredPermission: normalizeText(appConfig.assistantRequiredPermission),
|
|
64
|
+
socialEnabled: normalizeBoolean(appConfig.socialEnabled, false),
|
|
65
|
+
socialFederationEnabled: normalizeBoolean(appConfig.socialFederationEnabled, false)
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
features
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function normalizeSlugPolicy(value = "") {
|
|
74
|
+
const normalizedValue = normalizeLowerText(value);
|
|
75
|
+
if (
|
|
76
|
+
normalizedValue === WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME ||
|
|
77
|
+
normalizedValue === WORKSPACE_SLUG_POLICY_USER_SELECTED
|
|
78
|
+
) {
|
|
79
|
+
return normalizedValue;
|
|
80
|
+
}
|
|
81
|
+
return WORKSPACE_SLUG_POLICY_NONE;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isSupportedTenancyMode(value = "") {
|
|
85
|
+
return value === TENANCY_MODE_NONE || value === TENANCY_MODE_PERSONAL || value === TENANCY_MODE_WORKSPACES;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function resolveBootstrapTenancyProfile(tenancyProfile = null, appConfig = {}) {
|
|
89
|
+
const fallback = resolveTenancyProfile(appConfig);
|
|
90
|
+
const source = tenancyProfile && typeof tenancyProfile === "object" ? tenancyProfile : fallback;
|
|
91
|
+
const mode = isSupportedTenancyMode(source?.mode) ? source.mode : fallback.mode;
|
|
92
|
+
const workspace = source?.workspace && typeof source.workspace === "object" ? source.workspace : fallback.workspace;
|
|
93
|
+
|
|
94
|
+
return Object.freeze({
|
|
95
|
+
mode,
|
|
96
|
+
workspace: Object.freeze({
|
|
97
|
+
enabled: workspace.enabled === true,
|
|
98
|
+
autoProvision: workspace.autoProvision === true,
|
|
99
|
+
allowSelfCreate: workspace.allowSelfCreate === true,
|
|
100
|
+
slugPolicy: normalizeSlugPolicy(workspace.slugPolicy)
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function createAnonymousBootstrapPayload({ appState, tenancyProfile }) {
|
|
106
|
+
return {
|
|
107
|
+
session: {
|
|
108
|
+
authenticated: false
|
|
109
|
+
},
|
|
110
|
+
profile: null,
|
|
111
|
+
tenancy: tenancyProfile,
|
|
112
|
+
app: appState,
|
|
113
|
+
workspaces: [],
|
|
114
|
+
pendingInvites: [],
|
|
115
|
+
activeWorkspace: null,
|
|
116
|
+
membership: null,
|
|
117
|
+
requestedWorkspace: null,
|
|
118
|
+
permissions: [],
|
|
119
|
+
surfaceAccess: {
|
|
120
|
+
consoleowner: false
|
|
121
|
+
},
|
|
122
|
+
workspaceSettings: null,
|
|
123
|
+
userSettings: null,
|
|
124
|
+
requestMeta: {
|
|
125
|
+
hasRequest: false
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function mapUserSettingsBootstrap(settings = {}) {
|
|
131
|
+
const source = settings && typeof settings === "object" ? settings : {};
|
|
132
|
+
const mapped = {};
|
|
133
|
+
|
|
134
|
+
for (const field of userSettingsFields) {
|
|
135
|
+
if (field.includeInBootstrap === false) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const rawValue = Object.hasOwn(source, field.key)
|
|
139
|
+
? source[field.key]
|
|
140
|
+
: field.resolveDefault({
|
|
141
|
+
settings: source
|
|
142
|
+
});
|
|
143
|
+
mapped[field.key] = field.normalizeOutput(rawValue, {
|
|
144
|
+
settings: source
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return mapped;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function createUsersBootstrapContributor({
|
|
152
|
+
usersRepository,
|
|
153
|
+
userSettingsRepository,
|
|
154
|
+
appConfig = {},
|
|
155
|
+
tenancyProfile = null,
|
|
156
|
+
authService,
|
|
157
|
+
consoleService = null
|
|
158
|
+
} = {}) {
|
|
159
|
+
const contributorId = "users.bootstrap";
|
|
160
|
+
const appState = resolveAppState(appConfig);
|
|
161
|
+
const resolvedTenancyProfile = resolveBootstrapTenancyProfile(tenancyProfile, appConfig);
|
|
162
|
+
|
|
163
|
+
requireServiceMethod(usersRepository, "findById", contributorId, {
|
|
164
|
+
serviceLabel: "usersRepository"
|
|
165
|
+
});
|
|
166
|
+
requireServiceMethod(userSettingsRepository, "ensureForUserId", contributorId, {
|
|
167
|
+
serviceLabel: "userSettingsRepository"
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return Object.freeze({
|
|
171
|
+
contributorId,
|
|
172
|
+
async contribute({ request = null, reply = null } = {}) {
|
|
173
|
+
const authResult = await request.executeAction({
|
|
174
|
+
actionId: "auth.session.read"
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
if (authResult?.clearSession === true && typeof authService?.clearSessionCookies === "function") {
|
|
178
|
+
authService.clearSessionCookies(reply);
|
|
179
|
+
}
|
|
180
|
+
if (authResult?.session && typeof authService?.writeSessionCookies === "function") {
|
|
181
|
+
authService.writeSessionCookies(reply, authResult.session);
|
|
182
|
+
}
|
|
183
|
+
if (authResult?.transientFailure === true) {
|
|
184
|
+
throw new AppError(503, "Authentication service temporarily unavailable. Please retry.");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const normalizedUser = authenticatedUserValidator.normalize(authResult?.authenticated ? authResult?.profile : null);
|
|
188
|
+
let payload = createAnonymousBootstrapPayload({
|
|
189
|
+
appState,
|
|
190
|
+
tenancyProfile: resolvedTenancyProfile
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (normalizedUser) {
|
|
194
|
+
const latestProfile = (await usersRepository.findById(normalizedUser.id)) || normalizedUser;
|
|
195
|
+
const userSettings = await userSettingsRepository.ensureForUserId(latestProfile.id);
|
|
196
|
+
|
|
197
|
+
let seededConsoleOwnerUserId = 0;
|
|
198
|
+
if (
|
|
199
|
+
consoleService &&
|
|
200
|
+
typeof consoleService.ensureInitialConsoleMember === "function"
|
|
201
|
+
) {
|
|
202
|
+
seededConsoleOwnerUserId = Number(await consoleService.ensureInitialConsoleMember(latestProfile.id));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
payload = {
|
|
206
|
+
session: {
|
|
207
|
+
authenticated: true,
|
|
208
|
+
userId: latestProfile.id
|
|
209
|
+
},
|
|
210
|
+
profile: {
|
|
211
|
+
displayName: latestProfile.displayName,
|
|
212
|
+
email: latestProfile.email,
|
|
213
|
+
avatar: accountAvatarFormatter(latestProfile, userSettings)
|
|
214
|
+
},
|
|
215
|
+
tenancy: resolvedTenancyProfile,
|
|
216
|
+
app: appState,
|
|
217
|
+
workspaces: [],
|
|
218
|
+
pendingInvites: [],
|
|
219
|
+
activeWorkspace: null,
|
|
220
|
+
membership: null,
|
|
221
|
+
requestedWorkspace: null,
|
|
222
|
+
permissions: [],
|
|
223
|
+
surfaceAccess: {
|
|
224
|
+
consoleowner: seededConsoleOwnerUserId > 0 && seededConsoleOwnerUserId === Number(latestProfile.id)
|
|
225
|
+
},
|
|
226
|
+
workspaceSettings: null,
|
|
227
|
+
userSettings: mapUserSettingsBootstrap(userSettings),
|
|
228
|
+
requestMeta: {
|
|
229
|
+
hasRequest: Boolean(request)
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const oauthCatalogPayload = getOAuthProviderCatalogPayload(authService);
|
|
235
|
+
const session = payload?.session && typeof payload.session === "object" ? payload.session : { authenticated: false };
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
...payload,
|
|
239
|
+
session: {
|
|
240
|
+
...session,
|
|
241
|
+
...oauthCatalogPayload
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export { createUsersBootstrapContributor };
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import { AppError } from "@jskit-ai/kernel/server/runtime";
|
|
2
1
|
import { requireServiceMethod } from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
|
|
3
|
-
import { normalizeLowerText
|
|
2
|
+
import { normalizeLowerText } from "@jskit-ai/kernel/shared/actions/textNormalization";
|
|
4
3
|
import {
|
|
5
4
|
TENANCY_MODE_NONE,
|
|
6
|
-
TENANCY_MODE_PERSONAL,
|
|
7
|
-
TENANCY_MODE_WORKSPACES,
|
|
8
|
-
WORKSPACE_SLUG_POLICY_NONE,
|
|
9
|
-
WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
|
|
10
|
-
WORKSPACE_SLUG_POLICY_USER_SELECTED,
|
|
11
5
|
resolveTenancyProfile
|
|
12
6
|
} from "../shared/tenancyProfile.js";
|
|
13
7
|
import { workspacePendingInvitationsResource } from "../shared/resources/workspacePendingInvitationsResource.js";
|
|
@@ -16,9 +10,6 @@ import {
|
|
|
16
10
|
mapWorkspaceSettingsPublic,
|
|
17
11
|
mapWorkspaceSummary
|
|
18
12
|
} from "./common/formatters/workspaceFormatter.js";
|
|
19
|
-
import { accountAvatarFormatter } from "./common/formatters/accountAvatarFormatter.js";
|
|
20
|
-
import { authenticatedUserValidator } from "./common/validators/authenticatedUserValidator.js";
|
|
21
|
-
import { userSettingsFields } from "../shared/resources/userSettingsFields.js";
|
|
22
13
|
|
|
23
14
|
const REQUESTED_WORKSPACE_STATUS_RESOLVED = "resolved";
|
|
24
15
|
const REQUESTED_WORKSPACE_STATUS_NOT_FOUND = "not_found";
|
|
@@ -31,47 +22,6 @@ function normalizePendingInvites(invites) {
|
|
|
31
22
|
}).pendingInvites;
|
|
32
23
|
}
|
|
33
24
|
|
|
34
|
-
function getOAuthProviderCatalogPayload(authService) {
|
|
35
|
-
if (!authService || typeof authService.getOAuthProviderCatalog !== "function") {
|
|
36
|
-
return {
|
|
37
|
-
oauthProviders: [],
|
|
38
|
-
oauthDefaultProvider: null
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const catalog = authService.getOAuthProviderCatalog();
|
|
43
|
-
const providers = Array.isArray(catalog?.providers)
|
|
44
|
-
? catalog.providers
|
|
45
|
-
.map((provider) => ({
|
|
46
|
-
id: normalizeLowerText(provider?.id),
|
|
47
|
-
label: normalizeText(provider?.label)
|
|
48
|
-
}))
|
|
49
|
-
.filter((provider) => provider.id && provider.label)
|
|
50
|
-
: [];
|
|
51
|
-
const defaultProvider = normalizeLowerText(catalog?.defaultProvider);
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
oauthProviders: providers,
|
|
55
|
-
oauthDefaultProvider: providers.some((provider) => provider.id === defaultProvider) ? defaultProvider : null
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function normalizeBoolean(value, fallback) {
|
|
60
|
-
if (typeof value === "boolean") {
|
|
61
|
-
return value;
|
|
62
|
-
}
|
|
63
|
-
if (typeof value === "string") {
|
|
64
|
-
const normalized = normalizeLowerText(value);
|
|
65
|
-
if (normalized === "true") {
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
if (normalized === "false") {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return fallback;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
25
|
function normalizeQueryPayload(value = {}) {
|
|
76
26
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
77
27
|
return {};
|
|
@@ -137,111 +87,28 @@ function resolveRequestedWorkspaceStatusFromError(error) {
|
|
|
137
87
|
return "";
|
|
138
88
|
}
|
|
139
89
|
|
|
140
|
-
function resolveAppState(appConfig = {}, { workspaceInvitationsEnabled = true } = {}) {
|
|
141
|
-
const features = {
|
|
142
|
-
workspaceSwitching: normalizeBoolean(appConfig.workspaceSwitching, true),
|
|
143
|
-
workspaceInvites: workspaceInvitationsEnabled === true,
|
|
144
|
-
assistantEnabled: normalizeBoolean(appConfig.assistantEnabled, false),
|
|
145
|
-
assistantRequiredPermission: normalizeText(appConfig.assistantRequiredPermission),
|
|
146
|
-
socialEnabled: normalizeBoolean(appConfig.socialEnabled, false),
|
|
147
|
-
socialFederationEnabled: normalizeBoolean(appConfig.socialFederationEnabled, false)
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
features
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function normalizeSlugPolicy(value = "") {
|
|
156
|
-
const normalizedValue = normalizeLowerText(value);
|
|
157
|
-
if (
|
|
158
|
-
normalizedValue === WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME ||
|
|
159
|
-
normalizedValue === WORKSPACE_SLUG_POLICY_USER_SELECTED
|
|
160
|
-
) {
|
|
161
|
-
return normalizedValue;
|
|
162
|
-
}
|
|
163
|
-
return WORKSPACE_SLUG_POLICY_NONE;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function isSupportedTenancyMode(value = "") {
|
|
167
|
-
return value === TENANCY_MODE_NONE || value === TENANCY_MODE_PERSONAL || value === TENANCY_MODE_WORKSPACES;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
90
|
function resolveBootstrapTenancyProfile(tenancyProfile = null, appConfig = {}) {
|
|
171
91
|
const fallback = resolveTenancyProfile(appConfig);
|
|
172
|
-
const source = tenancyProfile && typeof tenancyProfile === "object" ? tenancyProfile : fallback;
|
|
173
|
-
const mode = isSupportedTenancyMode(source?.mode) ? source.mode : fallback.mode;
|
|
174
|
-
const workspace = source?.workspace && typeof source.workspace === "object" ? source.workspace : fallback.workspace;
|
|
175
|
-
|
|
176
92
|
return Object.freeze({
|
|
177
|
-
mode,
|
|
93
|
+
mode: fallback.mode,
|
|
178
94
|
workspace: Object.freeze({
|
|
179
|
-
enabled: workspace.enabled === true,
|
|
180
|
-
autoProvision: workspace.autoProvision === true,
|
|
181
|
-
allowSelfCreate: workspace.allowSelfCreate === true,
|
|
182
|
-
slugPolicy:
|
|
95
|
+
enabled: fallback.workspace.enabled === true,
|
|
96
|
+
autoProvision: fallback.workspace.autoProvision === true,
|
|
97
|
+
allowSelfCreate: fallback.workspace.allowSelfCreate === true,
|
|
98
|
+
slugPolicy: fallback.workspace.slugPolicy
|
|
183
99
|
})
|
|
184
100
|
});
|
|
185
101
|
}
|
|
186
102
|
|
|
187
|
-
function createAnonymousBootstrapPayload({ appState, tenancyProfile }) {
|
|
188
|
-
return {
|
|
189
|
-
session: {
|
|
190
|
-
authenticated: false
|
|
191
|
-
},
|
|
192
|
-
profile: null,
|
|
193
|
-
tenancy: tenancyProfile,
|
|
194
|
-
app: appState,
|
|
195
|
-
workspaces: [],
|
|
196
|
-
pendingInvites: [],
|
|
197
|
-
activeWorkspace: null,
|
|
198
|
-
membership: null,
|
|
199
|
-
requestedWorkspace: null,
|
|
200
|
-
permissions: [],
|
|
201
|
-
surfaceAccess: {
|
|
202
|
-
consoleowner: false
|
|
203
|
-
},
|
|
204
|
-
workspaceSettings: null,
|
|
205
|
-
userSettings: null
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function mapUserSettingsBootstrap(settings = {}) {
|
|
210
|
-
const source = settings && typeof settings === "object" ? settings : {};
|
|
211
|
-
const mapped = {};
|
|
212
|
-
|
|
213
|
-
for (const field of userSettingsFields) {
|
|
214
|
-
if (field.includeInBootstrap === false) {
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
const rawValue = Object.hasOwn(source, field.key)
|
|
218
|
-
? source[field.key]
|
|
219
|
-
: field.resolveDefault({
|
|
220
|
-
settings: source
|
|
221
|
-
});
|
|
222
|
-
mapped[field.key] = field.normalizeOutput(rawValue, {
|
|
223
|
-
settings: source
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return mapped;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
103
|
function createWorkspaceBootstrapContributor({
|
|
231
104
|
workspaceService,
|
|
232
105
|
workspacePendingInvitationsService,
|
|
233
|
-
|
|
234
|
-
userSettingsRepository,
|
|
106
|
+
usersRepository,
|
|
235
107
|
workspaceInvitationsEnabled = false,
|
|
236
108
|
appConfig = {},
|
|
237
|
-
tenancyProfile = null
|
|
238
|
-
authService,
|
|
239
|
-
consoleService = null
|
|
109
|
+
tenancyProfile = null
|
|
240
110
|
} = {}) {
|
|
241
|
-
const contributorId = "users.bootstrap";
|
|
242
|
-
const appState = resolveAppState(appConfig, {
|
|
243
|
-
workspaceInvitationsEnabled
|
|
244
|
-
});
|
|
111
|
+
const contributorId = "users.workspace.bootstrap";
|
|
245
112
|
const resolvedTenancyProfile = resolveBootstrapTenancyProfile(tenancyProfile, appConfig);
|
|
246
113
|
|
|
247
114
|
requireServiceMethod(workspaceService, "listWorkspacesForUser", contributorId, {
|
|
@@ -255,144 +122,83 @@ function createWorkspaceBootstrapContributor({
|
|
|
255
122
|
serviceLabel: "workspacePendingInvitationsService"
|
|
256
123
|
});
|
|
257
124
|
}
|
|
258
|
-
requireServiceMethod(
|
|
259
|
-
serviceLabel: "
|
|
260
|
-
});
|
|
261
|
-
requireServiceMethod(userSettingsRepository, "ensureForUserId", contributorId, {
|
|
262
|
-
serviceLabel: "userSettingsRepository"
|
|
125
|
+
requireServiceMethod(usersRepository, "findById", contributorId, {
|
|
126
|
+
serviceLabel: "usersRepository"
|
|
263
127
|
});
|
|
264
128
|
|
|
265
129
|
return Object.freeze({
|
|
266
130
|
contributorId,
|
|
267
|
-
async contribute({ request = null,
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
131
|
+
async contribute({ request = null, query = {}, payload = {} } = {}) {
|
|
132
|
+
const normalizedUserId = Number(payload?.session?.authenticated === true ? payload?.session?.userId : 0);
|
|
133
|
+
const normalizedWorkspaceSlug = resolveBootstrapWorkspaceSlug({ query, request });
|
|
134
|
+
if (!normalizedUserId) {
|
|
135
|
+
if (!normalizedWorkspaceSlug || resolvedTenancyProfile.mode === TENANCY_MODE_NONE) {
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
271
138
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (authResult?.transientFailure === true) {
|
|
279
|
-
throw new AppError(503, "Authentication service temporarily unavailable. Please retry.");
|
|
139
|
+
return {
|
|
140
|
+
requestedWorkspace: createRequestedWorkspacePayload(
|
|
141
|
+
normalizedWorkspaceSlug,
|
|
142
|
+
REQUESTED_WORKSPACE_STATUS_UNAUTHENTICATED
|
|
143
|
+
)
|
|
144
|
+
};
|
|
280
145
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
consoleService &&
|
|
286
|
-
typeof consoleService.ensureInitialConsoleMember === "function"
|
|
287
|
-
) {
|
|
288
|
-
seededConsoleOwnerUserId = Number(await consoleService.ensureInitialConsoleMember(authResult.profile.id));
|
|
146
|
+
|
|
147
|
+
const latestProfile = await usersRepository.findById(normalizedUserId);
|
|
148
|
+
if (!latestProfile) {
|
|
149
|
+
return {};
|
|
289
150
|
}
|
|
290
151
|
|
|
291
|
-
const user = authResult?.authenticated ? authResult.profile : null;
|
|
292
|
-
const normalizedUser = authenticatedUserValidator.normalize(user);
|
|
293
152
|
const pendingInvites =
|
|
294
|
-
workspaceInvitationsEnabled
|
|
153
|
+
workspaceInvitationsEnabled
|
|
295
154
|
? normalizePendingInvites(
|
|
296
|
-
await workspacePendingInvitationsService.listPendingInvitesForUser(
|
|
155
|
+
await workspacePendingInvitationsService.listPendingInvitesForUser(latestProfile, {
|
|
297
156
|
context: {
|
|
298
|
-
actor:
|
|
157
|
+
actor: latestProfile
|
|
299
158
|
}
|
|
300
159
|
})
|
|
301
160
|
)
|
|
302
161
|
: [];
|
|
303
|
-
const
|
|
304
|
-
let
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
...payload,
|
|
311
|
-
requestedWorkspace: createRequestedWorkspacePayload(
|
|
162
|
+
const workspaces = await workspaceService.listWorkspacesForUser(latestProfile, { request });
|
|
163
|
+
let workspaceContext = null;
|
|
164
|
+
let requestedWorkspace = null;
|
|
165
|
+
if (normalizedWorkspaceSlug && resolvedTenancyProfile.mode !== TENANCY_MODE_NONE) {
|
|
166
|
+
try {
|
|
167
|
+
workspaceContext = await workspaceService.resolveWorkspaceContextForUserBySlug(
|
|
168
|
+
latestProfile,
|
|
312
169
|
normalizedWorkspaceSlug,
|
|
313
|
-
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
})) || normalizedUser;
|
|
324
|
-
|
|
325
|
-
const workspaces = await workspaceService.listWorkspacesForUser(latestProfile, { request });
|
|
326
|
-
let workspaceContext = null;
|
|
327
|
-
let requestedWorkspace = null;
|
|
328
|
-
if (normalizedWorkspaceSlug && resolvedTenancyProfile.mode !== TENANCY_MODE_NONE) {
|
|
329
|
-
try {
|
|
330
|
-
workspaceContext = await workspaceService.resolveWorkspaceContextForUserBySlug(
|
|
331
|
-
latestProfile,
|
|
332
|
-
normalizedWorkspaceSlug,
|
|
333
|
-
{ request }
|
|
334
|
-
);
|
|
335
|
-
requestedWorkspace = createRequestedWorkspacePayload(
|
|
336
|
-
normalizedWorkspaceSlug,
|
|
337
|
-
REQUESTED_WORKSPACE_STATUS_RESOLVED
|
|
338
|
-
);
|
|
339
|
-
} catch (error) {
|
|
340
|
-
const requestedWorkspaceStatus = resolveRequestedWorkspaceStatusFromError(error);
|
|
341
|
-
if (!requestedWorkspaceStatus) {
|
|
342
|
-
throw error;
|
|
343
|
-
}
|
|
344
|
-
requestedWorkspace = createRequestedWorkspacePayload(normalizedWorkspaceSlug, requestedWorkspaceStatus);
|
|
170
|
+
{ request }
|
|
171
|
+
);
|
|
172
|
+
requestedWorkspace = createRequestedWorkspacePayload(
|
|
173
|
+
normalizedWorkspaceSlug,
|
|
174
|
+
REQUESTED_WORKSPACE_STATUS_RESOLVED
|
|
175
|
+
);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const requestedWorkspaceStatus = resolveRequestedWorkspaceStatusFromError(error);
|
|
178
|
+
if (!requestedWorkspaceStatus) {
|
|
179
|
+
throw error;
|
|
345
180
|
}
|
|
181
|
+
requestedWorkspace = createRequestedWorkspacePayload(normalizedWorkspaceSlug, requestedWorkspaceStatus);
|
|
346
182
|
}
|
|
347
|
-
|
|
348
|
-
const userSettings = await userSettingsRepository.ensureForUserId(latestProfile.id);
|
|
349
|
-
payload = {
|
|
350
|
-
session: {
|
|
351
|
-
authenticated: true,
|
|
352
|
-
userId: latestProfile.id
|
|
353
|
-
},
|
|
354
|
-
profile: {
|
|
355
|
-
displayName: latestProfile.displayName,
|
|
356
|
-
email: latestProfile.email,
|
|
357
|
-
avatar: accountAvatarFormatter(latestProfile, userSettings)
|
|
358
|
-
},
|
|
359
|
-
tenancy: resolvedTenancyProfile,
|
|
360
|
-
app: appState,
|
|
361
|
-
workspaces: [...workspaces],
|
|
362
|
-
pendingInvites,
|
|
363
|
-
activeWorkspace: workspaceContext
|
|
364
|
-
? mapWorkspaceSummary(workspaceContext.workspace, {
|
|
365
|
-
roleSid: workspaceContext.membership?.roleSid,
|
|
366
|
-
status: workspaceContext.membership?.status
|
|
367
|
-
})
|
|
368
|
-
: null,
|
|
369
|
-
membership: mapMembershipSummary(workspaceContext?.membership, workspaceContext?.workspace),
|
|
370
|
-
requestedWorkspace,
|
|
371
|
-
permissions: workspaceContext ? [...workspaceContext.permissions] : [],
|
|
372
|
-
surfaceAccess: {
|
|
373
|
-
consoleowner: seededConsoleOwnerUserId > 0 && seededConsoleOwnerUserId === Number(latestProfile.id)
|
|
374
|
-
},
|
|
375
|
-
workspaceSettings: workspaceContext
|
|
376
|
-
? mapWorkspaceSettingsPublic(workspaceContext.workspaceSettings, {
|
|
377
|
-
workspaceInvitationsEnabled
|
|
378
|
-
})
|
|
379
|
-
: null,
|
|
380
|
-
userSettings: mapUserSettingsBootstrap(userSettings),
|
|
381
|
-
requestMeta: {
|
|
382
|
-
hasRequest: Boolean(request)
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
183
|
}
|
|
386
184
|
|
|
387
|
-
const oauthCatalogPayload = getOAuthProviderCatalogPayload(authService);
|
|
388
|
-
const session = payload?.session && typeof payload.session === "object" ? payload.session : { authenticated: false };
|
|
389
|
-
|
|
390
185
|
return {
|
|
391
|
-
...
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
186
|
+
workspaces: [...workspaces],
|
|
187
|
+
pendingInvites,
|
|
188
|
+
activeWorkspace: workspaceContext
|
|
189
|
+
? mapWorkspaceSummary(workspaceContext.workspace, {
|
|
190
|
+
roleSid: workspaceContext.membership?.roleSid,
|
|
191
|
+
status: workspaceContext.membership?.status
|
|
192
|
+
})
|
|
193
|
+
: null,
|
|
194
|
+
membership: mapMembershipSummary(workspaceContext?.membership, workspaceContext?.workspace),
|
|
195
|
+
requestedWorkspace,
|
|
196
|
+
permissions: workspaceContext ? [...workspaceContext.permissions] : [],
|
|
197
|
+
workspaceSettings: workspaceContext
|
|
198
|
+
? mapWorkspaceSettingsPublic(workspaceContext.workspaceSettings, {
|
|
199
|
+
workspaceInvitationsEnabled
|
|
200
|
+
})
|
|
201
|
+
: null
|
|
396
202
|
};
|
|
397
203
|
}
|
|
398
204
|
});
|