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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
: null;
|
|
417
|
+
const mergedMatch = {
|
|
418
|
+
user: {
|
|
419
|
+
...DEFAULT_USER_ROLE_CONFIG.match.user,
|
|
420
|
+
...(select.userMatch || {}),
|
|
421
|
+
},
|
|
422
|
+
};
|
|
42
423
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
442
|
+
try {
|
|
443
|
+
// Check cache first if useCache is true
|
|
444
|
+
if (useCache) {
|
|
445
|
+
let cachedData = await getRedisData(cacheKey);
|
|
56
446
|
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
|
476
|
+
console.error("Error in buildUserRoleQuery:", error);
|
|
100
477
|
return [];
|
|
101
478
|
}
|
|
102
479
|
};
|
|
103
480
|
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
135
|
-
const updateAllRelatedCaches = async (userId, workspaceId) => {
|
|
550
|
+
const getUserRoleWithPermissions = async (workspaceId, userId) => {
|
|
136
551
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
145
|
-
|
|
568
|
+
return null;
|
|
569
|
+
} catch (err) {
|
|
570
|
+
console.error("Error in getUserRoleWithPermissions:", err);
|
|
571
|
+
return null;
|
|
146
572
|
}
|
|
147
573
|
};
|
|
148
574
|
|
|
149
|
-
//
|
|
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
|
|
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
|
|
620
|
+
await updateCachedMembers();
|
|
274
621
|
}
|
|
275
622
|
return deletedRole;
|
|
276
623
|
};
|
|
277
624
|
|
|
278
625
|
const findUserWorkspaces = async (userId) => {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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
|
};
|