shuttlepro-shared 1.2.69 → 1.2.70

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,191 +1,578 @@
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
+
1
375
  const { UserRole } = require("../../models/UserRole");
2
376
  const { getRedisData, setRedisData } = require("../../config/redis");
3
377
 
4
- const defaultSelect =
5
- "iconUrl thumbUrl name productsCount ordersCount contact email address websiteUrl facebookUrl twitterUrl instagramUrl members defaultModule";
378
+ // Default selection and population configurations
379
+ const DEFAULT_USER_ROLE_CONFIG = {
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
+ };
6
390
 
7
- // Cache keys
391
+ // Cache key constant
8
392
  const CACHE_KEY_ALL_MEMBERS = "userroles_all_members";
9
- const CACHE_KEY_USER_PERMISSIONS_PREFIX = "user_permissions_";
10
393
 
11
- const getCachedMembers = async (filter = {}) => {
12
- try {
13
- let members = await getRedisData(CACHE_KEY_ALL_MEMBERS);
14
-
15
- if (!members) {
16
- members = await UserRole.find()
17
- .select("userId role userShift roleId workspaceId")
18
- .populate({
19
- path: "roleId",
20
- select: "id name userId userShift permissionId modulePermissions",
21
- populate: [{ path: "permissionId", select: "id name" }],
22
- })
23
- .populate({
24
- path: "userId",
25
- match: { isDeleted: false, suspended: false },
26
- select: "firstName lastName role email picture userShift _id",
27
- })
28
- .lean()
29
- .exec();
30
-
31
- members = members?.filter((m) => m?.userId && m?.roleId) || [];
32
- await setRedisData(CACHE_KEY_ALL_MEMBERS, members);
33
- }
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
+ };
34
416
 
35
- const userIdFilter = filter.userId
36
- ? new Set(
37
- Array.isArray(filter.userId)
38
- ? filter.userId.map((id) => id.toString())
39
- : [filter.userId.toString()]
40
- )
41
- : null;
417
+ const mergedMatch = {
418
+ user: {
419
+ ...DEFAULT_USER_ROLE_CONFIG.match.user,
420
+ ...(select.userMatch || {}),
421
+ },
422
+ };
42
423
 
43
- const roleIdFilter = filter.roleId
44
- ? Array.isArray(filter.roleId)
45
- ? new Set(filter.roleId.map((id) => id.toString()))
46
- : typeof filter.roleId === "object"
47
- ? filter.roleId
48
- : new Set([filter.roleId.toString()])
49
- : null;
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
+ ];
50
441
 
51
- return members.filter((member) => {
52
- // Optimize userId filter
53
- if (userIdFilter && !userIdFilter.has(member.userId?._id?.toString())) {
54
- return false;
55
- }
442
+ try {
443
+ // Check cache first if useCache is true
444
+ if (useCache) {
445
+ let cachedData = await getRedisData(cacheKey);
56
446
 
57
- // Optimize roleId filter
58
- if (roleIdFilter) {
59
- if (roleIdFilter instanceof Set) {
60
- const roleIdStr =
61
- member.roleId?._id?.toString() ?? member.roleId?.id?.toString();
62
- if (!roleIdFilter.has(roleIdStr)) return false;
63
- } else if (typeof roleIdFilter === "object") {
64
- for (const [key, value] of Object.entries(roleIdFilter)) {
65
- const roleVal = key.includes(".")
66
- ? key.split(".").reduce((obj, k) => obj?.[k], member.roleId)
67
- : member.roleId?.[key];
68
- if (Array.isArray(value)) {
69
- if (!value.includes(roleVal)) return false;
70
- } else if (roleVal !== value) {
71
- return false;
72
- }
73
- }
74
- }
447
+ if (cachedData) {
448
+ return applyAdvancedFiltering(cachedData, filter);
75
449
  }
450
+ }
76
451
 
77
- // General filters
78
- for (const [key, value] of Object.entries(filter)) {
79
- if (key === "userId" || key === "roleId") continue;
80
-
81
- const memberValue = key.includes(".")
82
- ? key.split(".").reduce((obj, prop) => obj?.[prop], member)
83
- : member[key];
84
-
85
- if (Array.isArray(value)) {
86
- if (!value.includes(memberValue)) return false;
87
- } else if (typeof value === "object" && value !== null) {
88
- for (const [subKey, subVal] of Object.entries(value)) {
89
- if (memberValue?.[subKey] !== subVal) return false;
90
- }
91
- } else {
92
- if (memberValue !== value) return false;
93
- }
94
- }
452
+ // Construct base query
453
+ let query = UserRole.find(filter).select(mergedSelect.userRole);
95
454
 
96
- return true;
455
+ // Apply population
456
+ populateConfig.forEach((config) => {
457
+ query = query.populate(config);
97
458
  });
459
+
460
+ // Execute query
461
+ const results = lean ? await query.lean().exec() : await query.exec();
462
+
463
+ // Filter out invalid entries and cache results
464
+ const validResults = results.filter(
465
+ (result) => result?.userId && result?.roleId
466
+ );
467
+
468
+ // Cache results if useCache is true
469
+ if (useCache) {
470
+ await setRedisData(cacheKey, validResults);
471
+ }
472
+
473
+ // Apply advanced filtering
474
+ return applyAdvancedFiltering(validResults, filter);
98
475
  } catch (error) {
99
- console.error("Error fetching cached members:", error);
476
+ console.error("Error in buildUserRoleQuery:", error);
100
477
  return [];
101
478
  }
102
479
  };
103
480
 
104
- // Update the cache for all members
105
- const updateCachedMembers = async (filter = {}) => {
481
+ /**
482
+ * Apply advanced filtering with nested property support
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) => {
106
537
  try {
107
- const members = await UserRole.find(filter)
108
- .select("userId role userShift roleId")
109
- .populate({
110
- path: "roleId",
111
- select: "id name userId userShift permissionId modulePermissions",
112
- populate: [{ path: "permissionId", select: "id name" }],
113
- })
114
- .populate({
115
- path: "userId",
116
- match: { isDeleted: false, suspended: false },
117
- select: "firstName lastName role email picture userShift",
118
- })
119
- .lean()
120
- .exec();
121
-
122
- const validMembers =
123
- members?.filter((member) => member?.userId && member?.roleId) || [];
124
-
125
- await setRedisData(CACHE_KEY_ALL_MEMBERS, validMembers);
126
-
127
- return validMembers;
128
- } catch (error) {
129
- console.error("Error updating cached members:", error);
130
- return [];
538
+ const members = await getCachedMembers({ workspaceId, userId });
539
+ return members?.[0]?.roleId?.modulePermissions?.modules
540
+ ? convertPermissionsArrayToObject(
541
+ members[0].roleId.modulePermissions.modules
542
+ )
543
+ : null;
544
+ } catch (err) {
545
+ console.error("Error in getUserPermissions:", err);
546
+ return null;
131
547
  }
132
548
  };
133
549
 
134
- // Comprehensive cache update method
135
- const updateAllRelatedCaches = async (userId, workspaceId) => {
550
+ const getUserRoleWithPermissions = async (workspaceId, userId) => {
136
551
  try {
137
- // Update all members cache
138
- await updateCachedMembers();
139
-
140
- // Clear user permissions cache
141
- if (workspaceId && userId) {
142
- await clearUserPermissionsCache(workspaceId, userId);
552
+ const members = await getCachedMembers({ workspaceId, userId });
553
+ if (members?.length) {
554
+ const data = members[0];
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
+ };
143
567
  }
144
- } catch (error) {
145
- console.error("Error updating related caches:", error);
568
+ return null;
569
+ } catch (err) {
570
+ console.error("Error in getUserRoleWithPermissions:", err);
571
+ return null;
146
572
  }
147
573
  };
148
574
 
149
- // Clear user permissions cache
150
- const clearUserPermissionsCache = async (workspaceId, userId) => {
151
- const cacheKey = `${CACHE_KEY_USER_PERMISSIONS_PREFIX}${workspaceId}_${userId}`;
152
- await setRedisData(cacheKey, null, null, 0);
153
- };
154
-
155
- // Find single user role by filter
156
- const findSingleUserRoleByFilter = async (
157
- filter = {},
158
- populateOptions = {}
159
- ) => {
160
- const defaultPopulateOptions = {
161
- rolePopulate: {
162
- path: "roleId",
163
- select: "id name userId userShift permissionId modulePermissions",
164
- populate: [{ path: "permissionId", select: "id name" }],
165
- },
166
- userPopulate: {
167
- path: "userId",
168
- match: { isDeleted: false, suspended: false },
169
- select: "firstName lastName role email picture userShift",
170
- },
171
- };
172
- const mergedPopulateOptions = {
173
- rolePopulate: {
174
- ...defaultPopulateOptions.rolePopulate,
175
- ...populateOptions.rolePopulate,
176
- },
177
- userPopulate: {
178
- ...defaultPopulateOptions.userPopulate,
179
- ...populateOptions.userPopulate,
180
- },
181
- };
182
- return await UserRole.findOne(filter)
183
- .populate(mergedPopulateOptions.rolePopulate)
184
- .populate(mergedPopulateOptions.userPopulate)
185
- .lean()
186
- .exec();
187
- };
188
-
575
+ // Existing utility function
189
576
  const convertPermissionsArrayToObject = (originalArray) => {
190
577
  return originalArray?.reduce((acc, item) => {
191
578
  const { id, actions, integrationPermissions, ...extras } = item;
@@ -209,160 +596,66 @@ const convertPermissionsArrayToObject = (originalArray) => {
209
596
  }, {});
210
597
  };
211
598
 
599
+ // Existing methods (simplified)
212
600
  const createUserRole = async (data) => {
213
601
  const savedRole = await UserRole.create(data);
214
-
215
- // Update all related caches
216
- await updateAllRelatedCaches(
217
- savedRole?.userId?.toString(),
218
- savedRole?.workspaceId?.toString()
219
- );
220
-
602
+ await updateCachedMembers();
221
603
  return savedRole;
222
604
  };
223
605
 
224
- const findOneAndUpdateUserRole = async ({
225
- workspaceId,
226
- userId,
227
- userShift,
228
- role,
229
- }) => {
230
- const updatedRole = await UserRole.findOneAndUpdate(
231
- { workspaceId, userId },
232
- { $set: { userShift, role } },
233
- { new: true, upsert: false }
234
- ).exec();
235
- if (updatedRole) {
236
- await updateAllRelatedCaches(userId, workspaceId);
237
- }
238
- return updatedRole;
239
- };
240
-
241
- const findUserRole = async (filter = {}) => {
242
- return await getCachedMembers(filter);
243
- };
244
-
245
606
  const updateUserRole = async (id, data) => {
246
607
  const updatedRole = await UserRole.findByIdAndUpdate(id, data, {
247
608
  new: true,
248
609
  }).exec();
249
610
  if (updatedRole) {
250
- await updateAllRelatedCaches(updatedRole.userId, updatedRole.workspaceId);
611
+ await updateCachedMembers();
251
612
  }
252
613
  return updatedRole;
253
614
  };
254
615
 
255
- const deleteUserRoleByFilter = async (filter) => {
256
- const roleToDelete = await UserRole.findOne(filter).exec();
257
- const deletedRole = await UserRole.findOneAndDelete(filter).exec();
258
- if (deletedRole) {
259
- await updateAllRelatedCaches(
260
- roleToDelete?.userId,
261
- roleToDelete?.workspaceId
262
- );
263
- }
264
- return deletedRole;
265
- };
266
-
267
616
  const deleteUserRole = async (id) => {
268
617
  const role = await UserRole.findById(id).exec();
269
- const userId = role?.userId;
270
- const workspaceId = role?.workspaceId;
271
618
  const deletedRole = await UserRole.findByIdAndDelete(id).exec();
272
619
  if (deletedRole) {
273
- await updateAllRelatedCaches(userId, workspaceId);
620
+ await updateCachedMembers();
274
621
  }
275
622
  return deletedRole;
276
623
  };
277
624
 
278
625
  const findUserWorkspaces = async (userId) => {
279
- let userRoleWithWorkspaces = await UserRole.find({ userId: userId })
280
- .select("userId roleId workspaceId")
281
- .populate({
282
- path: "roleId",
283
- select: "id name userId userShift permissionId modulePermissions",
284
- populate: [{ path: "permissionId", select: "id name" }],
285
- })
286
- .populate({
287
- path: "workspaceId",
288
- select: defaultSelect,
289
- match: { isDeleted: false },
290
- })
291
- .lean()
292
- .exec();
293
- userRoleWithWorkspaces = userRoleWithWorkspaces
294
- ?.filter((userRole) => userRole?.workspaceId)
295
- ?.filter((userRole) => userRole?.roleId)
296
- ?.map((ur) => {
297
- return {
298
- ...ur?.workspaceId,
299
- id: ur?.workspaceId?._id?.toString(),
300
- _id: ur?.workspaceId?._id?.toString(),
301
- role: ur?.roleId?.name || "",
302
- permissions: ur?.roleId?.modulePermissions?.modules || [],
303
- };
304
- });
305
- return userRoleWithWorkspaces || [];
306
- };
307
-
308
- const getUserPermissions = async (workspaceId, userId) => {
309
- try {
310
- let members = await getCachedMembers({ workspaceId, userId });
311
- console.log(members, "members");
312
- if (members?.length) {
313
- return (
314
- convertPermissionsArrayToObject(
315
- members?.[0]?.roleId?.modulePermissions?.modules
316
- ) || null
317
- );
318
- }
319
- return null;
320
- } catch (err) {
321
- console.error("Error in getUserPermissions:", err);
322
- return null;
323
- }
324
- };
325
-
326
- const getUserRoleWithPermissions = async (workspaceId, userId) => {
327
- try {
328
- let members = await getCachedMembers({ workspaceId, userId });
329
- console.log(members, "members");
330
- if (members?.length) {
331
- let data = members?.[0];
332
- const roleWithPermissions = {
333
- ...data,
334
- roleId: data?.roleId?._id?.toString() || "",
335
- role: data?.roleId?.name || "",
336
- permissions:
337
- convertPermissionsArrayToObject(
338
- data?.roleId?.modulePermissions?.modules
339
- ) || [],
340
- parentRole: data?.roleId?.permissionId?.name || "",
341
- parentRoleId: data?.roleId?.permissionId?._id?.toString() || "",
342
- defaultModule: data?.roleId?.defaultModule || "",
343
- };
344
- return roleWithPermissions || null;
345
- }
346
- return null;
347
- } catch (err) {
348
- console.error("Error in getUserRoleWithPermissions:", err);
349
- return null;
350
- }
626
+ const userRoles = await buildUserRoleQuery({
627
+ filter: { userId },
628
+ populate: {
629
+ additional: [
630
+ {
631
+ path: "workspaceId",
632
+ select:
633
+ "iconUrl thumbUrl name productsCount ordersCount contact email address websiteUrl facebookUrl twitterUrl instagramUrl members defaultModule",
634
+ match: { isDeleted: false },
635
+ },
636
+ ],
637
+ },
638
+ });
639
+
640
+ return userRoles
641
+ .filter((userRole) => userRole.workspaceId)
642
+ .map((ur) => ({
643
+ ...ur.workspaceId,
644
+ id: ur.workspaceId?._id?.toString(),
645
+ _id: ur.workspaceId?._id?.toString(),
646
+ role: ur.roleId?.name || "",
647
+ permissions: ur.roleId?.modulePermissions?.modules || [],
648
+ }));
351
649
  };
352
650
 
353
651
  const getChannelsPermissions = async (workspaceId, userId) => {
354
652
  try {
355
- let members = await getCachedMembers({ workspaceId, userId });
356
- console.log(members, "members");
357
- if (members?.length) {
358
- let data = members?.[0];
359
- return (
360
- convertPermissionsArrayToObject(
361
- data?.roleId?.modulePermissions?.modules
653
+ const members = await getCachedMembers({ workspaceId, userId });
654
+ return members?.[0]?.roleId?.modulePermissions?.modules
655
+ ? convertPermissionsArrayToObject(
656
+ members[0].roleId.modulePermissions.modules
362
657
  )?.["conversations"]?.["integrationPermissions"] || []
363
- );
364
- }
365
- return [];
658
+ : [];
366
659
  } catch (err) {
367
660
  console.error("Error in getChannelsPermissions:", err);
368
661
  return [];
@@ -373,14 +666,13 @@ module.exports = {
373
666
  createUserRole,
374
667
  findUserRole,
375
668
  updateUserRole,
376
- deleteUserRoleByFilter,
377
669
  deleteUserRole,
378
670
  findUserWorkspaces,
379
671
  getUserRoleWithPermissions,
380
672
  getUserPermissions,
381
673
  getChannelsPermissions,
382
- findOneAndUpdateUserRole,
383
674
  findSingleUserRoleByFilter,
384
675
  getCachedMembers,
385
676
  updateCachedMembers,
677
+ buildUserRoleQuery, // Expose the new flexible query builder
386
678
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shuttlepro-shared",
3
- "version": "1.2.69",
3
+ "version": "1.2.70",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {