@vuu-ui/vuu-data-test 4.0.0-alpha.2 → 4.0.0-alpha.4
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/README.md +8 -0
- package/package.json +9 -8
- package/src/Table.js +5 -5
- package/src/core/module/ModuleContainer.js +8 -0
- package/src/core/module/VuuModule.js +27 -3
- package/src/core/table/TableContainer.js +1 -1
- package/src/index.js +3 -0
- package/src/module-admin/ModuleAdminModule.js +60 -0
- package/src/module-admin/index.js +3 -0
- package/src/module-admin/module-admin-schemas.js +99 -0
- package/src/module-admin/snapshot-projection.js +57 -0
- package/src/schemas.js +8 -2
- package/src/user-admin/UserAdminModule.js +412 -0
- package/src/user-admin/index.js +3 -0
- package/src/user-admin/initialSnapshot.js +477 -0
- package/src/user-admin/snapshot-projection.js +151 -0
- package/types/core/module/ModuleContainer.d.ts +6 -3
- package/types/core/module/VuuModule.d.ts +3 -0
- package/types/core/table/TableContainer.d.ts +5 -5
- package/types/index.d.ts +3 -0
- package/types/module-admin/ModuleAdminModule.d.ts +23 -0
- package/types/module-admin/index.d.ts +4 -0
- package/types/module-admin/module-admin-schemas.d.ts +4 -0
- package/types/module-admin/snapshot-projection.d.ts +14 -0
- package/types/schemas.d.ts +5 -3
- package/types/user-admin/UserAdminModule.d.ts +50 -0
- package/types/user-admin/index.d.ts +3 -0
- package/types/user-admin/initialSnapshot.d.ts +2 -0
- package/types/user-admin/snapshot-projection.d.ts +9 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { USER_ADMIN_RPC_CONTRACT, USER_ADMIN_TABLE_SCHEMAS } from "@heswell/user-admin/contracts";
|
|
2
|
+
import { InMemoryUserAdminStore } from "@heswell/user-admin/in-memory";
|
|
3
|
+
import { VuuModule } from "../core/module/VuuModule.js";
|
|
4
|
+
import TableContainer from "../core/table/TableContainer.js";
|
|
5
|
+
import { Table, buildDataColumnMapFromSchema } from "../Table.js";
|
|
6
|
+
import { USER_ADMIN_INITIAL_SNAPSHOT } from "./initialSnapshot.js";
|
|
7
|
+
import { reconcileUserAdminTables, resolveDisplayName } from "./snapshot-projection.js";
|
|
8
|
+
const createTables = ()=>({
|
|
9
|
+
clients: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.clients),
|
|
10
|
+
group_roles: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.group_roles),
|
|
11
|
+
groups: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.groups),
|
|
12
|
+
roles: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.roles),
|
|
13
|
+
user_group_roles: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.user_group_roles),
|
|
14
|
+
user_groups: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.user_groups),
|
|
15
|
+
users: TableContainer.createTable(USER_ADMIN_TABLE_SCHEMAS.users)
|
|
16
|
+
});
|
|
17
|
+
const errorResult = (error)=>({
|
|
18
|
+
errorMessage: error instanceof Error ? error.message : "User admin request failed",
|
|
19
|
+
type: "ERROR_RESULT"
|
|
20
|
+
});
|
|
21
|
+
const isRecord = (value)=>"object" == typeof value && null !== value && !Array.isArray(value);
|
|
22
|
+
const readParams = (request, rpcName)=>{
|
|
23
|
+
if ("RPC_REQUEST" !== request.type || request.rpcName !== rpcName) throw new Error(`Expected ${rpcName} RPC request`);
|
|
24
|
+
if (!isRecord(request.params)) throw new Error(`${rpcName} requires named parameters`);
|
|
25
|
+
const allowed = new Set(USER_ADMIN_RPC_CONTRACT[rpcName]);
|
|
26
|
+
for (const name of Object.keys(request.params))if (!allowed.has(name)) throw new Error(`${rpcName} received an unsupported parameter: ${name}`);
|
|
27
|
+
return request.params;
|
|
28
|
+
};
|
|
29
|
+
const requiredString = (params, name)=>{
|
|
30
|
+
const value = params[name];
|
|
31
|
+
if ("string" != typeof value || 0 === value.length) throw new Error(`${name} must be a non-empty string`);
|
|
32
|
+
return value;
|
|
33
|
+
};
|
|
34
|
+
const optionalString = (params, name)=>{
|
|
35
|
+
const value = params[name];
|
|
36
|
+
if (void 0 !== value && "string" != typeof value) throw new Error(`${name} must be a string`);
|
|
37
|
+
return value;
|
|
38
|
+
};
|
|
39
|
+
const optionalBoolean = (params, name)=>{
|
|
40
|
+
const value = params[name];
|
|
41
|
+
if (void 0 !== value && "boolean" != typeof value) throw new Error(`${name} must be a boolean`);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
const optionalStringArray = (params, name)=>{
|
|
45
|
+
const value = params[name];
|
|
46
|
+
if (void 0 !== value && (!Array.isArray(value) || value.some((item)=>"string" != typeof item))) throw new Error(`${name} must be an array of strings`);
|
|
47
|
+
return value;
|
|
48
|
+
};
|
|
49
|
+
const reference = (params, idName, name)=>{
|
|
50
|
+
const id = optionalString(params, idName);
|
|
51
|
+
const label = optionalString(params, name);
|
|
52
|
+
if (!id && !label) throw new Error(`${idName} or ${name} is required`);
|
|
53
|
+
return {
|
|
54
|
+
id,
|
|
55
|
+
label
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
const parseAssignments = (value)=>{
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(value);
|
|
62
|
+
} catch {
|
|
63
|
+
throw new Error("assignments must be valid JSON");
|
|
64
|
+
}
|
|
65
|
+
if (!Array.isArray(parsed) || parsed.some((assignment)=>!isRecord(assignment) || "string" != typeof assignment.accessRole || 0 === assignment.accessRole.length || "string" != typeof assignment.groupId || 0 === assignment.groupId.length || Object.keys(assignment).some((name)=>"accessRole" !== name && "groupId" !== name))) throw new Error("assignments must be a JSON array of accessRole and groupId strings");
|
|
66
|
+
return parsed;
|
|
67
|
+
};
|
|
68
|
+
const parseSessionPermissions = (value)=>{
|
|
69
|
+
if ("string" != typeof value) throw new Error("permissions must be a serialized array");
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = JSON.parse(value);
|
|
73
|
+
} catch {
|
|
74
|
+
throw new Error("permissions must be valid JSON");
|
|
75
|
+
}
|
|
76
|
+
if (!Array.isArray(parsed)) throw new Error("permissions must contain application group assignments");
|
|
77
|
+
const accessRoles = new Set();
|
|
78
|
+
const permissions = parsed.map((application, index)=>{
|
|
79
|
+
if (!isRecord(application) || Object.keys(application).some((field)=>"clientIdentifier" !== field && "accessRole" !== field && "groupIds" !== field) || "string" != typeof application.clientIdentifier || 0 === application.clientIdentifier.length || "string" != typeof application.accessRole || 0 === application.accessRole.length || !Array.isArray(application.groupIds) || application.groupIds.some((groupId)=>"string" != typeof groupId || 0 === groupId.length)) throw new Error(`permissions[${index}] must contain clientIdentifier, accessRole, and groupIds`);
|
|
80
|
+
if (accessRoles.has(application.accessRole)) throw new Error(`permissions contains duplicate accessRole: ${application.accessRole}`);
|
|
81
|
+
const groupIds = application.groupIds;
|
|
82
|
+
if (new Set(groupIds).size !== groupIds.length) throw new Error(`permissions contains duplicate group IDs for: ${application.accessRole}`);
|
|
83
|
+
accessRoles.add(application.accessRole);
|
|
84
|
+
return {
|
|
85
|
+
clientIdentifier: application.clientIdentifier,
|
|
86
|
+
accessRole: application.accessRole,
|
|
87
|
+
groupIds
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
return permissions.flatMap(({ groupIds, accessRole })=>groupIds.map((groupId)=>({
|
|
91
|
+
accessRole,
|
|
92
|
+
groupId
|
|
93
|
+
})));
|
|
94
|
+
};
|
|
95
|
+
class UserAdminModule extends VuuModule {
|
|
96
|
+
#tables;
|
|
97
|
+
store;
|
|
98
|
+
constructor(snapshot = USER_ADMIN_INITIAL_SNAPSHOT){
|
|
99
|
+
super("USER_ADMIN");
|
|
100
|
+
this.store = new InMemoryUserAdminStore(snapshot);
|
|
101
|
+
this.#tables = createTables();
|
|
102
|
+
reconcileUserAdminTables(snapshot, this.#tables);
|
|
103
|
+
}
|
|
104
|
+
get schemas() {
|
|
105
|
+
return USER_ADMIN_TABLE_SCHEMAS;
|
|
106
|
+
}
|
|
107
|
+
get tables() {
|
|
108
|
+
return this.#tables;
|
|
109
|
+
}
|
|
110
|
+
get menus() {
|
|
111
|
+
return {
|
|
112
|
+
clients: void 0,
|
|
113
|
+
group_roles: void 0,
|
|
114
|
+
groups: void 0,
|
|
115
|
+
roles: void 0,
|
|
116
|
+
user_group_roles: void 0,
|
|
117
|
+
user_groups: void 0,
|
|
118
|
+
users: void 0
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
get visualLinks() {}
|
|
122
|
+
get menuServices() {}
|
|
123
|
+
get services() {
|
|
124
|
+
const services = [
|
|
125
|
+
{
|
|
126
|
+
rpcName: "addUser",
|
|
127
|
+
service: this.addUser
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
rpcName: "updateUser",
|
|
131
|
+
service: this.updateUser
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
rpcName: "deleteUser",
|
|
135
|
+
service: this.deleteUser
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
rpcName: "addGroup",
|
|
139
|
+
service: this.addGroup
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
rpcName: "updateGroup",
|
|
143
|
+
service: this.updateGroup
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
rpcName: "deleteGroup",
|
|
147
|
+
service: this.deleteGroup
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
rpcName: "addClient",
|
|
151
|
+
service: this.addClient
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
rpcName: "updateClient",
|
|
155
|
+
service: this.updateClient
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
rpcName: "addRole",
|
|
159
|
+
service: this.addRole
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
rpcName: "addClientRole",
|
|
163
|
+
service: this.addClientRole
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
rpcName: "updateRole",
|
|
167
|
+
service: this.updateRole
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
rpcName: "assignGroupRole",
|
|
171
|
+
service: this.assignGroupRole
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
rpcName: "removeGroupRole",
|
|
175
|
+
service: this.removeGroupRole
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
rpcName: "assignUserToGroup",
|
|
179
|
+
service: this.assignUserToGroup
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
rpcName: "removeUserFromGroup",
|
|
183
|
+
service: this.removeUserFromGroup
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
rpcName: "getUserModuleAccessOptions",
|
|
187
|
+
service: this.getUserModuleAccessOptions
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
rpcName: "setUserModuleAccess",
|
|
191
|
+
service: this.setUserModuleAccess
|
|
192
|
+
}
|
|
193
|
+
];
|
|
194
|
+
return {
|
|
195
|
+
clients: services,
|
|
196
|
+
group_roles: services,
|
|
197
|
+
groups: services,
|
|
198
|
+
roles: services,
|
|
199
|
+
user_group_roles: services,
|
|
200
|
+
user_groups: services,
|
|
201
|
+
users: services
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
async reconcile() {
|
|
205
|
+
reconcileUserAdminTables(await this.store.snapshot(), this.#tables);
|
|
206
|
+
}
|
|
207
|
+
createSessionTable(sourceTable, sessionTableName, editSessionMode, dataSource, sessionType) {
|
|
208
|
+
const sessionTable = super.createSessionTable(sourceTable, sessionTableName, editSessionMode, dataSource, sessionType);
|
|
209
|
+
if ("users" !== sourceTable.name) return sessionTable;
|
|
210
|
+
const sessionSchema = {
|
|
211
|
+
...sessionTable.schema,
|
|
212
|
+
columns: sessionTable.schema.columns.concat({
|
|
213
|
+
name: "permissions",
|
|
214
|
+
serverDataType: "string"
|
|
215
|
+
})
|
|
216
|
+
};
|
|
217
|
+
return new Table(sessionSchema, sessionTable.data.map((row)=>row.concat("")), buildDataColumnMapFromSchema(sessionSchema));
|
|
218
|
+
}
|
|
219
|
+
async beforeSessionSave(sourceTable, sessionTable) {
|
|
220
|
+
if ("users" !== sourceTable.name) return;
|
|
221
|
+
const permissionsIndex = sessionTable.map.permissions;
|
|
222
|
+
const actionIndex = sessionTable.map.vuuAction;
|
|
223
|
+
const userIdIndex = sessionTable.map.user_id;
|
|
224
|
+
const usernameIndex = sessionTable.map.username;
|
|
225
|
+
for (const row of sessionTable.data){
|
|
226
|
+
if ("editCell" !== row[actionIndex]) continue;
|
|
227
|
+
const userId = String(row[userIdIndex]);
|
|
228
|
+
const sourceRow = sourceTable.findByKey(userId);
|
|
229
|
+
if (!sourceRow || sourceRow[sourceTable.map.username] !== row[usernameIndex]) throw new Error("username is read-only");
|
|
230
|
+
if ("string" == typeof row[permissionsIndex] && "" !== row[permissionsIndex]) await this.store.setUserModuleAccess(userId, parseSessionPermissions(row[permissionsIndex]));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async afterSessionSave(sourceTable) {
|
|
234
|
+
if ("users" === sourceTable.name) await this.reconcile();
|
|
235
|
+
}
|
|
236
|
+
mutation = (rpcName, mutate)=>async (request)=>{
|
|
237
|
+
try {
|
|
238
|
+
await mutate(readParams(request, rpcName));
|
|
239
|
+
await this.reconcile();
|
|
240
|
+
return {
|
|
241
|
+
data: void 0,
|
|
242
|
+
type: "SUCCESS_RESULT"
|
|
243
|
+
};
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return errorResult(error);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
addUser = this.mutation("addUser", async (params)=>{
|
|
249
|
+
const groupIds = optionalStringArray(params, "group_ids");
|
|
250
|
+
const username = requiredString(params, "username");
|
|
251
|
+
await this.assertUsernameIsUnique(username);
|
|
252
|
+
await this.store.addUser({
|
|
253
|
+
email: optionalString(params, "email"),
|
|
254
|
+
emailVerified: optionalBoolean(params, "emailVerified"),
|
|
255
|
+
enabled: optionalBoolean(params, "enabled"),
|
|
256
|
+
firstName: optionalString(params, "firstName"),
|
|
257
|
+
lastName: optionalString(params, "lastName"),
|
|
258
|
+
temporary_password: optionalString(params, "temporary_password"),
|
|
259
|
+
username
|
|
260
|
+
});
|
|
261
|
+
if (groupIds) {
|
|
262
|
+
const user = await this.store.findUserByUsername(requiredString(params, "username"));
|
|
263
|
+
if (!user) throw new Error("Created user could not be found");
|
|
264
|
+
await this.store.syncUserGroups(user.id, groupIds);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
updateUser = this.mutation("updateUser", async (params)=>{
|
|
268
|
+
const groupIds = optionalStringArray(params, "group_ids");
|
|
269
|
+
const userId = requiredString(params, "userId");
|
|
270
|
+
const username = optionalString(params, "username");
|
|
271
|
+
if (username) await this.assertUsernameIsUnique(username, userId);
|
|
272
|
+
await this.store.updateUser({
|
|
273
|
+
email: optionalString(params, "email"),
|
|
274
|
+
emailVerified: optionalBoolean(params, "emailVerified"),
|
|
275
|
+
enabled: optionalBoolean(params, "enabled"),
|
|
276
|
+
firstName: optionalString(params, "firstName"),
|
|
277
|
+
lastName: optionalString(params, "lastName"),
|
|
278
|
+
temporary_password: optionalString(params, "temporary_password"),
|
|
279
|
+
userId,
|
|
280
|
+
username
|
|
281
|
+
});
|
|
282
|
+
if (groupIds) await this.store.syncUserGroups(userId, groupIds);
|
|
283
|
+
});
|
|
284
|
+
deleteUser = this.mutation("deleteUser", (params)=>this.store.deleteUser(requiredString(params, "userId")));
|
|
285
|
+
addGroup = this.mutation("addGroup", (params)=>this.store.addGroup({
|
|
286
|
+
name: requiredString(params, "name")
|
|
287
|
+
}));
|
|
288
|
+
updateGroup = this.mutation("updateGroup", (params)=>this.store.updateGroup(requiredString(params, "groupId"), {
|
|
289
|
+
name: requiredString(params, "name")
|
|
290
|
+
}));
|
|
291
|
+
deleteGroup = this.mutation("deleteGroup", (params)=>this.store.deleteGroup(requiredString(params, "groupId")));
|
|
292
|
+
addClient = this.mutation("addClient", (params)=>this.store.addClient({
|
|
293
|
+
clientId: requiredString(params, "clientId"),
|
|
294
|
+
description: optionalString(params, "description"),
|
|
295
|
+
enabled: optionalBoolean(params, "enabled"),
|
|
296
|
+
name: optionalString(params, "name")
|
|
297
|
+
}));
|
|
298
|
+
updateClient = this.mutation("updateClient", (params)=>this.store.updateClient(requiredString(params, "clientId"), {
|
|
299
|
+
description: optionalString(params, "description"),
|
|
300
|
+
enabled: optionalBoolean(params, "enabled"),
|
|
301
|
+
name: optionalString(params, "name")
|
|
302
|
+
}));
|
|
303
|
+
addRole = this.mutation("addRole", (params)=>this.store.addRole({
|
|
304
|
+
description: optionalString(params, "description"),
|
|
305
|
+
name: requiredString(params, "name")
|
|
306
|
+
}));
|
|
307
|
+
addClientRole = this.mutation("addClientRole", (params)=>this.store.addClientRole({
|
|
308
|
+
clientKey: requiredString(params, "clientId")
|
|
309
|
+
}, {
|
|
310
|
+
description: optionalString(params, "description"),
|
|
311
|
+
name: requiredString(params, "name")
|
|
312
|
+
}));
|
|
313
|
+
updateRole = this.mutation("updateRole", async (params)=>{
|
|
314
|
+
const clientId = optionalString(params, "clientId");
|
|
315
|
+
const changes = {
|
|
316
|
+
description: optionalString(params, "description"),
|
|
317
|
+
name: optionalString(params, "name")
|
|
318
|
+
};
|
|
319
|
+
if (clientId) await this.store.updateClientRole(clientId, requiredString(params, "roleName"), changes);
|
|
320
|
+
else await this.store.updateRealmRole(requiredString(params, "roleId"), changes);
|
|
321
|
+
});
|
|
322
|
+
assignGroupRole = this.mutation("assignGroupRole", (params)=>{
|
|
323
|
+
const group = reference(params, "groupId", "groupName");
|
|
324
|
+
const role = reference(params, "roleId", "roleName");
|
|
325
|
+
const clientId = optionalString(params, "clientId");
|
|
326
|
+
return this.store.addRoleToGroup({
|
|
327
|
+
groupId: group.id,
|
|
328
|
+
groupName: group.label
|
|
329
|
+
}, {
|
|
330
|
+
roleId: role.id,
|
|
331
|
+
roleName: role.label
|
|
332
|
+
}, clientId ? {
|
|
333
|
+
clientKey: clientId
|
|
334
|
+
} : void 0);
|
|
335
|
+
});
|
|
336
|
+
removeGroupRole = this.mutation("removeGroupRole", (params)=>{
|
|
337
|
+
const group = reference(params, "groupId", "groupName");
|
|
338
|
+
const role = reference(params, "roleId", "roleName");
|
|
339
|
+
const clientId = optionalString(params, "clientId");
|
|
340
|
+
return this.store.removeRoleFromGroup({
|
|
341
|
+
groupId: group.id,
|
|
342
|
+
groupName: group.label
|
|
343
|
+
}, {
|
|
344
|
+
roleId: role.id,
|
|
345
|
+
roleName: role.label
|
|
346
|
+
}, clientId ? {
|
|
347
|
+
clientKey: clientId
|
|
348
|
+
} : void 0);
|
|
349
|
+
});
|
|
350
|
+
assignUserToGroup = this.mutation("assignUserToGroup", (params)=>{
|
|
351
|
+
const user = reference(params, "userId", "username");
|
|
352
|
+
const group = reference(params, "groupId", "groupName");
|
|
353
|
+
return this.store.addUserToGroup({
|
|
354
|
+
userId: user.id,
|
|
355
|
+
username: user.label
|
|
356
|
+
}, {
|
|
357
|
+
groupId: group.id,
|
|
358
|
+
groupName: group.label
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
removeUserFromGroup = this.mutation("removeUserFromGroup", (params)=>{
|
|
362
|
+
const user = reference(params, "userId", "username");
|
|
363
|
+
const group = reference(params, "groupId", "groupName");
|
|
364
|
+
return this.store.removeUserFromGroup({
|
|
365
|
+
userId: user.id,
|
|
366
|
+
username: user.label
|
|
367
|
+
}, {
|
|
368
|
+
groupId: group.id,
|
|
369
|
+
groupName: group.label
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
getUserModuleAccessOptions = async (request)=>{
|
|
373
|
+
try {
|
|
374
|
+
const params = readParams(request, "getUserModuleAccessOptions");
|
|
375
|
+
const [options, snapshot] = await Promise.all([
|
|
376
|
+
this.store.getUserModuleAccessOptions(requiredString(params, "userId")),
|
|
377
|
+
this.store.snapshot()
|
|
378
|
+
]);
|
|
379
|
+
const groupDisplayNames = new Map(snapshot.groups.map(({ groupDisplayName, id, name })=>[
|
|
380
|
+
id,
|
|
381
|
+
resolveDisplayName(name, groupDisplayName)
|
|
382
|
+
]));
|
|
383
|
+
const roleDisplayNames = new Map(snapshot.clientRoles.map(({ role })=>[
|
|
384
|
+
role.id,
|
|
385
|
+
resolveDisplayName(role.name, role.roleDisplayName)
|
|
386
|
+
]));
|
|
387
|
+
return {
|
|
388
|
+
data: {
|
|
389
|
+
modules: options.modules.map(({ groups, ...module })=>({
|
|
390
|
+
...module,
|
|
391
|
+
groups: groups.map((group)=>({
|
|
392
|
+
...group,
|
|
393
|
+
groupDisplayName: groupDisplayNames.get(group.groupId) ?? resolveDisplayName(group.groupName),
|
|
394
|
+
roleDisplayName: roleDisplayNames.get(group.roleId) ?? resolveDisplayName(group.roleName)
|
|
395
|
+
}))
|
|
396
|
+
}))
|
|
397
|
+
},
|
|
398
|
+
type: "SUCCESS_RESULT"
|
|
399
|
+
};
|
|
400
|
+
} catch (error) {
|
|
401
|
+
return errorResult(error);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
setUserModuleAccess = this.mutation("setUserModuleAccess", (params)=>this.store.setUserModuleAccess(requiredString(params, "userId"), parseAssignments(requiredString(params, "assignments"))));
|
|
405
|
+
async assertUsernameIsUnique(username, userId) {
|
|
406
|
+
const normalizedUsername = username.toLocaleLowerCase();
|
|
407
|
+
const existingUser = (await this.store.snapshot()).users.find((user)=>user.id !== userId && user.username.toLocaleLowerCase() === normalizedUsername);
|
|
408
|
+
if (existingUser) throw new Error("username must be unique");
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const userAdminModule = new UserAdminModule();
|
|
412
|
+
export { UserAdminModule, userAdminModule };
|