shuttlepro-shared 1.2.68 → 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,145 +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
|
-
|
|
5
|
-
|
|
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
|
|
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
|
-
|
|
12
|
-
|
|
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
|
+
|
|
13
442
|
try {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
path: "roleId",
|
|
22
|
-
select: "id name userId userShift permissionId modulePermissions",
|
|
23
|
-
populate: [{ path: "permissionId", select: "id name" }],
|
|
24
|
-
})
|
|
25
|
-
.populate({
|
|
26
|
-
path: "userId",
|
|
27
|
-
match: { isDeleted: false, suspended: false },
|
|
28
|
-
select: "firstName lastName role email picture userShift",
|
|
29
|
-
})
|
|
30
|
-
.lean()
|
|
31
|
-
.exec();
|
|
32
|
-
|
|
33
|
-
// Filter out invalid members
|
|
34
|
-
members =
|
|
35
|
-
members?.filter((member) => member?.userId && member?.roleId) || [];
|
|
36
|
-
|
|
37
|
-
// Cache the result
|
|
38
|
-
await setRedisData(CACHE_KEY_ALL_MEMBERS, members);
|
|
443
|
+
// Check cache first if useCache is true
|
|
444
|
+
if (useCache) {
|
|
445
|
+
let cachedData = await getRedisData(cacheKey);
|
|
446
|
+
|
|
447
|
+
if (cachedData) {
|
|
448
|
+
return applyAdvancedFiltering(cachedData, filter);
|
|
449
|
+
}
|
|
39
450
|
}
|
|
40
451
|
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
452
|
+
// Construct base query
|
|
453
|
+
let query = UserRole.find(filter).select(mergedSelect.userRole);
|
|
454
|
+
|
|
455
|
+
// Apply population
|
|
456
|
+
populateConfig.forEach((config) => {
|
|
457
|
+
query = query.populate(config);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// Execute query
|
|
461
|
+
const results = lean ? await query.lean().exec() : await query.exec();
|
|
48
462
|
|
|
49
|
-
|
|
50
|
-
|
|
463
|
+
// Filter out invalid entries and cache results
|
|
464
|
+
const validResults = results.filter(
|
|
465
|
+
(result) => result?.userId && result?.roleId
|
|
51
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);
|
|
52
475
|
} catch (error) {
|
|
53
|
-
console.error("Error
|
|
476
|
+
console.error("Error in buildUserRoleQuery:", error);
|
|
54
477
|
return [];
|
|
55
478
|
}
|
|
56
479
|
};
|
|
57
480
|
|
|
58
|
-
|
|
59
|
-
|
|
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) => {
|
|
60
537
|
try {
|
|
61
|
-
const members = await
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
match: { isDeleted: false, suspended: false },
|
|
71
|
-
select: "firstName lastName role email picture userShift",
|
|
72
|
-
})
|
|
73
|
-
.lean()
|
|
74
|
-
.exec();
|
|
75
|
-
|
|
76
|
-
const validMembers =
|
|
77
|
-
members?.filter((member) => member?.userId && member?.roleId) || [];
|
|
78
|
-
|
|
79
|
-
await setRedisData(CACHE_KEY_ALL_MEMBERS, validMembers);
|
|
80
|
-
|
|
81
|
-
return validMembers;
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error("Error updating cached members:", error);
|
|
84
|
-
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;
|
|
85
547
|
}
|
|
86
548
|
};
|
|
87
549
|
|
|
88
|
-
|
|
89
|
-
const updateAllRelatedCaches = async (userId, workspaceId) => {
|
|
550
|
+
const getUserRoleWithPermissions = async (workspaceId, userId) => {
|
|
90
551
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
+
};
|
|
97
567
|
}
|
|
98
|
-
|
|
99
|
-
|
|
568
|
+
return null;
|
|
569
|
+
} catch (err) {
|
|
570
|
+
console.error("Error in getUserRoleWithPermissions:", err);
|
|
571
|
+
return null;
|
|
100
572
|
}
|
|
101
573
|
};
|
|
102
574
|
|
|
103
|
-
//
|
|
104
|
-
const clearUserPermissionsCache = async (workspaceId, userId) => {
|
|
105
|
-
const cacheKey = `${CACHE_KEY_USER_PERMISSIONS_PREFIX}${workspaceId}_${userId}`;
|
|
106
|
-
await setRedisData(cacheKey, null, null, 0);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Find single user role by filter
|
|
110
|
-
const findSingleUserRoleByFilter = async (
|
|
111
|
-
filter = {},
|
|
112
|
-
populateOptions = {}
|
|
113
|
-
) => {
|
|
114
|
-
const defaultPopulateOptions = {
|
|
115
|
-
rolePopulate: {
|
|
116
|
-
path: "roleId",
|
|
117
|
-
select: "id name userId userShift permissionId modulePermissions",
|
|
118
|
-
populate: [{ path: "permissionId", select: "id name" }],
|
|
119
|
-
},
|
|
120
|
-
userPopulate: {
|
|
121
|
-
path: "userId",
|
|
122
|
-
match: { isDeleted: false, suspended: false },
|
|
123
|
-
select: "firstName lastName role email picture userShift",
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
const mergedPopulateOptions = {
|
|
127
|
-
rolePopulate: {
|
|
128
|
-
...defaultPopulateOptions.rolePopulate,
|
|
129
|
-
...populateOptions.rolePopulate,
|
|
130
|
-
},
|
|
131
|
-
userPopulate: {
|
|
132
|
-
...defaultPopulateOptions.userPopulate,
|
|
133
|
-
...populateOptions.userPopulate,
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
return await UserRole.findOne(filter)
|
|
137
|
-
.populate(mergedPopulateOptions.rolePopulate)
|
|
138
|
-
.populate(mergedPopulateOptions.userPopulate)
|
|
139
|
-
.lean()
|
|
140
|
-
.exec();
|
|
141
|
-
};
|
|
142
|
-
|
|
575
|
+
// Existing utility function
|
|
143
576
|
const convertPermissionsArrayToObject = (originalArray) => {
|
|
144
577
|
return originalArray?.reduce((acc, item) => {
|
|
145
578
|
const { id, actions, integrationPermissions, ...extras } = item;
|
|
@@ -163,179 +596,66 @@ const convertPermissionsArrayToObject = (originalArray) => {
|
|
|
163
596
|
}, {});
|
|
164
597
|
};
|
|
165
598
|
|
|
599
|
+
// Existing methods (simplified)
|
|
166
600
|
const createUserRole = async (data) => {
|
|
167
601
|
const savedRole = await UserRole.create(data);
|
|
168
|
-
|
|
169
|
-
// Update all related caches
|
|
170
|
-
await updateAllRelatedCaches(
|
|
171
|
-
savedRole?.userId?.toString(),
|
|
172
|
-
savedRole?.workspaceId?.toString()
|
|
173
|
-
);
|
|
174
|
-
|
|
602
|
+
await updateCachedMembers();
|
|
175
603
|
return savedRole;
|
|
176
604
|
};
|
|
177
605
|
|
|
178
|
-
const findOneAndUpdateUserRole = async ({
|
|
179
|
-
workspaceId,
|
|
180
|
-
userId,
|
|
181
|
-
userShift,
|
|
182
|
-
role,
|
|
183
|
-
}) => {
|
|
184
|
-
const updatedRole = await UserRole.findOneAndUpdate(
|
|
185
|
-
{ workspaceId, userId },
|
|
186
|
-
{ $set: { userShift, role } },
|
|
187
|
-
{ new: true, upsert: false }
|
|
188
|
-
).exec();
|
|
189
|
-
if (updatedRole) {
|
|
190
|
-
await updateAllRelatedCaches(userId, workspaceId);
|
|
191
|
-
}
|
|
192
|
-
return updatedRole;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const findUserRole = async (filter = {}) => {
|
|
196
|
-
return await getCachedMembers(filter);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
606
|
const updateUserRole = async (id, data) => {
|
|
200
607
|
const updatedRole = await UserRole.findByIdAndUpdate(id, data, {
|
|
201
608
|
new: true,
|
|
202
609
|
}).exec();
|
|
203
610
|
if (updatedRole) {
|
|
204
|
-
await
|
|
611
|
+
await updateCachedMembers();
|
|
205
612
|
}
|
|
206
613
|
return updatedRole;
|
|
207
614
|
};
|
|
208
615
|
|
|
209
|
-
const deleteUserRoleByFilter = async (filter) => {
|
|
210
|
-
const roleToDelete = await UserRole.findOne(filter).exec();
|
|
211
|
-
const deletedRole = await UserRole.findOneAndDelete(filter).exec();
|
|
212
|
-
if (deletedRole) {
|
|
213
|
-
await updateAllRelatedCaches(
|
|
214
|
-
roleToDelete?.userId,
|
|
215
|
-
roleToDelete?.workspaceId
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
return deletedRole;
|
|
219
|
-
};
|
|
220
|
-
|
|
221
616
|
const deleteUserRole = async (id) => {
|
|
222
617
|
const role = await UserRole.findById(id).exec();
|
|
223
|
-
const userId = role?.userId;
|
|
224
|
-
const workspaceId = role?.workspaceId;
|
|
225
618
|
const deletedRole = await UserRole.findByIdAndDelete(id).exec();
|
|
226
619
|
if (deletedRole) {
|
|
227
|
-
await
|
|
620
|
+
await updateCachedMembers();
|
|
228
621
|
}
|
|
229
622
|
return deletedRole;
|
|
230
623
|
};
|
|
231
624
|
|
|
232
625
|
const findUserWorkspaces = async (userId) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
permissions: ur?.roleId?.modulePermissions?.modules || [],
|
|
257
|
-
};
|
|
258
|
-
});
|
|
259
|
-
return userRoleWithWorkspaces || [];
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const getUserPermissions = async (workspaceId, userId) => {
|
|
263
|
-
try {
|
|
264
|
-
let members = await getCachedMembers({ workspaceId, userId });
|
|
265
|
-
console.log(members, "members");
|
|
266
|
-
if (members?.length) {
|
|
267
|
-
return (
|
|
268
|
-
convertPermissionsArrayToObject(
|
|
269
|
-
members?.[0]?.roleId?.modulePermissions?.modules
|
|
270
|
-
) || null
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
} catch (err) {
|
|
275
|
-
console.error("Error in getUserPermissions:", err);
|
|
276
|
-
return null;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const getUserRoleWithPermissions = async (workspaceId, userId) => {
|
|
281
|
-
try {
|
|
282
|
-
let members = await getCachedMembers({ workspaceId, userId });
|
|
283
|
-
console.log(members, "members");
|
|
284
|
-
if (members?.length) {
|
|
285
|
-
let data = members?.[0];
|
|
286
|
-
const roleWithPermissions = {
|
|
287
|
-
...data,
|
|
288
|
-
roleId: data?.roleId?._id?.toString() || "",
|
|
289
|
-
role: data?.roleId?.name || "",
|
|
290
|
-
permissions:
|
|
291
|
-
convertPermissionsArrayToObject(
|
|
292
|
-
data?.roleId?.modulePermissions?.modules
|
|
293
|
-
) || [],
|
|
294
|
-
parentRole: data?.roleId?.permissionId?.name || "",
|
|
295
|
-
parentRoleId: data?.roleId?.permissionId?._id?.toString() || "",
|
|
296
|
-
defaultModule: data?.roleId?.defaultModule || "",
|
|
297
|
-
};
|
|
298
|
-
return roleWithPermissions || null;
|
|
299
|
-
}
|
|
300
|
-
return null;
|
|
301
|
-
} catch (err) {
|
|
302
|
-
console.error("Error in getUserRoleWithPermissions:", err);
|
|
303
|
-
return null;
|
|
304
|
-
}
|
|
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
|
+
}));
|
|
305
649
|
};
|
|
306
650
|
|
|
307
651
|
const getChannelsPermissions = async (workspaceId, userId) => {
|
|
308
|
-
const cacheKey = `${CACHE_KEY_USER_PERMISSIONS_PREFIX}${workspaceId}_${userId}`;
|
|
309
|
-
let cachedData = await getRedisData(cacheKey);
|
|
310
|
-
if (cachedData && cachedData.channelsPermissions) {
|
|
311
|
-
return cachedData.channelsPermissions;
|
|
312
|
-
}
|
|
313
652
|
try {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
path: "roleId",
|
|
321
|
-
select: "modulePermissions",
|
|
322
|
-
})
|
|
323
|
-
.lean()
|
|
324
|
-
.exec();
|
|
325
|
-
if (!data) {
|
|
326
|
-
return [];
|
|
327
|
-
}
|
|
328
|
-
const channelsPermissions =
|
|
329
|
-
convertPermissionsArrayToObject(
|
|
330
|
-
data?.roleId?.modulePermissions?.modules
|
|
331
|
-
)?.["conversations"]?.["integrationPermissions"] || [];
|
|
332
|
-
|
|
333
|
-
// Store in cache with other permission data
|
|
334
|
-
const permissionsData = cachedData || {};
|
|
335
|
-
permissionsData.channelsPermissions = channelsPermissions;
|
|
336
|
-
await setRedisData(cacheKey, permissionsData);
|
|
337
|
-
|
|
338
|
-
return channelsPermissions;
|
|
653
|
+
const members = await getCachedMembers({ workspaceId, userId });
|
|
654
|
+
return members?.[0]?.roleId?.modulePermissions?.modules
|
|
655
|
+
? convertPermissionsArrayToObject(
|
|
656
|
+
members[0].roleId.modulePermissions.modules
|
|
657
|
+
)?.["conversations"]?.["integrationPermissions"] || []
|
|
658
|
+
: [];
|
|
339
659
|
} catch (err) {
|
|
340
660
|
console.error("Error in getChannelsPermissions:", err);
|
|
341
661
|
return [];
|
|
@@ -346,14 +666,13 @@ module.exports = {
|
|
|
346
666
|
createUserRole,
|
|
347
667
|
findUserRole,
|
|
348
668
|
updateUserRole,
|
|
349
|
-
deleteUserRoleByFilter,
|
|
350
669
|
deleteUserRole,
|
|
351
670
|
findUserWorkspaces,
|
|
352
671
|
getUserRoleWithPermissions,
|
|
353
672
|
getUserPermissions,
|
|
354
673
|
getChannelsPermissions,
|
|
355
|
-
findOneAndUpdateUserRole,
|
|
356
674
|
findSingleUserRoleByFilter,
|
|
357
675
|
getCachedMembers,
|
|
358
676
|
updateCachedMembers,
|
|
677
|
+
buildUserRoleQuery, // Expose the new flexible query builder
|
|
359
678
|
};
|