@jskit-ai/users-core 0.1.64 → 0.1.66
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 +14 -65
- package/package.json +10 -10
- package/src/server/UsersCoreServiceProvider.js +18 -2
- package/src/server/accountNotifications/accountNotificationsActions.js +3 -5
- package/src/server/accountNotifications/accountNotificationsService.js +3 -2
- package/src/server/accountNotifications/bootAccountNotificationsRoutes.js +12 -11
- package/src/server/accountPreferences/accountPreferencesActions.js +3 -5
- package/src/server/accountPreferences/accountPreferencesService.js +3 -2
- package/src/server/accountPreferences/bootAccountPreferencesRoutes.js +12 -11
- package/src/server/accountProfile/accountProfileActions.js +15 -32
- package/src/server/accountProfile/accountProfileService.js +9 -8
- package/src/server/accountProfile/bootAccountProfileRoutes.js +25 -19
- package/src/server/accountSecurity/accountSecurityActions.js +21 -16
- package/src/server/accountSecurity/accountSecurityService.js +16 -6
- package/src/server/accountSecurity/bootAccountSecurityRoutes.js +52 -40
- package/src/server/common/formatters/accountSettingsResponseFormatter.js +8 -18
- package/src/server/common/registerCommonRepositories.js +5 -2
- package/src/server/common/repositories/userProfilesRepository.js +227 -88
- package/src/server/common/repositories/userSettingsRepository.js +108 -100
- package/src/server/common/support/accountSettingsJsonApiTransport.js +10 -0
- package/src/server/usersBootstrapContributor.js +13 -32
- package/src/shared/resources/accountSettingsSchemas.js +83 -0
- package/src/shared/resources/userProfileResource.js +146 -126
- package/src/shared/resources/userSettingsResource.js +376 -353
- package/templates/packages/users/package.descriptor.mjs +4 -5
- package/templates/packages/users/package.json +0 -1
- package/templates/packages/users/src/server/UsersProvider.js +23 -24
- package/templates/packages/users/src/server/actions.js +26 -28
- package/templates/packages/users/src/server/registerRoutes.js +29 -15
- package/templates/packages/users/src/server/repository.js +35 -28
- package/templates/packages/users/src/server/service.js +20 -15
- package/templates/packages/users/src/shared/userResource.js +55 -68
- package/templates/packages/users-workspace/package.descriptor.mjs +4 -5
- package/templates/packages/users-workspace/src/server/UsersProvider.js +23 -24
- package/templates/packages/users-workspace/src/server/actions.js +28 -28
- package/templates/packages/users-workspace/src/server/registerRoutes.js +34 -16
- package/test/accountSecurityService.test.js +32 -0
- package/test/providerLifecycle.test.js +63 -0
- package/test/registerCommonRepositories.test.js +28 -8
- package/test/repositoryContracts.test.js +177 -28
- package/test/resourcesCanonical.test.js +18 -11
- package/test/userSettingsInternalResource.test.js +8 -0
- package/test/userSettingsResource.test.js +24 -7
- package/test/usersBootstrapContributor.test.js +40 -1
- package/test/usersPackageScaffoldContract.test.js +70 -3
- package/test/usersRouteRequestInputValidator.test.js +92 -23
- package/test/usersRouteResources.test.js +28 -18
- package/src/server/common/resources/userProfilesResource.js +0 -203
- package/src/server/common/validators/authenticatedUserValidator.js +0 -43
- package/src/shared/resources/resolveGlobalArrayRegistry.js +0 -6
- package/src/shared/resources/userSettingsFields.js +0 -76
- package/templates/packages/main/src/shared/resources/userSettingsFields.js +0 -138
- package/templates/packages/users/src/server/actionIds.js +0 -6
- package/templates/packages/users/src/server/listConfig.js +0 -16
- package/test/settingsFieldRegistriesSingleton.test.js +0 -14
- package/test-support/registerDefaultSettingsFields.js +0 -2
package/package.descriptor.mjs
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/users-core",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.66",
|
|
5
5
|
kind: "runtime",
|
|
6
6
|
description: "Users/account runtime plus HTTP routes for account features.",
|
|
7
7
|
dependsOn: [
|
|
8
8
|
"@jskit-ai/auth-core",
|
|
9
9
|
"@jskit-ai/database-runtime",
|
|
10
10
|
"@jskit-ai/http-runtime",
|
|
11
|
+
"@jskit-ai/json-rest-api-core",
|
|
12
|
+
"@jskit-ai/resource-core",
|
|
13
|
+
"@jskit-ai/resource-crud-core",
|
|
11
14
|
"@jskit-ai/uploads-runtime",
|
|
12
15
|
"@jskit-ai/storage-runtime"
|
|
13
16
|
],
|
|
@@ -19,6 +22,7 @@ export default Object.freeze({
|
|
|
19
22
|
requires: [
|
|
20
23
|
"runtime.actions",
|
|
21
24
|
"runtime.database",
|
|
25
|
+
"json-rest-api.core",
|
|
22
26
|
"runtime.storage",
|
|
23
27
|
"runtime.uploads",
|
|
24
28
|
"auth.provider",
|
|
@@ -128,15 +132,16 @@ export default Object.freeze({
|
|
|
128
132
|
mutations: {
|
|
129
133
|
dependencies: {
|
|
130
134
|
runtime: {
|
|
131
|
-
"@jskit-ai/auth-core": "0.1.
|
|
132
|
-
"@jskit-ai/crud-core": "0.1.
|
|
133
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
134
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
135
|
-
"@jskit-ai/
|
|
135
|
+
"@jskit-ai/auth-core": "0.1.55",
|
|
136
|
+
"@jskit-ai/crud-core": "0.1.64",
|
|
137
|
+
"@jskit-ai/database-runtime": "0.1.56",
|
|
138
|
+
"@jskit-ai/http-runtime": "0.1.55",
|
|
139
|
+
"@jskit-ai/json-rest-api-core": "0.1.1",
|
|
140
|
+
"@jskit-ai/kernel": "0.1.56",
|
|
141
|
+
"@jskit-ai/resource-core": "0.1.1",
|
|
142
|
+
"@jskit-ai/resource-crud-core": "0.1.1",
|
|
136
143
|
"@local/users": "file:packages/users",
|
|
137
|
-
"@jskit-ai/uploads-runtime": "0.1.
|
|
138
|
-
"@fastify/type-provider-typebox": "^6.1.0",
|
|
139
|
-
typebox: "^1.0.81"
|
|
144
|
+
"@jskit-ai/uploads-runtime": "0.1.34"
|
|
140
145
|
},
|
|
141
146
|
dev: {}
|
|
142
147
|
},
|
|
@@ -163,14 +168,6 @@ export default Object.freeze({
|
|
|
163
168
|
category: "migration",
|
|
164
169
|
id: "users-core-profile-username-schema"
|
|
165
170
|
},
|
|
166
|
-
{
|
|
167
|
-
from: "templates/packages/main/src/shared/resources/userSettingsFields.js",
|
|
168
|
-
to: "packages/main/src/shared/resources/userSettingsFields.js",
|
|
169
|
-
preserveOnRemove: true,
|
|
170
|
-
reason: "Install app-owned user settings field definitions.",
|
|
171
|
-
category: "users-core",
|
|
172
|
-
id: "users-core-app-owned-user-settings-fields"
|
|
173
|
-
},
|
|
174
171
|
{
|
|
175
172
|
from: "templates/packages/users/package.json",
|
|
176
173
|
to: "packages/users/package.json",
|
|
@@ -232,15 +229,6 @@ export default Object.freeze({
|
|
|
232
229
|
in: ["personal", "workspaces"]
|
|
233
230
|
}
|
|
234
231
|
},
|
|
235
|
-
{
|
|
236
|
-
from: "templates/packages/users/src/server/actionIds.js",
|
|
237
|
-
to: "packages/users/src/server/actionIds.js",
|
|
238
|
-
ownership: "app",
|
|
239
|
-
preserveOnRemove: true,
|
|
240
|
-
reason: "Install app-owned users CRUD action IDs.",
|
|
241
|
-
category: "users-core",
|
|
242
|
-
id: "users-core-users-action-ids"
|
|
243
|
-
},
|
|
244
232
|
{
|
|
245
233
|
from: "templates/packages/users/src/server/actions.js",
|
|
246
234
|
to: "packages/users/src/server/actions.js",
|
|
@@ -267,15 +255,6 @@ export default Object.freeze({
|
|
|
267
255
|
in: ["personal", "workspaces"]
|
|
268
256
|
}
|
|
269
257
|
},
|
|
270
|
-
{
|
|
271
|
-
from: "templates/packages/users/src/server/listConfig.js",
|
|
272
|
-
to: "packages/users/src/server/listConfig.js",
|
|
273
|
-
ownership: "app",
|
|
274
|
-
preserveOnRemove: true,
|
|
275
|
-
reason: "Install app-owned users CRUD list configuration.",
|
|
276
|
-
category: "users-core",
|
|
277
|
-
id: "users-core-users-list-config"
|
|
278
|
-
},
|
|
279
258
|
{
|
|
280
259
|
from: "templates/packages/users/src/server/registerRoutes.js",
|
|
281
260
|
to: "packages/users/src/server/registerRoutes.js",
|
|
@@ -349,36 +328,6 @@ export default Object.freeze({
|
|
|
349
328
|
category: "runtime-config",
|
|
350
329
|
id: "users-core-auth-profile-mode"
|
|
351
330
|
},
|
|
352
|
-
{
|
|
353
|
-
op: "append-text",
|
|
354
|
-
file: "packages/main/src/shared/index.js",
|
|
355
|
-
position: "top",
|
|
356
|
-
skipIfContains: "import \"./resources/userSettingsFields.js\";",
|
|
357
|
-
value: "import \"./resources/userSettingsFields.js\";\n",
|
|
358
|
-
reason: "Load app-owned user settings field definitions inside the main shared module.",
|
|
359
|
-
category: "users-core",
|
|
360
|
-
id: "users-core-main-shared-user-settings-field-import"
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
op: "append-text",
|
|
364
|
-
file: "src/main.js",
|
|
365
|
-
position: "top",
|
|
366
|
-
skipIfContains: "import \"@local/main/shared\";",
|
|
367
|
-
value: "import \"@local/main/shared\";\n",
|
|
368
|
-
reason: "Ensure client runtime loads app-owned shared settings field registration.",
|
|
369
|
-
category: "users-core",
|
|
370
|
-
id: "users-core-client-import-main-shared"
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
op: "append-text",
|
|
374
|
-
file: "server.js",
|
|
375
|
-
position: "top",
|
|
376
|
-
skipIfContains: "import \"@local/main/shared\";",
|
|
377
|
-
value: "import \"@local/main/shared\";\n",
|
|
378
|
-
reason: "Ensure server runtime loads app-owned shared settings field registration.",
|
|
379
|
-
category: "users-core",
|
|
380
|
-
id: "users-core-server-import-main-shared"
|
|
381
|
-
}
|
|
382
331
|
]
|
|
383
332
|
}
|
|
384
333
|
});
|
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/users-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.66",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
9
|
"./server/profileSyncLifecycleContributorRegistry": "./src/server/profileSyncLifecycleContributorRegistry.js",
|
|
10
|
-
"./shared/settings": "./src/shared/settings.js",
|
|
11
10
|
"./shared/resources/userProfileResource": "./src/shared/resources/userProfileResource.js",
|
|
12
|
-
"./shared/resources/userSettingsFields": "./src/shared/resources/userSettingsFields.js",
|
|
13
11
|
"./shared/resources/userSettingsResource": "./src/shared/resources/userSettingsResource.js"
|
|
14
12
|
},
|
|
15
13
|
"dependencies": {
|
|
16
|
-
"@jskit-ai/auth-core": "0.1.
|
|
17
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
18
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
19
|
-
"@jskit-ai/
|
|
20
|
-
"@jskit-ai/
|
|
21
|
-
"@
|
|
22
|
-
"
|
|
14
|
+
"@jskit-ai/auth-core": "0.1.55",
|
|
15
|
+
"@jskit-ai/database-runtime": "0.1.56",
|
|
16
|
+
"@jskit-ai/http-runtime": "0.1.55",
|
|
17
|
+
"@jskit-ai/json-rest-api-core": "0.1.1",
|
|
18
|
+
"@jskit-ai/kernel": "0.1.56",
|
|
19
|
+
"@jskit-ai/resource-crud-core": "0.1.1",
|
|
20
|
+
"@jskit-ai/resource-core": "0.1.1",
|
|
21
|
+
"@jskit-ai/uploads-runtime": "0.1.34",
|
|
22
|
+
"json-rest-schema": "1.x.x"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { USERS_SHARED_API } from "../shared/index.js";
|
|
2
|
+
import {
|
|
3
|
+
INTERNAL_JSON_REST_API,
|
|
4
|
+
addResourceIfMissing,
|
|
5
|
+
createJsonRestResourceScopeOptions
|
|
6
|
+
} from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
7
|
+
import { toDatabaseDateTimeUtc } from "@jskit-ai/database-runtime/shared";
|
|
2
8
|
import { bootAccountProfileRoutes } from "./accountProfile/bootAccountProfileRoutes.js";
|
|
3
9
|
import { bootAccountPreferencesRoutes } from "./accountPreferences/bootAccountPreferencesRoutes.js";
|
|
4
10
|
import { bootAccountNotificationsRoutes } from "./accountNotifications/bootAccountNotificationsRoutes.js";
|
|
@@ -11,13 +17,15 @@ import { registerAccountPreferences } from "./accountPreferences/registerAccount
|
|
|
11
17
|
import { registerAccountNotifications } from "./accountNotifications/registerAccountNotifications.js";
|
|
12
18
|
import { registerAccountProfile } from "./accountProfile/registerAccountProfile.js";
|
|
13
19
|
import { registerAccountSecurity } from "./accountSecurity/registerAccountSecurity.js";
|
|
20
|
+
import { userProfileResource } from "../shared/resources/userProfileResource.js";
|
|
21
|
+
import { userSettingsResource } from "../shared/resources/userSettingsResource.js";
|
|
14
22
|
|
|
15
23
|
class UsersCoreServiceProvider {
|
|
16
24
|
static id = "users.core";
|
|
17
25
|
|
|
18
|
-
static dependsOn = ["runtime.server", "runtime.actions", "runtime.database", "runtime.storage", "auth.provider", "runtime.uploads"];
|
|
26
|
+
static dependsOn = ["runtime.server", "runtime.actions", "runtime.database", "runtime.storage", "auth.provider", "runtime.uploads", "json-rest-api.core"];
|
|
19
27
|
|
|
20
|
-
register(app) {
|
|
28
|
+
async register(app) {
|
|
21
29
|
registerSharedApi(app, USERS_SHARED_API);
|
|
22
30
|
registerCommonRepositories(app);
|
|
23
31
|
registerUsersCore(app);
|
|
@@ -30,6 +38,14 @@ class UsersCoreServiceProvider {
|
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
async boot(app) {
|
|
41
|
+
const api = app.make(INTERNAL_JSON_REST_API);
|
|
42
|
+
const scopeOptions = {
|
|
43
|
+
writeSerializers: {
|
|
44
|
+
"datetime-utc": toDatabaseDateTimeUtc
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
await addResourceIfMissing(api, "userProfiles", createJsonRestResourceScopeOptions(userProfileResource, scopeOptions));
|
|
48
|
+
await addResourceIfMissing(api, "userSettings", createJsonRestResourceScopeOptions(userSettingsResource, scopeOptions));
|
|
33
49
|
bootAccountProfileRoutes(app);
|
|
34
50
|
bootAccountPreferencesRoutes(app);
|
|
35
51
|
bootAccountNotificationsRoutes(app);
|
|
@@ -14,10 +14,8 @@ const accountNotificationsActions = Object.freeze([
|
|
|
14
14
|
permission: {
|
|
15
15
|
require: "authenticated"
|
|
16
16
|
},
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
outputValidator: userSettingsResource.operations.view.outputValidator,
|
|
17
|
+
input: userSettingsResource.operations.notificationsUpdate.body,
|
|
18
|
+
output: null,
|
|
21
19
|
idempotency: "optional",
|
|
22
20
|
audit: {
|
|
23
21
|
actionName: "settings.notifications.update"
|
|
@@ -27,7 +25,7 @@ const accountNotificationsActions = Object.freeze([
|
|
|
27
25
|
return deps.accountNotificationsService.updateNotifications(
|
|
28
26
|
resolveRequest(context),
|
|
29
27
|
resolveActionUser(context, input),
|
|
30
|
-
input
|
|
28
|
+
input,
|
|
31
29
|
{
|
|
32
30
|
context
|
|
33
31
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AppError } from "@jskit-ai/kernel/server/runtime/errors";
|
|
2
|
+
import { returnJsonApiData } from "@jskit-ai/http-runtime/shared";
|
|
2
3
|
import {
|
|
3
4
|
resolveUserProfile,
|
|
4
5
|
resolveSecurityStatus
|
|
@@ -25,12 +26,12 @@ function createService({
|
|
|
25
26
|
const settings = await userSettingsRepository.updateNotifications(profile.id, payload);
|
|
26
27
|
const securityStatus = await resolveSecurityStatus(authService, request);
|
|
27
28
|
|
|
28
|
-
return accountSettingsResponseFormatter({
|
|
29
|
+
return returnJsonApiData(accountSettingsResponseFormatter({
|
|
29
30
|
profile,
|
|
30
31
|
settings,
|
|
31
32
|
securityStatus,
|
|
32
33
|
authService
|
|
33
|
-
});
|
|
34
|
+
}));
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
return Object.freeze({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createJsonApiResourceRouteContract } from "@jskit-ai/http-runtime/shared/validators/jsonApiRouteTransport";
|
|
2
2
|
import { userSettingsResource } from "../../shared/resources/userSettingsResource.js";
|
|
3
|
+
import { resolveAccountSettingsResourceId } from "../common/support/accountSettingsJsonApiTransport.js";
|
|
3
4
|
|
|
4
5
|
function bootAccountNotificationsRoutes(app) {
|
|
5
6
|
if (!app || typeof app.make !== "function") {
|
|
@@ -17,20 +18,20 @@ function bootAccountNotificationsRoutes(app) {
|
|
|
17
18
|
tags: ["settings"],
|
|
18
19
|
summary: "Update notification settings"
|
|
19
20
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
...createJsonApiResourceRouteContract({
|
|
22
|
+
requestType: "user-notification-settings",
|
|
23
|
+
responseType: "user-settings",
|
|
24
|
+
body: userSettingsResource.operations.notificationsUpdate.body,
|
|
25
|
+
output: userSettingsResource.operations.view.output,
|
|
26
|
+
outputKind: "record",
|
|
27
|
+
getRecordId: resolveAccountSettingsResourceId,
|
|
28
|
+
includeValidation400: true
|
|
29
|
+
})
|
|
27
30
|
},
|
|
28
31
|
async function (request, reply) {
|
|
29
32
|
const response = await request.executeAction({
|
|
30
33
|
actionId: "settings.notifications.update",
|
|
31
|
-
input:
|
|
32
|
-
payload: request.input.body
|
|
33
|
-
}
|
|
34
|
+
input: request.input.body
|
|
34
35
|
});
|
|
35
36
|
reply.code(200).send(response);
|
|
36
37
|
}
|
|
@@ -14,10 +14,8 @@ const accountPreferencesActions = Object.freeze([
|
|
|
14
14
|
permission: {
|
|
15
15
|
require: "authenticated"
|
|
16
16
|
},
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
outputValidator: userSettingsResource.operations.view.outputValidator,
|
|
17
|
+
input: userSettingsResource.operations.preferencesUpdate.body,
|
|
18
|
+
output: null,
|
|
21
19
|
idempotency: "optional",
|
|
22
20
|
audit: {
|
|
23
21
|
actionName: "settings.preferences.update"
|
|
@@ -27,7 +25,7 @@ const accountPreferencesActions = Object.freeze([
|
|
|
27
25
|
return deps.accountPreferencesService.updatePreferences(
|
|
28
26
|
resolveRequest(context),
|
|
29
27
|
resolveActionUser(context, input),
|
|
30
|
-
input
|
|
28
|
+
input,
|
|
31
29
|
{
|
|
32
30
|
context
|
|
33
31
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AppError } from "@jskit-ai/kernel/server/runtime/errors";
|
|
2
|
+
import { returnJsonApiData } from "@jskit-ai/http-runtime/shared";
|
|
2
3
|
import {
|
|
3
4
|
resolveUserProfile,
|
|
4
5
|
resolveSecurityStatus
|
|
@@ -25,12 +26,12 @@ function createService({
|
|
|
25
26
|
const settings = await userSettingsRepository.updatePreferences(profile.id, payload);
|
|
26
27
|
const securityStatus = await resolveSecurityStatus(authService, request);
|
|
27
28
|
|
|
28
|
-
return accountSettingsResponseFormatter({
|
|
29
|
+
return returnJsonApiData(accountSettingsResponseFormatter({
|
|
29
30
|
profile,
|
|
30
31
|
settings,
|
|
31
32
|
securityStatus,
|
|
32
33
|
authService
|
|
33
|
-
});
|
|
34
|
+
}));
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
return Object.freeze({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createJsonApiResourceRouteContract } from "@jskit-ai/http-runtime/shared/validators/jsonApiRouteTransport";
|
|
2
2
|
import { userSettingsResource } from "../../shared/resources/userSettingsResource.js";
|
|
3
|
+
import { resolveAccountSettingsResourceId } from "../common/support/accountSettingsJsonApiTransport.js";
|
|
3
4
|
|
|
4
5
|
function bootAccountPreferencesRoutes(app) {
|
|
5
6
|
if (!app || typeof app.make !== "function") {
|
|
@@ -17,20 +18,20 @@ function bootAccountPreferencesRoutes(app) {
|
|
|
17
18
|
tags: ["settings"],
|
|
18
19
|
summary: "Update user preferences"
|
|
19
20
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
...createJsonApiResourceRouteContract({
|
|
22
|
+
requestType: "user-preferences",
|
|
23
|
+
responseType: "user-settings",
|
|
24
|
+
body: userSettingsResource.operations.preferencesUpdate.body,
|
|
25
|
+
output: userSettingsResource.operations.view.output,
|
|
26
|
+
outputKind: "record",
|
|
27
|
+
getRecordId: resolveAccountSettingsResourceId,
|
|
28
|
+
includeValidation400: true
|
|
29
|
+
})
|
|
27
30
|
},
|
|
28
31
|
async function (request, reply) {
|
|
29
32
|
const response = await request.executeAction({
|
|
30
33
|
actionId: "settings.preferences.update",
|
|
31
|
-
input:
|
|
32
|
-
payload: request.input.body
|
|
33
|
-
}
|
|
34
|
+
input: request.input.body
|
|
34
35
|
});
|
|
35
36
|
reply.code(200).send(response);
|
|
36
37
|
}
|
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
emptyInputValidator,
|
|
3
3
|
resolveRequest
|
|
4
4
|
} from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
|
|
5
|
-
import {
|
|
6
|
-
import { normalizeObjectInput } from "@jskit-ai/kernel/shared/validators/inputNormalization";
|
|
7
|
-
import { userSettingsResource } from "../../shared/resources/userSettingsResource.js";
|
|
5
|
+
import { deepFreeze } from "@jskit-ai/kernel/shared/support/deepFreeze";
|
|
8
6
|
import { userProfileResource } from "../../shared/resources/userProfileResource.js";
|
|
9
7
|
import { resolveActionUser } from "../common/support/resolveActionUser.js";
|
|
10
8
|
|
|
11
|
-
const
|
|
12
|
-
schema:
|
|
13
|
-
|
|
14
|
-
settings: userSettingsResource.operations.view.outputValidator.schema,
|
|
15
|
-
session: Type.Union([Type.Object({}, { additionalProperties: true }), Type.Null()])
|
|
16
|
-
},
|
|
17
|
-
{ additionalProperties: false }
|
|
18
|
-
),
|
|
19
|
-
normalize(payload = {}) {
|
|
20
|
-
const source = normalizeObjectInput(payload);
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
settings: userSettingsResource.operations.view.outputValidator.normalize(source.settings),
|
|
24
|
-
session: source.session && typeof source.session === "object" ? source.session : null
|
|
25
|
-
};
|
|
26
|
-
}
|
|
9
|
+
const settingsProfileUpdateInputValidator = deepFreeze({
|
|
10
|
+
schema: userProfileResource.operations.patch.body.schema,
|
|
11
|
+
mode: userProfileResource.operations.patch.body.mode
|
|
27
12
|
});
|
|
28
13
|
|
|
29
|
-
const accountProfileActions =
|
|
14
|
+
const accountProfileActions = deepFreeze([
|
|
30
15
|
{
|
|
31
16
|
id: "settings.read",
|
|
32
17
|
version: 1,
|
|
@@ -36,8 +21,8 @@ const accountProfileActions = Object.freeze([
|
|
|
36
21
|
permission: {
|
|
37
22
|
require: "authenticated"
|
|
38
23
|
},
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
input: emptyInputValidator,
|
|
25
|
+
output: null,
|
|
41
26
|
idempotency: "none",
|
|
42
27
|
audit: {
|
|
43
28
|
actionName: "settings.read"
|
|
@@ -58,10 +43,8 @@ const accountProfileActions = Object.freeze([
|
|
|
58
43
|
permission: {
|
|
59
44
|
require: "authenticated"
|
|
60
45
|
},
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
},
|
|
64
|
-
outputValidator: settingsProfileUpdateOutputValidator,
|
|
46
|
+
input: settingsProfileUpdateInputValidator,
|
|
47
|
+
output: null,
|
|
65
48
|
idempotency: "optional",
|
|
66
49
|
audit: {
|
|
67
50
|
actionName: "settings.profile.update"
|
|
@@ -71,7 +54,7 @@ const accountProfileActions = Object.freeze([
|
|
|
71
54
|
return deps.accountProfileService.updateProfile(
|
|
72
55
|
resolveRequest(context),
|
|
73
56
|
resolveActionUser(context, input),
|
|
74
|
-
input
|
|
57
|
+
input,
|
|
75
58
|
{
|
|
76
59
|
context
|
|
77
60
|
}
|
|
@@ -87,8 +70,8 @@ const accountProfileActions = Object.freeze([
|
|
|
87
70
|
permission: {
|
|
88
71
|
require: "authenticated"
|
|
89
72
|
},
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
input: userProfileResource.operations.avatarUpload.body,
|
|
74
|
+
output: null,
|
|
92
75
|
idempotency: "none",
|
|
93
76
|
audit: {
|
|
94
77
|
actionName: "settings.profile.avatar.upload"
|
|
@@ -121,8 +104,8 @@ const accountProfileActions = Object.freeze([
|
|
|
121
104
|
permission: {
|
|
122
105
|
require: "authenticated"
|
|
123
106
|
},
|
|
124
|
-
|
|
125
|
-
|
|
107
|
+
input: userProfileResource.operations.avatarDelete.body,
|
|
108
|
+
output: null,
|
|
126
109
|
idempotency: "none",
|
|
127
110
|
audit: {
|
|
128
111
|
actionName: "settings.profile.avatar.delete"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AppError } from "@jskit-ai/kernel/server/runtime/errors";
|
|
2
|
+
import { returnJsonApiData } from "@jskit-ai/http-runtime/shared";
|
|
2
3
|
import {
|
|
3
4
|
resolveUserProfile,
|
|
4
5
|
resolveSecurityStatus
|
|
@@ -26,12 +27,12 @@ function createService({
|
|
|
26
27
|
const settings = await userSettingsRepository.ensureForUserId(profile.id);
|
|
27
28
|
const securityStatus = await resolveSecurityStatus(authService, request);
|
|
28
29
|
|
|
29
|
-
return accountSettingsResponseFormatter({
|
|
30
|
+
return returnJsonApiData(accountSettingsResponseFormatter({
|
|
30
31
|
profile,
|
|
31
32
|
settings,
|
|
32
33
|
securityStatus,
|
|
33
34
|
authService
|
|
34
|
-
});
|
|
35
|
+
}));
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
async function updateProfile(request, user, payload = {}, options = {}) {
|
|
@@ -57,12 +58,12 @@ function createService({
|
|
|
57
58
|
|
|
58
59
|
return {
|
|
59
60
|
session,
|
|
60
|
-
|
|
61
|
+
response: returnJsonApiData(accountSettingsResponseFormatter({
|
|
61
62
|
profile: updatedProfile,
|
|
62
63
|
settings,
|
|
63
64
|
securityStatus,
|
|
64
65
|
authService
|
|
65
|
-
})
|
|
66
|
+
}))
|
|
66
67
|
};
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -78,12 +79,12 @@ function createService({
|
|
|
78
79
|
const settings = await userSettingsRepository.ensureForUserId(profile.id);
|
|
79
80
|
const securityStatus = await resolveSecurityStatus(authService, request);
|
|
80
81
|
|
|
81
|
-
return accountSettingsResponseFormatter({
|
|
82
|
+
return returnJsonApiData(accountSettingsResponseFormatter({
|
|
82
83
|
profile,
|
|
83
84
|
settings,
|
|
84
85
|
securityStatus,
|
|
85
86
|
authService
|
|
86
|
-
});
|
|
87
|
+
}));
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
async function deleteAvatar(request, user, options = {}) {
|
|
@@ -93,12 +94,12 @@ function createService({
|
|
|
93
94
|
const settings = await userSettingsRepository.ensureForUserId(profile.id);
|
|
94
95
|
const securityStatus = await resolveSecurityStatus(authService, request);
|
|
95
96
|
|
|
96
|
-
return accountSettingsResponseFormatter({
|
|
97
|
+
return returnJsonApiData(accountSettingsResponseFormatter({
|
|
97
98
|
profile,
|
|
98
99
|
settings,
|
|
99
100
|
securityStatus,
|
|
100
101
|
authService
|
|
101
|
-
});
|
|
102
|
+
}));
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
async function readAvatar(_request, user, options = {}) {
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { withStandardErrorResponses } from "@jskit-ai/http-runtime/shared/validators/errorResponses";
|
|
2
|
+
import { createJsonApiResourceRouteContract } from "@jskit-ai/http-runtime/shared/validators/jsonApiRouteTransport";
|
|
2
3
|
import { DEFAULT_IMAGE_UPLOAD_MAX_BYTES } from "@jskit-ai/uploads-runtime/shared";
|
|
3
4
|
import { readSingleMultipartFile } from "@jskit-ai/uploads-runtime/server/multipart/readSingleMultipartFile";
|
|
4
5
|
import { userSettingsResource } from "../../shared/resources/userSettingsResource.js";
|
|
5
6
|
import { userProfileResource } from "../../shared/resources/userProfileResource.js";
|
|
7
|
+
import { resolveAccountSettingsResourceId } from "../common/support/accountSettingsJsonApiTransport.js";
|
|
8
|
+
|
|
9
|
+
const USER_SETTINGS_RESOURCE_TRANSPORT = Object.freeze({
|
|
10
|
+
responseType: "user-settings",
|
|
11
|
+
output: userSettingsResource.operations.view.output,
|
|
12
|
+
outputKind: "record",
|
|
13
|
+
getRecordId: resolveAccountSettingsResourceId
|
|
14
|
+
});
|
|
6
15
|
|
|
7
16
|
function bootAccountProfileRoutes(app) {
|
|
8
17
|
if (!app || typeof app.make !== "function") {
|
|
@@ -10,8 +19,6 @@ function bootAccountProfileRoutes(app) {
|
|
|
10
19
|
}
|
|
11
20
|
|
|
12
21
|
const router = app.make("jskit.http.router");
|
|
13
|
-
const authService = app.make("authService");
|
|
14
|
-
const accountProfileService = app.make("users.accountProfile.service");
|
|
15
22
|
|
|
16
23
|
router.register(
|
|
17
24
|
"GET",
|
|
@@ -22,8 +29,8 @@ function bootAccountProfileRoutes(app) {
|
|
|
22
29
|
tags: ["settings"],
|
|
23
30
|
summary: "Get authenticated user's settings"
|
|
24
31
|
},
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
...createJsonApiResourceRouteContract({
|
|
33
|
+
...USER_SETTINGS_RESOURCE_TRANSPORT
|
|
27
34
|
})
|
|
28
35
|
},
|
|
29
36
|
async function (request, reply) {
|
|
@@ -43,27 +50,25 @@ function bootAccountProfileRoutes(app) {
|
|
|
43
50
|
tags: ["settings"],
|
|
44
51
|
summary: "Update profile settings"
|
|
45
52
|
},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
+
...createJsonApiResourceRouteContract({
|
|
54
|
+
requestType: "user-profiles",
|
|
55
|
+
body: userProfileResource.operations.patch.body,
|
|
56
|
+
includeValidation400: true,
|
|
57
|
+
...USER_SETTINGS_RESOURCE_TRANSPORT
|
|
58
|
+
})
|
|
53
59
|
},
|
|
54
60
|
async function (request, reply) {
|
|
55
61
|
const result = await request.executeAction({
|
|
56
62
|
actionId: "settings.profile.update",
|
|
57
|
-
input:
|
|
58
|
-
payload: request.input.body
|
|
59
|
-
}
|
|
63
|
+
input: request.input.body
|
|
60
64
|
});
|
|
61
65
|
|
|
66
|
+
const authService = app.make("authService");
|
|
62
67
|
if (result?.session && typeof authService.writeSessionCookies === "function") {
|
|
63
68
|
authService.writeSessionCookies(reply, result.session);
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
reply.code(200).send(result?.
|
|
71
|
+
reply.code(200).send(result?.response || result);
|
|
67
72
|
}
|
|
68
73
|
);
|
|
69
74
|
|
|
@@ -78,6 +83,7 @@ function bootAccountProfileRoutes(app) {
|
|
|
78
83
|
}
|
|
79
84
|
},
|
|
80
85
|
async function (request, reply) {
|
|
86
|
+
const accountProfileService = app.make("users.accountProfile.service");
|
|
81
87
|
const avatar = await accountProfileService.readAvatar(request, request.user, {
|
|
82
88
|
context: {
|
|
83
89
|
actor: request.user
|
|
@@ -106,9 +112,9 @@ function bootAccountProfileRoutes(app) {
|
|
|
106
112
|
consumes: ["multipart/form-data"]
|
|
107
113
|
}
|
|
108
114
|
},
|
|
109
|
-
|
|
115
|
+
responses: withStandardErrorResponses(
|
|
110
116
|
{
|
|
111
|
-
200: userProfileResource.operations.avatarUpload.
|
|
117
|
+
200: userProfileResource.operations.avatarUpload.output
|
|
112
118
|
},
|
|
113
119
|
{ includeValidation400: true }
|
|
114
120
|
)
|
|
@@ -146,8 +152,8 @@ function bootAccountProfileRoutes(app) {
|
|
|
146
152
|
tags: ["settings"],
|
|
147
153
|
summary: "Delete profile avatar and fallback to gravatar"
|
|
148
154
|
},
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
...createJsonApiResourceRouteContract({
|
|
156
|
+
...USER_SETTINGS_RESOURCE_TRANSPORT
|
|
151
157
|
})
|
|
152
158
|
},
|
|
153
159
|
async function (request, reply) {
|