shuttlepro-shared 1.2.70 → 1.2.72
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.
|
@@ -1,578 +1,182 @@
|
|
|
1
|
-
// const { UserRole } = require("../../models/UserRole");
|
|
2
|
-
// const { getRedisData, setRedisData } = require("../../config/redis");
|
|
3
|
-
|
|
4
|
-
// const defaultSelect =
|
|
5
|
-
// "iconUrl thumbUrl name productsCount ordersCount contact email address websiteUrl facebookUrl twitterUrl instagramUrl members defaultModule";
|
|
6
|
-
|
|
7
|
-
// // Cache keys
|
|
8
|
-
// const CACHE_KEY_ALL_MEMBERS = "userroles_all_members";
|
|
9
|
-
|
|
10
|
-
// const getCachedMembers = async (filter = {}) => {
|
|
11
|
-
// try {
|
|
12
|
-
// let members = await getRedisData(CACHE_KEY_ALL_MEMBERS);
|
|
13
|
-
|
|
14
|
-
// if (!members) {
|
|
15
|
-
// members = await UserRole.find()
|
|
16
|
-
// .select("userId role userShift roleId workspaceId")
|
|
17
|
-
// .populate({
|
|
18
|
-
// path: "roleId",
|
|
19
|
-
// select: "id name userId userShift permissionId modulePermissions",
|
|
20
|
-
// populate: [{ path: "permissionId", select: "id name" }],
|
|
21
|
-
// })
|
|
22
|
-
// .populate({
|
|
23
|
-
// path: "userId",
|
|
24
|
-
// match: { isDeleted: false, suspended: false },
|
|
25
|
-
// select: "firstName lastName role email picture userShift _id",
|
|
26
|
-
// })
|
|
27
|
-
// .lean()
|
|
28
|
-
// .exec();
|
|
29
|
-
|
|
30
|
-
// members = members?.filter((m) => m?.userId && m?.roleId) || [];
|
|
31
|
-
// await setRedisData(CACHE_KEY_ALL_MEMBERS, members);
|
|
32
|
-
// }
|
|
33
|
-
|
|
34
|
-
// const userIdFilter = filter.userId
|
|
35
|
-
// ? new Set(
|
|
36
|
-
// Array.isArray(filter.userId)
|
|
37
|
-
// ? filter.userId.map((id) => id.toString())
|
|
38
|
-
// : [filter.userId.toString()]
|
|
39
|
-
// )
|
|
40
|
-
// : null;
|
|
41
|
-
|
|
42
|
-
// const roleIdFilter = filter.roleId
|
|
43
|
-
// ? Array.isArray(filter.roleId)
|
|
44
|
-
// ? new Set(filter.roleId.map((id) => id.toString()))
|
|
45
|
-
// : typeof filter.roleId === "object"
|
|
46
|
-
// ? filter.roleId
|
|
47
|
-
// : new Set([filter.roleId.toString()])
|
|
48
|
-
// : null;
|
|
49
|
-
|
|
50
|
-
// return members.filter((member) => {
|
|
51
|
-
// // Optimize userId filter
|
|
52
|
-
// if (userIdFilter && !userIdFilter.has(member.userId?._id?.toString())) {
|
|
53
|
-
// return false;
|
|
54
|
-
// }
|
|
55
|
-
|
|
56
|
-
// // Optimize roleId filter
|
|
57
|
-
// if (roleIdFilter) {
|
|
58
|
-
// if (roleIdFilter instanceof Set) {
|
|
59
|
-
// const roleIdStr =
|
|
60
|
-
// member.roleId?._id?.toString() ?? member.roleId?.id?.toString();
|
|
61
|
-
// if (!roleIdFilter.has(roleIdStr)) return false;
|
|
62
|
-
// } else if (typeof roleIdFilter === "object") {
|
|
63
|
-
// for (const [key, value] of Object.entries(roleIdFilter)) {
|
|
64
|
-
// const roleVal = key.includes(".")
|
|
65
|
-
// ? key.split(".").reduce((obj, k) => obj?.[k], member.roleId)
|
|
66
|
-
// : member.roleId?.[key];
|
|
67
|
-
// if (Array.isArray(value)) {
|
|
68
|
-
// if (!value.includes(roleVal)) return false;
|
|
69
|
-
// } else if (roleVal !== value) {
|
|
70
|
-
// return false;
|
|
71
|
-
// }
|
|
72
|
-
// }
|
|
73
|
-
// }
|
|
74
|
-
// }
|
|
75
|
-
|
|
76
|
-
// // General filters
|
|
77
|
-
// for (const [key, value] of Object.entries(filter)) {
|
|
78
|
-
// if (key === "userId" || key === "roleId") continue;
|
|
79
|
-
|
|
80
|
-
// const memberValue = key.includes(".")
|
|
81
|
-
// ? key.split(".").reduce((obj, prop) => obj?.[prop], member)
|
|
82
|
-
// : member[key];
|
|
83
|
-
|
|
84
|
-
// if (Array.isArray(value)) {
|
|
85
|
-
// if (!value.includes(memberValue)) return false;
|
|
86
|
-
// } else if (typeof value === "object" && value !== null) {
|
|
87
|
-
// for (const [subKey, subVal] of Object.entries(value)) {
|
|
88
|
-
// if (memberValue?.[subKey] !== subVal) return false;
|
|
89
|
-
// }
|
|
90
|
-
// } else {
|
|
91
|
-
// if (memberValue !== value) return false;
|
|
92
|
-
// }
|
|
93
|
-
// }
|
|
94
|
-
|
|
95
|
-
// return true;
|
|
96
|
-
// });
|
|
97
|
-
// } catch (error) {
|
|
98
|
-
// console.error("Error fetching cached members:", error);
|
|
99
|
-
// return [];
|
|
100
|
-
// }
|
|
101
|
-
// };
|
|
102
|
-
|
|
103
|
-
// // Update the cache for all members
|
|
104
|
-
// const updateCachedMembers = async (filter = {}) => {
|
|
105
|
-
// try {
|
|
106
|
-
// const members = await UserRole.find(filter)
|
|
107
|
-
// .select("userId role userShift roleId")
|
|
108
|
-
// .populate({
|
|
109
|
-
// path: "roleId",
|
|
110
|
-
// select: "id name userId userShift permissionId modulePermissions",
|
|
111
|
-
// populate: [{ path: "permissionId", select: "id name" }],
|
|
112
|
-
// })
|
|
113
|
-
// .populate({
|
|
114
|
-
// path: "userId",
|
|
115
|
-
// match: { isDeleted: false, suspended: false },
|
|
116
|
-
// select: "firstName lastName role email picture userShift",
|
|
117
|
-
// })
|
|
118
|
-
// .lean()
|
|
119
|
-
// .exec();
|
|
120
|
-
|
|
121
|
-
// const validMembers =
|
|
122
|
-
// members?.filter((member) => member?.userId && member?.roleId) || [];
|
|
123
|
-
|
|
124
|
-
// await setRedisData(CACHE_KEY_ALL_MEMBERS, validMembers);
|
|
125
|
-
|
|
126
|
-
// return validMembers;
|
|
127
|
-
// } catch (error) {
|
|
128
|
-
// console.error("Error updating cached members:", error);
|
|
129
|
-
// return [];
|
|
130
|
-
// }
|
|
131
|
-
// };
|
|
132
|
-
|
|
133
|
-
// // Comprehensive cache update method
|
|
134
|
-
// const updateAllRelatedCaches = async (userId, workspaceId) => {
|
|
135
|
-
// try {
|
|
136
|
-
// await updateCachedMembers();
|
|
137
|
-
// } catch (error) {
|
|
138
|
-
// console.error("Error updating related caches:", error);
|
|
139
|
-
// }
|
|
140
|
-
// };
|
|
141
|
-
|
|
142
|
-
// // Find single user role by filter
|
|
143
|
-
// const findSingleUserRoleByFilter = async (
|
|
144
|
-
// filter = {},
|
|
145
|
-
// populateOptions = {}
|
|
146
|
-
// ) => {
|
|
147
|
-
// const defaultPopulateOptions = {
|
|
148
|
-
// rolePopulate: {
|
|
149
|
-
// path: "roleId",
|
|
150
|
-
// select: "id name userId userShift permissionId modulePermissions",
|
|
151
|
-
// populate: [{ path: "permissionId", select: "id name" }],
|
|
152
|
-
// },
|
|
153
|
-
// userPopulate: {
|
|
154
|
-
// path: "userId",
|
|
155
|
-
// match: { isDeleted: false, suspended: false },
|
|
156
|
-
// select: "firstName lastName role email picture userShift",
|
|
157
|
-
// },
|
|
158
|
-
// };
|
|
159
|
-
// const mergedPopulateOptions = {
|
|
160
|
-
// rolePopulate: {
|
|
161
|
-
// ...defaultPopulateOptions.rolePopulate,
|
|
162
|
-
// ...populateOptions.rolePopulate,
|
|
163
|
-
// },
|
|
164
|
-
// userPopulate: {
|
|
165
|
-
// ...defaultPopulateOptions.userPopulate,
|
|
166
|
-
// ...populateOptions.userPopulate,
|
|
167
|
-
// },
|
|
168
|
-
// };
|
|
169
|
-
// return await UserRole.findOne(filter)
|
|
170
|
-
// .populate(mergedPopulateOptions.rolePopulate)
|
|
171
|
-
// .populate(mergedPopulateOptions.userPopulate)
|
|
172
|
-
// .lean()
|
|
173
|
-
// .exec();
|
|
174
|
-
// };
|
|
175
|
-
|
|
176
|
-
// const convertPermissionsArrayToObject = (originalArray) => {
|
|
177
|
-
// return originalArray?.reduce((acc, item) => {
|
|
178
|
-
// const { id, actions, integrationPermissions, ...extras } = item;
|
|
179
|
-
// const formattedExtras = {};
|
|
180
|
-
// if (extras.deletable !== undefined) {
|
|
181
|
-
// formattedExtras.deletable = extras.deletable;
|
|
182
|
-
// }
|
|
183
|
-
// if (extras.createUpdateable !== undefined) {
|
|
184
|
-
// formattedExtras.createUpdateable = extras.createUpdateable;
|
|
185
|
-
// }
|
|
186
|
-
// acc[id] = {
|
|
187
|
-
// actions: Object.keys(actions).filter((action) => actions[action]),
|
|
188
|
-
// ...formattedExtras,
|
|
189
|
-
// ...(integrationPermissions && {
|
|
190
|
-
// integrationPermissions: Object.entries(integrationPermissions)
|
|
191
|
-
// .filter(([_, allowed]) => allowed)
|
|
192
|
-
// .map(([key]) => key),
|
|
193
|
-
// }),
|
|
194
|
-
// };
|
|
195
|
-
// return acc;
|
|
196
|
-
// }, {});
|
|
197
|
-
// };
|
|
198
|
-
|
|
199
|
-
// const createUserRole = async (data) => {
|
|
200
|
-
// const savedRole = await UserRole.create(data);
|
|
201
|
-
|
|
202
|
-
// // Update all related caches
|
|
203
|
-
// await updateAllRelatedCaches(
|
|
204
|
-
// savedRole?.userId?.toString(),
|
|
205
|
-
// savedRole?.workspaceId?.toString()
|
|
206
|
-
// );
|
|
207
|
-
|
|
208
|
-
// return savedRole;
|
|
209
|
-
// };
|
|
210
|
-
|
|
211
|
-
// const findOneAndUpdateUserRole = async ({
|
|
212
|
-
// workspaceId,
|
|
213
|
-
// userId,
|
|
214
|
-
// userShift,
|
|
215
|
-
// role,
|
|
216
|
-
// }) => {
|
|
217
|
-
// const updatedRole = await UserRole.findOneAndUpdate(
|
|
218
|
-
// { workspaceId, userId },
|
|
219
|
-
// { $set: { userShift, role } },
|
|
220
|
-
// { new: true, upsert: false }
|
|
221
|
-
// ).exec();
|
|
222
|
-
// if (updatedRole) {
|
|
223
|
-
// await updateAllRelatedCaches(userId, workspaceId);
|
|
224
|
-
// }
|
|
225
|
-
// return updatedRole;
|
|
226
|
-
// };
|
|
227
|
-
|
|
228
|
-
// const findUserRole = async (filter = {}) => {
|
|
229
|
-
// return await getCachedMembers(filter);
|
|
230
|
-
// };
|
|
231
|
-
|
|
232
|
-
// const updateUserRole = async (id, data) => {
|
|
233
|
-
// const updatedRole = await UserRole.findByIdAndUpdate(id, data, {
|
|
234
|
-
// new: true,
|
|
235
|
-
// }).exec();
|
|
236
|
-
// if (updatedRole) {
|
|
237
|
-
// await updateAllRelatedCaches(updatedRole.userId, updatedRole.workspaceId);
|
|
238
|
-
// }
|
|
239
|
-
// return updatedRole;
|
|
240
|
-
// };
|
|
241
|
-
|
|
242
|
-
// const deleteUserRoleByFilter = async (filter) => {
|
|
243
|
-
// const roleToDelete = await UserRole.findOne(filter).exec();
|
|
244
|
-
// const deletedRole = await UserRole.findOneAndDelete(filter).exec();
|
|
245
|
-
// if (deletedRole) {
|
|
246
|
-
// await updateAllRelatedCaches(
|
|
247
|
-
// roleToDelete?.userId,
|
|
248
|
-
// roleToDelete?.workspaceId
|
|
249
|
-
// );
|
|
250
|
-
// }
|
|
251
|
-
// return deletedRole;
|
|
252
|
-
// };
|
|
253
|
-
|
|
254
|
-
// const deleteUserRole = async (id) => {
|
|
255
|
-
// const role = await UserRole.findById(id).exec();
|
|
256
|
-
// const userId = role?.userId;
|
|
257
|
-
// const workspaceId = role?.workspaceId;
|
|
258
|
-
// const deletedRole = await UserRole.findByIdAndDelete(id).exec();
|
|
259
|
-
// if (deletedRole) {
|
|
260
|
-
// await updateAllRelatedCaches(userId, workspaceId);
|
|
261
|
-
// }
|
|
262
|
-
// return deletedRole;
|
|
263
|
-
// };
|
|
264
|
-
|
|
265
|
-
// const findUserWorkspaces = async (userId) => {
|
|
266
|
-
// let userRoleWithWorkspaces = await UserRole.find({ userId: userId })
|
|
267
|
-
// .select("userId roleId workspaceId")
|
|
268
|
-
// .populate({
|
|
269
|
-
// path: "roleId",
|
|
270
|
-
// select: "id name userId userShift permissionId modulePermissions",
|
|
271
|
-
// populate: [{ path: "permissionId", select: "id name" }],
|
|
272
|
-
// })
|
|
273
|
-
// .populate({
|
|
274
|
-
// path: "workspaceId",
|
|
275
|
-
// select: defaultSelect,
|
|
276
|
-
// match: { isDeleted: false },
|
|
277
|
-
// })
|
|
278
|
-
// .lean()
|
|
279
|
-
// .exec();
|
|
280
|
-
// userRoleWithWorkspaces = userRoleWithWorkspaces
|
|
281
|
-
// ?.filter((userRole) => userRole?.workspaceId)
|
|
282
|
-
// ?.filter((userRole) => userRole?.roleId)
|
|
283
|
-
// ?.map((ur) => {
|
|
284
|
-
// return {
|
|
285
|
-
// ...ur?.workspaceId,
|
|
286
|
-
// id: ur?.workspaceId?._id?.toString(),
|
|
287
|
-
// _id: ur?.workspaceId?._id?.toString(),
|
|
288
|
-
// role: ur?.roleId?.name || "",
|
|
289
|
-
// permissions: ur?.roleId?.modulePermissions?.modules || [],
|
|
290
|
-
// };
|
|
291
|
-
// });
|
|
292
|
-
// return userRoleWithWorkspaces || [];
|
|
293
|
-
// };
|
|
294
|
-
|
|
295
|
-
// const getUserPermissions = async (workspaceId, userId) => {
|
|
296
|
-
// try {
|
|
297
|
-
// let members = await getCachedMembers({ workspaceId, userId });
|
|
298
|
-
// console.log(members, "members");
|
|
299
|
-
// if (members?.length) {
|
|
300
|
-
// return (
|
|
301
|
-
// convertPermissionsArrayToObject(
|
|
302
|
-
// members?.[0]?.roleId?.modulePermissions?.modules
|
|
303
|
-
// ) || null
|
|
304
|
-
// );
|
|
305
|
-
// }
|
|
306
|
-
// return null;
|
|
307
|
-
// } catch (err) {
|
|
308
|
-
// console.error("Error in getUserPermissions:", err);
|
|
309
|
-
// return null;
|
|
310
|
-
// }
|
|
311
|
-
// };
|
|
312
|
-
|
|
313
|
-
// const getUserRoleWithPermissions = async (workspaceId, userId) => {
|
|
314
|
-
// try {
|
|
315
|
-
// let members = await getCachedMembers({ workspaceId, userId });
|
|
316
|
-
// console.log(members, "members");
|
|
317
|
-
// if (members?.length) {
|
|
318
|
-
// let data = members?.[0];
|
|
319
|
-
// const roleWithPermissions = {
|
|
320
|
-
// ...data,
|
|
321
|
-
// roleId: data?.roleId?._id?.toString() || "",
|
|
322
|
-
// role: data?.roleId?.name || "",
|
|
323
|
-
// permissions:
|
|
324
|
-
// convertPermissionsArrayToObject(
|
|
325
|
-
// data?.roleId?.modulePermissions?.modules
|
|
326
|
-
// ) || [],
|
|
327
|
-
// parentRole: data?.roleId?.permissionId?.name || "",
|
|
328
|
-
// parentRoleId: data?.roleId?.permissionId?._id?.toString() || "",
|
|
329
|
-
// defaultModule: data?.roleId?.defaultModule || "",
|
|
330
|
-
// };
|
|
331
|
-
// return roleWithPermissions || null;
|
|
332
|
-
// }
|
|
333
|
-
// return null;
|
|
334
|
-
// } catch (err) {
|
|
335
|
-
// console.error("Error in getUserRoleWithPermissions:", err);
|
|
336
|
-
// return null;
|
|
337
|
-
// }
|
|
338
|
-
// };
|
|
339
|
-
|
|
340
|
-
// const getChannelsPermissions = async (workspaceId, userId) => {
|
|
341
|
-
// try {
|
|
342
|
-
// let members = await getCachedMembers({ workspaceId, userId });
|
|
343
|
-
// console.log(members, "members");
|
|
344
|
-
// if (members?.length) {
|
|
345
|
-
// let data = members?.[0];
|
|
346
|
-
// return (
|
|
347
|
-
// convertPermissionsArrayToObject(
|
|
348
|
-
// data?.roleId?.modulePermissions?.modules
|
|
349
|
-
// )?.["conversations"]?.["integrationPermissions"] || []
|
|
350
|
-
// );
|
|
351
|
-
// }
|
|
352
|
-
// return [];
|
|
353
|
-
// } catch (err) {
|
|
354
|
-
// console.error("Error in getChannelsPermissions:", err);
|
|
355
|
-
// return [];
|
|
356
|
-
// }
|
|
357
|
-
// };
|
|
358
|
-
|
|
359
|
-
// module.exports = {
|
|
360
|
-
// createUserRole,
|
|
361
|
-
// findUserRole,
|
|
362
|
-
// updateUserRole,
|
|
363
|
-
// deleteUserRoleByFilter,
|
|
364
|
-
// deleteUserRole,
|
|
365
|
-
// findUserWorkspaces,
|
|
366
|
-
// getUserRoleWithPermissions,
|
|
367
|
-
// getUserPermissions,
|
|
368
|
-
// getChannelsPermissions,
|
|
369
|
-
// findOneAndUpdateUserRole,
|
|
370
|
-
// findSingleUserRoleByFilter,
|
|
371
|
-
// getCachedMembers,
|
|
372
|
-
// updateCachedMembers,
|
|
373
|
-
// };
|
|
374
|
-
|
|
375
1
|
const { UserRole } = require("../../models/UserRole");
|
|
376
2
|
const { getRedisData, setRedisData } = require("../../config/redis");
|
|
377
3
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
select: {
|
|
381
|
-
userRole: "userId role userShift roleId workspaceId",
|
|
382
|
-
role: "id name userId userShift permissionId modulePermissions",
|
|
383
|
-
permission: "id name",
|
|
384
|
-
user: "firstName lastName role email picture userShift _id",
|
|
385
|
-
},
|
|
386
|
-
match: {
|
|
387
|
-
user: { isDeleted: false, suspended: false },
|
|
388
|
-
},
|
|
389
|
-
};
|
|
4
|
+
const defaultSelect =
|
|
5
|
+
"iconUrl thumbUrl name productsCount ordersCount contact email address websiteUrl facebookUrl twitterUrl instagramUrl members defaultModule";
|
|
390
6
|
|
|
391
|
-
// Cache
|
|
7
|
+
// Cache keys
|
|
392
8
|
const CACHE_KEY_ALL_MEMBERS = "userroles_all_members";
|
|
393
9
|
|
|
394
|
-
|
|
395
|
-
* Construct a flexible query builder for UserRole with advanced filtering and population
|
|
396
|
-
* @param {Object} options - Query configuration options
|
|
397
|
-
* @returns {Promise} Mongoose query result
|
|
398
|
-
*/
|
|
399
|
-
const buildUserRoleQuery = async (options = {}) => {
|
|
400
|
-
const {
|
|
401
|
-
filter = {},
|
|
402
|
-
select = {},
|
|
403
|
-
populate = {},
|
|
404
|
-
cacheKey = CACHE_KEY_ALL_MEMBERS,
|
|
405
|
-
useCache = true,
|
|
406
|
-
lean = true,
|
|
407
|
-
} = options;
|
|
408
|
-
|
|
409
|
-
// Merge default configurations with provided options
|
|
410
|
-
const mergedSelect = {
|
|
411
|
-
userRole: select.userRole || DEFAULT_USER_ROLE_CONFIG.select.userRole,
|
|
412
|
-
role: select.role || DEFAULT_USER_ROLE_CONFIG.select.role,
|
|
413
|
-
permission: select.permission || DEFAULT_USER_ROLE_CONFIG.select.permission,
|
|
414
|
-
user: select.user || DEFAULT_USER_ROLE_CONFIG.select.user,
|
|
415
|
-
};
|
|
416
|
-
|
|
417
|
-
const mergedMatch = {
|
|
418
|
-
user: {
|
|
419
|
-
...DEFAULT_USER_ROLE_CONFIG.match.user,
|
|
420
|
-
...(select.userMatch || {}),
|
|
421
|
-
},
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
// Populate configuration with fallback defaults
|
|
425
|
-
const populateConfig = [
|
|
426
|
-
{
|
|
427
|
-
path: "roleId",
|
|
428
|
-
select: mergedSelect.role,
|
|
429
|
-
populate: {
|
|
430
|
-
path: "permissionId",
|
|
431
|
-
select: mergedSelect.permission,
|
|
432
|
-
},
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
path: "userId",
|
|
436
|
-
match: mergedMatch.user,
|
|
437
|
-
select: mergedSelect.user,
|
|
438
|
-
},
|
|
439
|
-
...(populate.additional || []),
|
|
440
|
-
];
|
|
441
|
-
|
|
10
|
+
const getCachedMembers = async (filter = {}) => {
|
|
442
11
|
try {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
12
|
+
let members = await getRedisData(CACHE_KEY_ALL_MEMBERS);
|
|
13
|
+
|
|
14
|
+
if (!members) {
|
|
15
|
+
members = await UserRole.find()
|
|
16
|
+
.select("userId role userShift roleId workspaceId")
|
|
17
|
+
.populate({
|
|
18
|
+
path: "roleId",
|
|
19
|
+
select: "id name userId userShift permissionId modulePermissions",
|
|
20
|
+
populate: [{ path: "permissionId", select: "id name" }],
|
|
21
|
+
})
|
|
22
|
+
.populate({
|
|
23
|
+
path: "userId",
|
|
24
|
+
match: { isDeleted: false, suspended: false },
|
|
25
|
+
select: "firstName lastName role email picture userShift _id",
|
|
26
|
+
})
|
|
27
|
+
.lean()
|
|
28
|
+
.exec();
|
|
29
|
+
|
|
30
|
+
members = members?.filter((m) => m?.userId && m?.roleId) || [];
|
|
31
|
+
await setRedisData(CACHE_KEY_ALL_MEMBERS, members);
|
|
450
32
|
}
|
|
451
33
|
|
|
452
|
-
|
|
453
|
-
|
|
34
|
+
const userIdFilter = filter.userId
|
|
35
|
+
? new Set(
|
|
36
|
+
Array.isArray(filter.userId)
|
|
37
|
+
? filter.userId.map((id) => id.toString())
|
|
38
|
+
: [filter.userId.toString()]
|
|
39
|
+
)
|
|
40
|
+
: null;
|
|
454
41
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
42
|
+
const roleIdFilter = filter.roleId
|
|
43
|
+
? Array.isArray(filter.roleId)
|
|
44
|
+
? new Set(filter.roleId.map((id) => id.toString()))
|
|
45
|
+
: typeof filter.roleId === "object"
|
|
46
|
+
? filter.roleId
|
|
47
|
+
: new Set([filter.roleId.toString()])
|
|
48
|
+
: null;
|
|
459
49
|
|
|
460
|
-
|
|
461
|
-
|
|
50
|
+
return members.filter((member) => {
|
|
51
|
+
// Optimize userId filter
|
|
52
|
+
if (userIdFilter && !userIdFilter.has(member.userId?._id?.toString())) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
462
55
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
56
|
+
// Optimize roleId filter
|
|
57
|
+
if (roleIdFilter) {
|
|
58
|
+
if (roleIdFilter instanceof Set) {
|
|
59
|
+
const roleIdStr =
|
|
60
|
+
member.roleId?._id?.toString() ?? member.roleId?.id?.toString();
|
|
61
|
+
if (!roleIdFilter.has(roleIdStr)) return false;
|
|
62
|
+
} else if (typeof roleIdFilter === "object") {
|
|
63
|
+
for (const [key, value] of Object.entries(roleIdFilter)) {
|
|
64
|
+
const roleVal = key.includes(".")
|
|
65
|
+
? key.split(".").reduce((obj, k) => obj?.[k], member.roleId)
|
|
66
|
+
: member.roleId?.[key];
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
if (!value.includes(roleVal)) return false;
|
|
69
|
+
} else if (roleVal !== value) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
467
75
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
76
|
+
// General filters
|
|
77
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
78
|
+
if (key === "userId" || key === "roleId") continue;
|
|
79
|
+
|
|
80
|
+
const memberValue = key.includes(".")
|
|
81
|
+
? key.split(".").reduce((obj, prop) => obj?.[prop], member)
|
|
82
|
+
: member[key];
|
|
83
|
+
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
if (!value.includes(memberValue)) return false;
|
|
86
|
+
} else if (typeof value === "object" && value !== null) {
|
|
87
|
+
for (const [subKey, subVal] of Object.entries(value)) {
|
|
88
|
+
if (memberValue?.[subKey] !== subVal) return false;
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
if (memberValue !== value) return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
472
94
|
|
|
473
|
-
|
|
474
|
-
|
|
95
|
+
return true;
|
|
96
|
+
});
|
|
475
97
|
} catch (error) {
|
|
476
|
-
console.error("Error
|
|
98
|
+
console.error("Error fetching cached members:", error);
|
|
477
99
|
return [];
|
|
478
100
|
}
|
|
479
101
|
};
|
|
480
102
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
* @param {Array} data - Data to filter
|
|
484
|
-
* @param {Object} filter - Filter conditions
|
|
485
|
-
* @returns {Array} Filtered results
|
|
486
|
-
*/
|
|
487
|
-
const applyAdvancedFiltering = (data, filter = {}) => {
|
|
488
|
-
if (!data || data.length === 0) return [];
|
|
489
|
-
|
|
490
|
-
return data.filter((item) => {
|
|
491
|
-
for (const [key, value] of Object.entries(filter)) {
|
|
492
|
-
// Skip special filtering keys
|
|
493
|
-
if (key === "userId" || key === "roleId") continue;
|
|
494
|
-
|
|
495
|
-
// Handle nested property access
|
|
496
|
-
const itemValue = key.includes(".")
|
|
497
|
-
? key.split(".").reduce((obj, prop) => obj?.[prop], item)
|
|
498
|
-
: item[key];
|
|
499
|
-
|
|
500
|
-
// Complex filtering logic
|
|
501
|
-
if (Array.isArray(value)) {
|
|
502
|
-
if (!value.includes(itemValue)) return false;
|
|
503
|
-
} else if (typeof value === "object" && value !== null) {
|
|
504
|
-
for (const [subKey, subVal] of Object.entries(value)) {
|
|
505
|
-
if (itemValue?.[subKey] !== subVal) return false;
|
|
506
|
-
}
|
|
507
|
-
} else {
|
|
508
|
-
if (itemValue !== value) return false;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return true;
|
|
512
|
-
});
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Wrapper functions using the new query builder
|
|
517
|
-
*/
|
|
518
|
-
const getCachedMembers = async (filter = {}) => buildUserRoleQuery({ filter });
|
|
519
|
-
|
|
520
|
-
const findUserRole = async (filter = {}) => buildUserRoleQuery({ filter });
|
|
521
|
-
|
|
522
|
-
const updateCachedMembers = async (filter = {}) =>
|
|
523
|
-
buildUserRoleQuery({
|
|
524
|
-
filter,
|
|
525
|
-
cacheKey: CACHE_KEY_ALL_MEMBERS,
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
const findSingleUserRoleByFilter = async (filter = {}, options = {}) => {
|
|
529
|
-
const results = await buildUserRoleQuery({
|
|
530
|
-
filter,
|
|
531
|
-
...options,
|
|
532
|
-
});
|
|
533
|
-
return results[0] || null;
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
const getUserPermissions = async (workspaceId, userId) => {
|
|
103
|
+
// Update the cache for all members
|
|
104
|
+
const updateCachedMembers = async (filter = {}) => {
|
|
537
105
|
try {
|
|
538
|
-
const members = await
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
106
|
+
const members = await UserRole.find(filter)
|
|
107
|
+
.select("userId role userShift roleId")
|
|
108
|
+
.populate({
|
|
109
|
+
path: "roleId",
|
|
110
|
+
select: "id name userId userShift permissionId modulePermissions",
|
|
111
|
+
populate: [{ path: "permissionId", select: "id name" }],
|
|
112
|
+
})
|
|
113
|
+
.populate({
|
|
114
|
+
path: "userId",
|
|
115
|
+
match: { isDeleted: false, suspended: false },
|
|
116
|
+
select: "firstName lastName role email picture userShift",
|
|
117
|
+
})
|
|
118
|
+
.lean()
|
|
119
|
+
.exec();
|
|
120
|
+
|
|
121
|
+
console.log(members, "members");
|
|
122
|
+
|
|
123
|
+
const validMembers =
|
|
124
|
+
members?.filter((member) => member?.userId && member?.roleId) || [];
|
|
125
|
+
|
|
126
|
+
conosle.log(validMembers, "validMembers");
|
|
127
|
+
|
|
128
|
+
await setRedisData(CACHE_KEY_ALL_MEMBERS, validMembers);
|
|
129
|
+
|
|
130
|
+
return validMembers;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error("Error updating cached members:", error);
|
|
133
|
+
return [];
|
|
547
134
|
}
|
|
548
135
|
};
|
|
549
136
|
|
|
550
|
-
|
|
137
|
+
// Comprehensive cache update method
|
|
138
|
+
const updateAllRelatedCaches = async (userId, workspaceId) => {
|
|
551
139
|
try {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
return {
|
|
556
|
-
...data,
|
|
557
|
-
roleId: data?.roleId?._id?.toString() || "",
|
|
558
|
-
role: data?.roleId?.name || "",
|
|
559
|
-
permissions:
|
|
560
|
-
convertPermissionsArrayToObject(
|
|
561
|
-
data?.roleId?.modulePermissions?.modules
|
|
562
|
-
) || [],
|
|
563
|
-
parentRole: data?.roleId?.permissionId?.name || "",
|
|
564
|
-
parentRoleId: data?.roleId?.permissionId?._id?.toString() || "",
|
|
565
|
-
defaultModule: data?.roleId?.defaultModule || "",
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
return null;
|
|
569
|
-
} catch (err) {
|
|
570
|
-
console.error("Error in getUserRoleWithPermissions:", err);
|
|
571
|
-
return null;
|
|
140
|
+
await updateCachedMembers();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error("Error updating related caches:", error);
|
|
572
143
|
}
|
|
573
144
|
};
|
|
574
145
|
|
|
575
|
-
//
|
|
146
|
+
// Find single user role by filter
|
|
147
|
+
const findSingleUserRoleByFilter = async (
|
|
148
|
+
filter = {},
|
|
149
|
+
populateOptions = {}
|
|
150
|
+
) => {
|
|
151
|
+
const defaultPopulateOptions = {
|
|
152
|
+
rolePopulate: {
|
|
153
|
+
path: "roleId",
|
|
154
|
+
select: "id name userId userShift permissionId modulePermissions",
|
|
155
|
+
populate: [{ path: "permissionId", select: "id name" }],
|
|
156
|
+
},
|
|
157
|
+
userPopulate: {
|
|
158
|
+
path: "userId",
|
|
159
|
+
match: { isDeleted: false, suspended: false },
|
|
160
|
+
select: "firstName lastName role email picture userShift",
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
const mergedPopulateOptions = {
|
|
164
|
+
rolePopulate: {
|
|
165
|
+
...defaultPopulateOptions.rolePopulate,
|
|
166
|
+
...populateOptions.rolePopulate,
|
|
167
|
+
},
|
|
168
|
+
userPopulate: {
|
|
169
|
+
...defaultPopulateOptions.userPopulate,
|
|
170
|
+
...populateOptions.userPopulate,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
return await UserRole.findOne(filter)
|
|
174
|
+
.populate(mergedPopulateOptions.rolePopulate)
|
|
175
|
+
.populate(mergedPopulateOptions.userPopulate)
|
|
176
|
+
.lean()
|
|
177
|
+
.exec();
|
|
178
|
+
};
|
|
179
|
+
|
|
576
180
|
const convertPermissionsArrayToObject = (originalArray) => {
|
|
577
181
|
return originalArray?.reduce((acc, item) => {
|
|
578
182
|
const { id, actions, integrationPermissions, ...extras } = item;
|
|
@@ -596,66 +200,159 @@ const convertPermissionsArrayToObject = (originalArray) => {
|
|
|
596
200
|
}, {});
|
|
597
201
|
};
|
|
598
202
|
|
|
599
|
-
// Existing methods (simplified)
|
|
600
203
|
const createUserRole = async (data) => {
|
|
601
204
|
const savedRole = await UserRole.create(data);
|
|
602
|
-
|
|
205
|
+
|
|
206
|
+
// Update all related caches
|
|
207
|
+
await updateAllRelatedCaches(
|
|
208
|
+
savedRole?.userId?.toString(),
|
|
209
|
+
savedRole?.workspaceId?.toString()
|
|
210
|
+
);
|
|
211
|
+
|
|
603
212
|
return savedRole;
|
|
604
213
|
};
|
|
605
214
|
|
|
215
|
+
const findOneAndUpdateUserRole = async ({
|
|
216
|
+
workspaceId,
|
|
217
|
+
userId,
|
|
218
|
+
userShift,
|
|
219
|
+
role,
|
|
220
|
+
}) => {
|
|
221
|
+
const updatedRole = await UserRole.findOneAndUpdate(
|
|
222
|
+
{ workspaceId, userId },
|
|
223
|
+
{ $set: { userShift, role } },
|
|
224
|
+
{ new: true, upsert: false }
|
|
225
|
+
).exec();
|
|
226
|
+
if (updatedRole) {
|
|
227
|
+
await updateAllRelatedCaches(userId, workspaceId);
|
|
228
|
+
}
|
|
229
|
+
return updatedRole;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const findUserRole = async (filter = {}) => {
|
|
233
|
+
return await getCachedMembers(filter);
|
|
234
|
+
};
|
|
235
|
+
|
|
606
236
|
const updateUserRole = async (id, data) => {
|
|
607
237
|
const updatedRole = await UserRole.findByIdAndUpdate(id, data, {
|
|
608
238
|
new: true,
|
|
609
239
|
}).exec();
|
|
610
240
|
if (updatedRole) {
|
|
611
|
-
await
|
|
241
|
+
await updateAllRelatedCaches(updatedRole.userId, updatedRole.workspaceId);
|
|
612
242
|
}
|
|
613
243
|
return updatedRole;
|
|
614
244
|
};
|
|
615
245
|
|
|
246
|
+
const deleteUserRoleByFilter = async (filter) => {
|
|
247
|
+
const deletedRole = await UserRole.findOneAndDelete(filter).exec();
|
|
248
|
+
if (deletedRole) {
|
|
249
|
+
await updateAllRelatedCaches(
|
|
250
|
+
roleToDelete?.userId,
|
|
251
|
+
roleToDelete?.workspaceId
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return deletedRole;
|
|
255
|
+
};
|
|
256
|
+
|
|
616
257
|
const deleteUserRole = async (id) => {
|
|
617
258
|
const role = await UserRole.findById(id).exec();
|
|
259
|
+
const userId = role?.userId;
|
|
260
|
+
const workspaceId = role?.workspaceId;
|
|
618
261
|
const deletedRole = await UserRole.findByIdAndDelete(id).exec();
|
|
619
262
|
if (deletedRole) {
|
|
620
|
-
await
|
|
263
|
+
await updateAllRelatedCaches(userId, workspaceId);
|
|
621
264
|
}
|
|
622
265
|
return deletedRole;
|
|
623
266
|
};
|
|
624
267
|
|
|
625
268
|
const findUserWorkspaces = async (userId) => {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
populate
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
269
|
+
let userRoleWithWorkspaces = await UserRole.find({ userId: userId })
|
|
270
|
+
.select("userId roleId workspaceId")
|
|
271
|
+
.populate({
|
|
272
|
+
path: "roleId",
|
|
273
|
+
select: "id name userId userShift permissionId modulePermissions",
|
|
274
|
+
populate: [{ path: "permissionId", select: "id name" }],
|
|
275
|
+
})
|
|
276
|
+
.populate({
|
|
277
|
+
path: "workspaceId",
|
|
278
|
+
select: defaultSelect,
|
|
279
|
+
match: { isDeleted: false },
|
|
280
|
+
})
|
|
281
|
+
.lean()
|
|
282
|
+
.exec();
|
|
283
|
+
userRoleWithWorkspaces = userRoleWithWorkspaces
|
|
284
|
+
?.filter((userRole) => userRole?.workspaceId)
|
|
285
|
+
?.filter((userRole) => userRole?.roleId)
|
|
286
|
+
?.map((ur) => {
|
|
287
|
+
return {
|
|
288
|
+
...ur?.workspaceId,
|
|
289
|
+
id: ur?.workspaceId?._id?.toString(),
|
|
290
|
+
_id: ur?.workspaceId?._id?.toString(),
|
|
291
|
+
role: ur?.roleId?.name || "",
|
|
292
|
+
permissions: ur?.roleId?.modulePermissions?.modules || [],
|
|
293
|
+
};
|
|
294
|
+
});
|
|
295
|
+
return userRoleWithWorkspaces || [];
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const getUserPermissions = async (workspaceId, userId) => {
|
|
299
|
+
try {
|
|
300
|
+
let members = await getCachedMembers({ workspaceId, userId });
|
|
301
|
+
console.log(members, "members");
|
|
302
|
+
if (members?.length) {
|
|
303
|
+
return (
|
|
304
|
+
convertPermissionsArrayToObject(
|
|
305
|
+
members?.[0]?.roleId?.modulePermissions?.modules
|
|
306
|
+
) || null
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
return null;
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.error("Error in getUserPermissions:", err);
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const getUserRoleWithPermissions = async (workspaceId, userId) => {
|
|
317
|
+
try {
|
|
318
|
+
let members = await getCachedMembers({ workspaceId, userId });
|
|
319
|
+
console.log(members, "members");
|
|
320
|
+
if (members?.length) {
|
|
321
|
+
let data = members?.[0];
|
|
322
|
+
const roleWithPermissions = {
|
|
323
|
+
...data,
|
|
324
|
+
roleId: data?.roleId?._id?.toString() || "",
|
|
325
|
+
role: data?.roleId?.name || "",
|
|
326
|
+
permissions:
|
|
327
|
+
convertPermissionsArrayToObject(
|
|
328
|
+
data?.roleId?.modulePermissions?.modules
|
|
329
|
+
) || [],
|
|
330
|
+
parentRole: data?.roleId?.permissionId?.name || "",
|
|
331
|
+
parentRoleId: data?.roleId?.permissionId?._id?.toString() || "",
|
|
332
|
+
defaultModule: data?.roleId?.defaultModule || "",
|
|
333
|
+
};
|
|
334
|
+
return roleWithPermissions || null;
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
} catch (err) {
|
|
338
|
+
console.error("Error in getUserRoleWithPermissions:", err);
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
649
341
|
};
|
|
650
342
|
|
|
651
343
|
const getChannelsPermissions = async (workspaceId, userId) => {
|
|
652
344
|
try {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
345
|
+
let members = await getCachedMembers({ workspaceId, userId });
|
|
346
|
+
console.log(members, "members");
|
|
347
|
+
if (members?.length) {
|
|
348
|
+
let data = members?.[0];
|
|
349
|
+
return (
|
|
350
|
+
convertPermissionsArrayToObject(
|
|
351
|
+
data?.roleId?.modulePermissions?.modules
|
|
657
352
|
)?.["conversations"]?.["integrationPermissions"] || []
|
|
658
|
-
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
return [];
|
|
659
356
|
} catch (err) {
|
|
660
357
|
console.error("Error in getChannelsPermissions:", err);
|
|
661
358
|
return [];
|
|
@@ -666,13 +363,14 @@ module.exports = {
|
|
|
666
363
|
createUserRole,
|
|
667
364
|
findUserRole,
|
|
668
365
|
updateUserRole,
|
|
366
|
+
deleteUserRoleByFilter,
|
|
669
367
|
deleteUserRole,
|
|
670
368
|
findUserWorkspaces,
|
|
671
369
|
getUserRoleWithPermissions,
|
|
672
370
|
getUserPermissions,
|
|
673
371
|
getChannelsPermissions,
|
|
372
|
+
findOneAndUpdateUserRole,
|
|
674
373
|
findSingleUserRoleByFilter,
|
|
675
374
|
getCachedMembers,
|
|
676
375
|
updateCachedMembers,
|
|
677
|
-
buildUserRoleQuery, // Expose the new flexible query builder
|
|
678
376
|
};
|