@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
|
@@ -1,405 +1,428 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSchema } from "json-rest-schema";
|
|
2
|
+
import { deepFreeze } from "@jskit-ai/kernel/shared/support/deepFreeze";
|
|
3
|
+
import { normalizeLowerText, normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
2
4
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "@jskit-ai/kernel/shared/validators";
|
|
7
|
-
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
5
|
+
createSchemaDefinition
|
|
6
|
+
} from "@jskit-ai/resource-core/shared/resource";
|
|
7
|
+
import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
|
|
8
8
|
import { createOperationMessages } from "../operationMessages.js";
|
|
9
|
-
import {
|
|
9
|
+
import { DEFAULT_USER_SETTINGS } from "../settings.js";
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "./
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return Type.Object(properties, { additionalProperties: false });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function buildSectionOutputSchema(section) {
|
|
45
|
-
const properties = {};
|
|
46
|
-
for (const field of listFieldsBySection(section)) {
|
|
47
|
-
properties[field.key] = field.outputSchema;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return Type.Object(properties, { additionalProperties: false });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function normalizeInput(payload = {}) {
|
|
54
|
-
return normalizeSettingsFieldInput(payload, userSettingsFields);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function normalizeSectionOutput(section, sectionSource = {}, settings = {}) {
|
|
58
|
-
const normalized = {};
|
|
59
|
-
for (const field of listFieldsBySection(section)) {
|
|
60
|
-
const rawValue = Object.hasOwn(sectionSource, field.key)
|
|
61
|
-
? sectionSource[field.key]
|
|
62
|
-
: field.resolveDefault({
|
|
63
|
-
settings
|
|
64
|
-
});
|
|
65
|
-
normalized[field.key] = field.normalizeOutput(rawValue, {
|
|
66
|
-
settings
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return normalized;
|
|
11
|
+
accountSecurityStatusSchema,
|
|
12
|
+
userProfileOutputSchema
|
|
13
|
+
} from "./accountSettingsSchemas.js";
|
|
14
|
+
|
|
15
|
+
const USER_SETTINGS_PREFERENCE_KEYS = deepFreeze([
|
|
16
|
+
"theme",
|
|
17
|
+
"locale",
|
|
18
|
+
"timeZone",
|
|
19
|
+
"dateFormat",
|
|
20
|
+
"numberFormat",
|
|
21
|
+
"currencyCode",
|
|
22
|
+
"avatarSize"
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
const USER_SETTINGS_NOTIFICATION_KEYS = deepFreeze([
|
|
26
|
+
"productUpdates",
|
|
27
|
+
"accountActivity",
|
|
28
|
+
"securityAlerts"
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const USER_SETTINGS_ALL_KEYS = deepFreeze([
|
|
32
|
+
...USER_SETTINGS_PREFERENCE_KEYS,
|
|
33
|
+
...USER_SETTINGS_NOTIFICATION_KEYS
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const USER_SETTINGS_BOOTSTRAP_KEYS = USER_SETTINGS_ALL_KEYS;
|
|
37
|
+
|
|
38
|
+
function normalizePositiveInteger(value) {
|
|
39
|
+
return Number(value);
|
|
70
40
|
}
|
|
71
41
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
get schema() {
|
|
86
|
-
return buildUserSettingsOutputSchema();
|
|
42
|
+
const userSettingsBodySchema = createSchema({
|
|
43
|
+
theme: { type: "string", required: true, minLength: 1, maxLength: 32 },
|
|
44
|
+
locale: { type: "string", required: true, minLength: 1, maxLength: 24, lowercase: true },
|
|
45
|
+
timeZone: { type: "string", required: true, minLength: 1, maxLength: 64 },
|
|
46
|
+
dateFormat: { type: "string", required: true, minLength: 1, maxLength: 32 },
|
|
47
|
+
numberFormat: { type: "string", required: true, minLength: 1, maxLength: 32 },
|
|
48
|
+
currencyCode: {
|
|
49
|
+
type: "string",
|
|
50
|
+
required: true,
|
|
51
|
+
minLength: 3,
|
|
52
|
+
maxLength: 3,
|
|
53
|
+
uppercase: true,
|
|
54
|
+
pattern: "^[A-Z]{3}$"
|
|
87
55
|
},
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
56
|
+
avatarSize: { type: "number", required: true, min: 1 },
|
|
57
|
+
productUpdates: {
|
|
58
|
+
type: "boolean",
|
|
59
|
+
required: true,
|
|
60
|
+
strictBoolean: true,
|
|
61
|
+
messages: {
|
|
62
|
+
default: "productUpdates must be a boolean."
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
accountActivity: {
|
|
66
|
+
type: "boolean",
|
|
67
|
+
required: true,
|
|
68
|
+
strictBoolean: true,
|
|
69
|
+
messages: {
|
|
70
|
+
default: "accountActivity must be a boolean."
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
securityAlerts: {
|
|
74
|
+
type: "boolean",
|
|
75
|
+
required: true,
|
|
76
|
+
strictBoolean: true,
|
|
77
|
+
messages: {
|
|
78
|
+
default: "securityAlerts must be a boolean."
|
|
79
|
+
}
|
|
107
80
|
}
|
|
108
81
|
});
|
|
109
82
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
buildUserSettingsPatchBodySchema(),
|
|
124
|
-
listFieldsBySection(USER_SETTINGS_SECTIONS.PREFERENCES).map((field) => field.key)
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function buildNotificationsUpdateBodySchema() {
|
|
129
|
-
return pickPatchBody(
|
|
130
|
-
buildUserSettingsPatchBodySchema(),
|
|
131
|
-
listFieldsBySection(USER_SETTINGS_SECTIONS.NOTIFICATIONS).map((field) => field.key)
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const preferencesUpdateBodyValidator = Object.freeze({
|
|
136
|
-
get schema() {
|
|
137
|
-
return buildPreferencesUpdateBodySchema();
|
|
83
|
+
const userSettingsPreferencesSchema = createSchema({
|
|
84
|
+
theme: { type: "string", required: true, minLength: 1, maxLength: 32 },
|
|
85
|
+
locale: { type: "string", required: true, minLength: 1, maxLength: 24, lowercase: true },
|
|
86
|
+
timeZone: { type: "string", required: true, minLength: 1, maxLength: 64 },
|
|
87
|
+
dateFormat: { type: "string", required: true, minLength: 1, maxLength: 32 },
|
|
88
|
+
numberFormat: { type: "string", required: true, minLength: 1, maxLength: 32 },
|
|
89
|
+
currencyCode: {
|
|
90
|
+
type: "string",
|
|
91
|
+
required: true,
|
|
92
|
+
minLength: 3,
|
|
93
|
+
maxLength: 3,
|
|
94
|
+
uppercase: true,
|
|
95
|
+
pattern: "^[A-Z]{3}$"
|
|
138
96
|
},
|
|
139
|
-
|
|
97
|
+
avatarSize: { type: "number", required: true, min: 1 }
|
|
140
98
|
});
|
|
141
99
|
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
100
|
+
const userSettingsNotificationsSchema = createSchema({
|
|
101
|
+
productUpdates: {
|
|
102
|
+
type: "boolean",
|
|
103
|
+
required: true,
|
|
104
|
+
strictBoolean: true,
|
|
105
|
+
messages: {
|
|
106
|
+
default: "productUpdates must be a boolean."
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
accountActivity: {
|
|
110
|
+
type: "boolean",
|
|
111
|
+
required: true,
|
|
112
|
+
strictBoolean: true,
|
|
113
|
+
messages: {
|
|
114
|
+
default: "accountActivity must be a boolean."
|
|
115
|
+
}
|
|
145
116
|
},
|
|
146
|
-
|
|
117
|
+
securityAlerts: {
|
|
118
|
+
type: "boolean",
|
|
119
|
+
required: true,
|
|
120
|
+
strictBoolean: true,
|
|
121
|
+
messages: {
|
|
122
|
+
default: "securityAlerts must be a boolean."
|
|
123
|
+
}
|
|
124
|
+
}
|
|
147
125
|
});
|
|
148
126
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
127
|
+
const userSettingsOutputSchema = createSchema({
|
|
128
|
+
profile: {
|
|
129
|
+
type: "object",
|
|
130
|
+
required: true,
|
|
131
|
+
schema: userProfileOutputSchema
|
|
132
|
+
},
|
|
133
|
+
security: {
|
|
134
|
+
type: "object",
|
|
135
|
+
required: true,
|
|
136
|
+
schema: accountSecurityStatusSchema
|
|
137
|
+
},
|
|
138
|
+
preferences: {
|
|
139
|
+
type: "object",
|
|
140
|
+
required: true,
|
|
141
|
+
schema: userSettingsPreferencesSchema
|
|
142
|
+
},
|
|
143
|
+
notifications: {
|
|
144
|
+
type: "object",
|
|
145
|
+
required: true,
|
|
146
|
+
schema: userSettingsNotificationsSchema
|
|
153
147
|
}
|
|
148
|
+
});
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
provider: normalizeText(source.provider)
|
|
157
|
-
};
|
|
158
|
-
}
|
|
150
|
+
const userSettingsOutputValidator = createSchemaDefinition(userSettingsOutputSchema, "replace");
|
|
159
151
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
152
|
+
const passwordMethodToggleOutputSchema = createSchema({
|
|
153
|
+
securityStatus: {
|
|
154
|
+
type: "object",
|
|
155
|
+
required: true,
|
|
156
|
+
schema: accountSecurityStatusSchema
|
|
157
|
+
},
|
|
158
|
+
settings: {
|
|
159
|
+
type: "object",
|
|
160
|
+
required: true,
|
|
161
|
+
schema: userSettingsOutputSchema
|
|
164
162
|
}
|
|
163
|
+
});
|
|
165
164
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
const oauthUnlinkOutputSchema = createSchema({
|
|
166
|
+
securityStatus: {
|
|
167
|
+
type: "object",
|
|
168
|
+
required: true,
|
|
169
|
+
schema: accountSecurityStatusSchema
|
|
169
170
|
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
returnTo
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const settingsActionOutputValidator = Object.freeze({
|
|
177
|
-
schema: Type.Object({}, { additionalProperties: true }),
|
|
178
|
-
normalize: normalizeObjectInput
|
|
179
171
|
});
|
|
180
172
|
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
173
|
+
const passwordChangeBodySchema = createSchema({
|
|
174
|
+
currentPassword: {
|
|
175
|
+
type: "string",
|
|
176
|
+
required: false,
|
|
177
|
+
minLength: 1,
|
|
178
|
+
messages: {
|
|
179
|
+
default: "Current password is invalid."
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
newPassword: {
|
|
183
|
+
type: "string",
|
|
184
|
+
required: true,
|
|
185
|
+
minLength: 8,
|
|
186
|
+
messages: {
|
|
187
|
+
required: "New password is required.",
|
|
188
|
+
minLength: "New password must be at least 8 characters.",
|
|
189
|
+
default: "New password must be at least 8 characters."
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
confirmPassword: {
|
|
193
|
+
type: "string",
|
|
194
|
+
required: true,
|
|
195
|
+
minLength: 1,
|
|
196
|
+
messages: {
|
|
197
|
+
required: "Confirm password is required.",
|
|
198
|
+
minLength: "Confirm password is required.",
|
|
199
|
+
default: "Confirm password is required."
|
|
200
|
+
}
|
|
201
|
+
}
|
|
190
202
|
});
|
|
191
203
|
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
currentPassword: Type.Optional(
|
|
196
|
-
Type.String({
|
|
197
|
-
minLength: 1,
|
|
198
|
-
messages: {
|
|
199
|
-
default: "Current password is invalid."
|
|
200
|
-
}
|
|
201
|
-
})
|
|
202
|
-
),
|
|
203
|
-
newPassword: Type.String({
|
|
204
|
-
minLength: 8,
|
|
205
|
-
messages: {
|
|
206
|
-
required: "New password is required.",
|
|
207
|
-
minLength: "New password must be at least 8 characters.",
|
|
208
|
-
default: "New password must be at least 8 characters."
|
|
209
|
-
}
|
|
210
|
-
}),
|
|
211
|
-
confirmPassword: Type.String({
|
|
212
|
-
minLength: 1,
|
|
213
|
-
messages: {
|
|
214
|
-
required: "Confirm password is required.",
|
|
215
|
-
minLength: "Confirm password is required.",
|
|
216
|
-
default: "Confirm password is required."
|
|
217
|
-
}
|
|
218
|
-
})
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
additionalProperties: false,
|
|
222
|
-
messages: {
|
|
223
|
-
additionalProperties: "Unexpected field."
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
),
|
|
227
|
-
normalize: normalizeObjectInput
|
|
204
|
+
const passwordChangeOutputSchema = createSchema({
|
|
205
|
+
ok: { type: "boolean", required: true },
|
|
206
|
+
message: { type: "string", required: true, minLength: 1 }
|
|
228
207
|
});
|
|
229
208
|
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
})
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
additionalProperties: false,
|
|
242
|
-
messages: {
|
|
243
|
-
additionalProperties: "Unexpected field."
|
|
244
|
-
}
|
|
209
|
+
const passwordMethodToggleBodySchema = createSchema({
|
|
210
|
+
enabled: {
|
|
211
|
+
type: "boolean",
|
|
212
|
+
required: true,
|
|
213
|
+
strictBoolean: true,
|
|
214
|
+
messages: {
|
|
215
|
+
required: "enabled is required.",
|
|
216
|
+
default: "enabled must be a boolean."
|
|
245
217
|
}
|
|
246
|
-
|
|
247
|
-
normalize: normalizeObjectInput
|
|
218
|
+
}
|
|
248
219
|
});
|
|
249
220
|
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
})
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
additionalProperties: false,
|
|
264
|
-
messages: {
|
|
265
|
-
additionalProperties: "Unexpected field."
|
|
266
|
-
}
|
|
221
|
+
const oauthProviderParamsSchema = createSchema({
|
|
222
|
+
provider: {
|
|
223
|
+
type: "string",
|
|
224
|
+
required: true,
|
|
225
|
+
minLength: 2,
|
|
226
|
+
maxLength: 64,
|
|
227
|
+
messages: {
|
|
228
|
+
required: "OAuth provider is required.",
|
|
229
|
+
default: "OAuth provider is invalid."
|
|
267
230
|
}
|
|
268
|
-
|
|
269
|
-
normalize: normalizeOAuthProviderParams
|
|
231
|
+
}
|
|
270
232
|
});
|
|
271
233
|
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
default: "Return path is invalid."
|
|
280
|
-
}
|
|
281
|
-
})
|
|
282
|
-
)
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
additionalProperties: false,
|
|
286
|
-
messages: {
|
|
287
|
-
additionalProperties: "Unexpected field."
|
|
288
|
-
}
|
|
234
|
+
const oauthProviderQuerySchema = createSchema({
|
|
235
|
+
returnTo: {
|
|
236
|
+
type: "string",
|
|
237
|
+
required: false,
|
|
238
|
+
minLength: 1,
|
|
239
|
+
messages: {
|
|
240
|
+
default: "Return path is invalid."
|
|
289
241
|
}
|
|
290
|
-
|
|
291
|
-
normalize: normalizeOAuthProviderQuery
|
|
242
|
+
}
|
|
292
243
|
});
|
|
293
244
|
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
returnTo: Type.String({ minLength: 1 }),
|
|
299
|
-
url: Type.String({ minLength: 1 })
|
|
300
|
-
},
|
|
301
|
-
{ additionalProperties: false }
|
|
302
|
-
),
|
|
303
|
-
normalize: normalizeObjectInput
|
|
245
|
+
const oauthLinkStartOutputSchema = createSchema({
|
|
246
|
+
provider: { type: "string", required: true, minLength: 2, maxLength: 64 },
|
|
247
|
+
returnTo: { type: "string", required: true, minLength: 1 },
|
|
248
|
+
url: { type: "string", required: true, minLength: 1 }
|
|
304
249
|
});
|
|
305
250
|
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
normalize: normalizeObjectInput
|
|
251
|
+
const logoutOtherSessionsOutputSchema = createSchema({
|
|
252
|
+
ok: { type: "boolean", required: true }
|
|
309
253
|
});
|
|
310
254
|
|
|
311
255
|
const USER_SETTINGS_OPERATION_MESSAGES = createOperationMessages();
|
|
312
256
|
|
|
313
|
-
const userSettingsResource =
|
|
257
|
+
const userSettingsResource = defineCrudResource({
|
|
314
258
|
namespace: "userSettings",
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
259
|
+
tableName: "user_settings",
|
|
260
|
+
idProperty: "user_id",
|
|
261
|
+
searchSchema: {
|
|
262
|
+
id: { type: "id", actualField: "id" }
|
|
263
|
+
},
|
|
264
|
+
schema: {
|
|
265
|
+
id: {
|
|
266
|
+
type: "id",
|
|
267
|
+
primary: true,
|
|
268
|
+
required: true,
|
|
269
|
+
search: true,
|
|
270
|
+
storage: { column: "user_id" }
|
|
271
|
+
},
|
|
272
|
+
theme: {
|
|
273
|
+
type: "string",
|
|
274
|
+
required: true,
|
|
275
|
+
max: 32,
|
|
276
|
+
defaultTo: DEFAULT_USER_SETTINGS.theme,
|
|
277
|
+
setter: (value) => normalizeText(value)
|
|
278
|
+
},
|
|
279
|
+
locale: {
|
|
280
|
+
type: "string",
|
|
281
|
+
required: true,
|
|
282
|
+
max: 24,
|
|
283
|
+
defaultTo: DEFAULT_USER_SETTINGS.locale,
|
|
284
|
+
setter: (value) => normalizeLowerText(value)
|
|
285
|
+
},
|
|
286
|
+
timeZone: {
|
|
287
|
+
type: "string",
|
|
288
|
+
required: true,
|
|
289
|
+
max: 64,
|
|
290
|
+
defaultTo: DEFAULT_USER_SETTINGS.timeZone,
|
|
291
|
+
storage: { column: "time_zone" },
|
|
292
|
+
setter: (value) => normalizeText(value)
|
|
293
|
+
},
|
|
294
|
+
dateFormat: {
|
|
295
|
+
type: "string",
|
|
296
|
+
required: true,
|
|
297
|
+
max: 32,
|
|
298
|
+
defaultTo: DEFAULT_USER_SETTINGS.dateFormat,
|
|
299
|
+
storage: { column: "date_format" },
|
|
300
|
+
setter: (value) => normalizeText(value)
|
|
301
|
+
},
|
|
302
|
+
numberFormat: {
|
|
303
|
+
type: "string",
|
|
304
|
+
required: true,
|
|
305
|
+
max: 32,
|
|
306
|
+
defaultTo: DEFAULT_USER_SETTINGS.numberFormat,
|
|
307
|
+
storage: { column: "number_format" },
|
|
308
|
+
setter: (value) => normalizeText(value)
|
|
309
|
+
},
|
|
310
|
+
currencyCode: {
|
|
311
|
+
type: "string",
|
|
312
|
+
required: true,
|
|
313
|
+
minLength: 3,
|
|
314
|
+
maxLength: 3,
|
|
315
|
+
defaultTo: DEFAULT_USER_SETTINGS.currencyCode,
|
|
316
|
+
storage: { column: "currency_code" },
|
|
317
|
+
setter: (value) => normalizeText(value).toUpperCase()
|
|
318
|
+
},
|
|
319
|
+
avatarSize: {
|
|
320
|
+
type: "number",
|
|
321
|
+
required: true,
|
|
322
|
+
min: 1,
|
|
323
|
+
defaultTo: DEFAULT_USER_SETTINGS.avatarSize,
|
|
324
|
+
storage: { column: "avatar_size" },
|
|
325
|
+
setter: (value) => normalizePositiveInteger(value)
|
|
326
|
+
},
|
|
327
|
+
passwordSignInEnabled: {
|
|
328
|
+
type: "boolean",
|
|
329
|
+
required: true,
|
|
330
|
+
defaultTo: DEFAULT_USER_SETTINGS.passwordSignInEnabled,
|
|
331
|
+
storage: { column: "password_sign_in_enabled" }
|
|
332
|
+
},
|
|
333
|
+
passwordSetupRequired: {
|
|
334
|
+
type: "boolean",
|
|
335
|
+
required: true,
|
|
336
|
+
defaultTo: DEFAULT_USER_SETTINGS.passwordSetupRequired,
|
|
337
|
+
storage: { column: "password_setup_required" }
|
|
338
|
+
},
|
|
339
|
+
productUpdates: {
|
|
340
|
+
type: "boolean",
|
|
341
|
+
required: true,
|
|
342
|
+
defaultTo: DEFAULT_USER_SETTINGS.productUpdates,
|
|
343
|
+
storage: { column: "notify_product_updates" }
|
|
344
|
+
},
|
|
345
|
+
accountActivity: {
|
|
346
|
+
type: "boolean",
|
|
347
|
+
required: true,
|
|
348
|
+
defaultTo: DEFAULT_USER_SETTINGS.accountActivity,
|
|
349
|
+
storage: { column: "notify_account_activity" }
|
|
350
|
+
},
|
|
351
|
+
securityAlerts: {
|
|
352
|
+
type: "boolean",
|
|
353
|
+
required: true,
|
|
354
|
+
defaultTo: DEFAULT_USER_SETTINGS.securityAlerts,
|
|
355
|
+
storage: { column: "notify_security_alerts" }
|
|
356
|
+
},
|
|
357
|
+
createdAt: {
|
|
358
|
+
type: "dateTime",
|
|
359
|
+
default: "now()",
|
|
360
|
+
storage: {
|
|
361
|
+
column: "created_at",
|
|
362
|
+
writeSerializer: "datetime-utc"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
updatedAt: {
|
|
366
|
+
type: "dateTime",
|
|
367
|
+
default: "now()",
|
|
368
|
+
storage: {
|
|
369
|
+
column: "updated_at",
|
|
370
|
+
writeSerializer: "datetime-utc"
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
messages: USER_SETTINGS_OPERATION_MESSAGES,
|
|
375
|
+
crudOperations: ["view", "list", "create", "replace", "patch"],
|
|
376
|
+
crud: {
|
|
377
|
+
output: userSettingsOutputValidator,
|
|
378
|
+
body: userSettingsBodySchema
|
|
379
|
+
},
|
|
380
|
+
operations: {
|
|
381
|
+
preferencesUpdate: {
|
|
360
382
|
method: "PATCH",
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
notificationsUpdate: Object.freeze({
|
|
383
|
+
body: userSettingsPreferencesSchema,
|
|
384
|
+
output: userSettingsOutputValidator
|
|
385
|
+
},
|
|
386
|
+
notificationsUpdate: {
|
|
366
387
|
method: "PATCH",
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
passwordChange: Object.freeze({
|
|
388
|
+
body: userSettingsNotificationsSchema,
|
|
389
|
+
output: userSettingsOutputValidator
|
|
390
|
+
},
|
|
391
|
+
passwordChange: {
|
|
372
392
|
method: "POST",
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
passwordMethodToggle: Object.freeze({
|
|
393
|
+
body: passwordChangeBodySchema,
|
|
394
|
+
output: passwordChangeOutputSchema
|
|
395
|
+
},
|
|
396
|
+
passwordMethodToggle: {
|
|
378
397
|
method: "PATCH",
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
oauthLinkStart: Object.freeze({
|
|
398
|
+
body: passwordMethodToggleBodySchema,
|
|
399
|
+
output: passwordMethodToggleOutputSchema
|
|
400
|
+
},
|
|
401
|
+
oauthLinkStart: {
|
|
384
402
|
method: "GET",
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
oauthUnlink: Object.freeze({
|
|
403
|
+
params: oauthProviderParamsSchema,
|
|
404
|
+
query: oauthProviderQuerySchema,
|
|
405
|
+
output: oauthLinkStartOutputSchema
|
|
406
|
+
},
|
|
407
|
+
oauthUnlink: {
|
|
391
408
|
method: "DELETE",
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
logoutOtherSessions: Object.freeze({
|
|
409
|
+
params: oauthProviderParamsSchema,
|
|
410
|
+
output: oauthUnlinkOutputSchema
|
|
411
|
+
},
|
|
412
|
+
logoutOtherSessions: {
|
|
397
413
|
method: "POST",
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
})
|
|
414
|
+
body: createSchema({}),
|
|
415
|
+
output: logoutOtherSessionsOutputSchema
|
|
416
|
+
}
|
|
417
|
+
}
|
|
403
418
|
});
|
|
404
419
|
|
|
405
|
-
export {
|
|
420
|
+
export {
|
|
421
|
+
USER_SETTINGS_ALL_KEYS,
|
|
422
|
+
USER_SETTINGS_BOOTSTRAP_KEYS,
|
|
423
|
+
USER_SETTINGS_NOTIFICATION_KEYS,
|
|
424
|
+
USER_SETTINGS_PREFERENCE_KEYS,
|
|
425
|
+
userSettingsOutputSchema,
|
|
426
|
+
userSettingsOutputValidator,
|
|
427
|
+
userSettingsResource
|
|
428
|
+
};
|