dt-common-device 13.0.7 → 13.0.9
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.
|
@@ -9,6 +9,11 @@ export declare class AdminRepository {
|
|
|
9
9
|
getZonesByAccessGroups(accessGroupIds: string[], type?: string[]): Promise<any[]>;
|
|
10
10
|
getAccessGroup(accessGroupId: string, propertyId?: string): Promise<IAccessGroup | null>;
|
|
11
11
|
getZoneAccessGroupByZoneId(zoneId: string): Promise<IZoneAccessGroup[] | null>;
|
|
12
|
+
getAllParentZones(zoneId: string): Promise<string[]>;
|
|
13
|
+
getDirectChildZones(zoneId: string, propertyId?: string): Promise<string[]>;
|
|
14
|
+
getAllChildZones(zoneId: string, propertyId?: string): Promise<string[]>;
|
|
15
|
+
getAccessGroupsByZoneId(zoneId: string): Promise<IAccessGroup[]>;
|
|
16
|
+
getAccessGroupsByZoneIds(zoneIds: string[]): Promise<IAccessGroup[]>;
|
|
12
17
|
getZone(zoneId: string, propertyId?: string): Promise<IZone | null>;
|
|
13
18
|
getUser(userId: string): Promise<IUser | null>;
|
|
14
19
|
getZoneByDeviceId(deviceId: string): Promise<IZone | null>;
|
|
@@ -224,10 +224,11 @@ let AdminRepository = (() => {
|
|
|
224
224
|
// Use default types if not provided
|
|
225
225
|
const zoneTypesToFilter = type || ["Guest Room", "Room"];
|
|
226
226
|
// Fetch zone type IDs for the specified type
|
|
227
|
+
// Using IN with unnest() for better compatibility with string arrays
|
|
227
228
|
const zoneTypesQuery = `
|
|
228
229
|
SELECT id
|
|
229
230
|
FROM "dt_zoneTypes"
|
|
230
|
-
WHERE name
|
|
231
|
+
WHERE name IN (SELECT unnest($1::text[]))
|
|
231
232
|
`;
|
|
232
233
|
const zoneTypes = await this.postgres.query(zoneTypesQuery, [
|
|
233
234
|
zoneTypesToFilter,
|
|
@@ -277,6 +278,116 @@ let AdminRepository = (() => {
|
|
|
277
278
|
}
|
|
278
279
|
return null;
|
|
279
280
|
}
|
|
281
|
+
async getAllParentZones(zoneId) {
|
|
282
|
+
const allParentZoneIds = [];
|
|
283
|
+
let currentZoneId = zoneId;
|
|
284
|
+
while (currentZoneId) {
|
|
285
|
+
const zone = await this.getZone(currentZoneId);
|
|
286
|
+
if (!zone || !zone.parentId) {
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
allParentZoneIds.push(zone.parentId);
|
|
290
|
+
currentZoneId = zone.parentId;
|
|
291
|
+
}
|
|
292
|
+
return allParentZoneIds;
|
|
293
|
+
}
|
|
294
|
+
async getDirectChildZones(zoneId, propertyId) {
|
|
295
|
+
const redisKey = propertyId
|
|
296
|
+
? `${propertyId}:childZones:${zoneId}`
|
|
297
|
+
: `childZones:${zoneId}`;
|
|
298
|
+
// Try to get from cache first
|
|
299
|
+
const zonesCache = await this.redisUtils.get(redisKey);
|
|
300
|
+
let zones = null;
|
|
301
|
+
if (zonesCache !== null && zonesCache !== undefined) {
|
|
302
|
+
(0, config_1.getLogger)().info(`Got child zones from redis for zone ${zoneId}`);
|
|
303
|
+
zones = JSON.parse(zonesCache);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zoneId}`);
|
|
307
|
+
zones = response?.data?.data;
|
|
308
|
+
if (zones) {
|
|
309
|
+
await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Get only direct children (first level), not all descendants
|
|
313
|
+
if (zones && zones.childZones) {
|
|
314
|
+
if (Array.isArray(zones.childZones)) {
|
|
315
|
+
return zones.childZones
|
|
316
|
+
.map((z) => z.id)
|
|
317
|
+
.filter((id) => id);
|
|
318
|
+
}
|
|
319
|
+
else if (zones.childZones.id) {
|
|
320
|
+
return [zones.childZones.id];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
async getAllChildZones(zoneId, propertyId) {
|
|
326
|
+
const redisKey = propertyId
|
|
327
|
+
? `${propertyId}:childZones:${zoneId}`
|
|
328
|
+
: `childZones:${zoneId}`;
|
|
329
|
+
// Try to get from cache first
|
|
330
|
+
const zonesCache = await this.redisUtils.get(redisKey);
|
|
331
|
+
let zones = null;
|
|
332
|
+
if (zonesCache !== null && zonesCache !== undefined) {
|
|
333
|
+
(0, config_1.getLogger)().info(`Got child zones from redis for zone ${zoneId}`);
|
|
334
|
+
zones = JSON.parse(zonesCache);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zoneId}`);
|
|
338
|
+
zones = response?.data?.data;
|
|
339
|
+
if (zones) {
|
|
340
|
+
await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Recursively collect all child zone IDs (using the same pattern as getZonesByAccessGroupIds)
|
|
344
|
+
const _zones = (nestedZones, allZones = []) => {
|
|
345
|
+
nestedZones.forEach((z) => {
|
|
346
|
+
const onlyZone = { ...z };
|
|
347
|
+
delete onlyZone.childZones;
|
|
348
|
+
allZones.push(onlyZone);
|
|
349
|
+
if (!Array.isArray(z.childZones)) {
|
|
350
|
+
if (z.childZones && z.childZones.id)
|
|
351
|
+
z.childZones = [z.childZones];
|
|
352
|
+
}
|
|
353
|
+
if (z.childZones && z.childZones.length) {
|
|
354
|
+
_zones(z.childZones, allZones);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
return allZones.map((e) => e.id);
|
|
358
|
+
};
|
|
359
|
+
if (zones && zones.childZones && zones.childZones.length > 0) {
|
|
360
|
+
const childZoneIds = _zones(zones.childZones, []);
|
|
361
|
+
return childZoneIds;
|
|
362
|
+
}
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
async getAccessGroupsByZoneId(zoneId) {
|
|
366
|
+
const query = `
|
|
367
|
+
SELECT DISTINCT c.*
|
|
368
|
+
FROM dt_collections c
|
|
369
|
+
INNER JOIN dt_zones_collection_map zcm ON c.id = zcm."collectionId"
|
|
370
|
+
WHERE zcm."zoneId" = $1
|
|
371
|
+
AND c."isDeleted" = false
|
|
372
|
+
`;
|
|
373
|
+
const result = await this.postgres.query(query, [zoneId]);
|
|
374
|
+
return result.rows;
|
|
375
|
+
}
|
|
376
|
+
async getAccessGroupsByZoneIds(zoneIds) {
|
|
377
|
+
if (zoneIds.length === 0) {
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
// Get all access groups associated with any of these zones
|
|
381
|
+
const query = `
|
|
382
|
+
SELECT DISTINCT c.*
|
|
383
|
+
FROM dt_collections c
|
|
384
|
+
INNER JOIN dt_zones_collection_map zcm ON c.id = zcm."collectionId"
|
|
385
|
+
WHERE zcm."zoneId" = ANY($1)
|
|
386
|
+
AND c."isDeleted" = false
|
|
387
|
+
`;
|
|
388
|
+
const result = await this.postgres.query(query, [zoneIds]);
|
|
389
|
+
return result.rows;
|
|
390
|
+
}
|
|
280
391
|
async getZone(zoneId, propertyId) {
|
|
281
392
|
try {
|
|
282
393
|
let query;
|
|
@@ -7,6 +7,7 @@ export declare class AdminService {
|
|
|
7
7
|
getZonesByAccessGroups(accessGroupIds: string[], type?: string[]): Promise<any[]>;
|
|
8
8
|
getAccessGroup(accessGroupId: string, propertyId?: string): Promise<IAccessGroup | null>;
|
|
9
9
|
getAccessGroupByZoneId(zoneId: string): Promise<IAccessGroup[] | []>;
|
|
10
|
+
getAccessgroupBySubParentZoneId(zoneId: string): Promise<IAccessGroup[]>;
|
|
10
11
|
getZone(zoneId: string, propertyId?: string): Promise<IZone | null>;
|
|
11
12
|
getUser(userId: string): Promise<IUser | null>;
|
|
12
13
|
getZoneByDeviceId(deviceId: string): Promise<IZone | null>;
|
|
@@ -133,6 +133,84 @@ let AdminService = (() => {
|
|
|
133
133
|
}
|
|
134
134
|
return accessGroups;
|
|
135
135
|
}
|
|
136
|
+
async getAccessgroupBySubParentZoneId(zoneId) {
|
|
137
|
+
if (!zoneId) {
|
|
138
|
+
throw new Error("Zone ID is required");
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
// Get the zone to retrieve propertyId if needed
|
|
142
|
+
const zone = await this.adminRepository.getZone(zoneId);
|
|
143
|
+
if (!zone) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
// Use Map to collect unique access groups (by ID)
|
|
147
|
+
const accessGroupsMap = new Map();
|
|
148
|
+
// Track visited zones to avoid cycles and duplicate checks
|
|
149
|
+
const visitedZoneIds = new Set();
|
|
150
|
+
// OPTIMIZATION: Set to true if you only need to check if ANY access group exists
|
|
151
|
+
// Set to false if you need ALL access groups from entire hierarchy
|
|
152
|
+
const stopOnFirstFound = true;
|
|
153
|
+
// Recursive function to traverse hierarchy and collect access groups
|
|
154
|
+
const traverseZoneHierarchy = async (currentZoneId, propertyId) => {
|
|
155
|
+
// Base case 1: if zone already visited, return (prevents cycles)
|
|
156
|
+
if (visitedZoneIds.has(currentZoneId)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
// Base case 2: early exit if we found access group and only need existence check
|
|
160
|
+
if (stopOnFirstFound && accessGroupsMap.size > 0) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
// Mark as visited
|
|
164
|
+
visitedZoneIds.add(currentZoneId);
|
|
165
|
+
// Check access groups for current zone (query as we traverse)
|
|
166
|
+
const zoneAccessGroups = await this.adminRepository.getAccessGroupsByZoneId(currentZoneId);
|
|
167
|
+
// If we found access groups, add to map
|
|
168
|
+
if (zoneAccessGroups.length > 0) {
|
|
169
|
+
zoneAccessGroups.forEach((ag) => accessGroupsMap.set(ag.id, ag));
|
|
170
|
+
// Early exit optimization: if we only need to know if access group exists
|
|
171
|
+
if (stopOnFirstFound) {
|
|
172
|
+
return true; // Stop traversal - we found what we need
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Get current zone details
|
|
176
|
+
const currentZone = await this.adminRepository.getZone(currentZoneId);
|
|
177
|
+
if (!currentZone) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
// Recursive case 1: Traverse up to parent zone (if exists and not visited)
|
|
181
|
+
if (currentZone.parentId && !visitedZoneIds.has(currentZone.parentId)) {
|
|
182
|
+
const found = await traverseZoneHierarchy(currentZone.parentId, propertyId);
|
|
183
|
+
// Early exit: if we found access group in parent, stop checking children
|
|
184
|
+
if (found && stopOnFirstFound) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Recursive case 2: Traverse down to direct child zones only
|
|
189
|
+
// Only check children if we haven't found an access group yet (optimization)
|
|
190
|
+
if (!stopOnFirstFound || accessGroupsMap.size === 0) {
|
|
191
|
+
const directChildZoneIds = await this.adminRepository.getDirectChildZones(currentZoneId, propertyId);
|
|
192
|
+
// Recursively process each direct child zone
|
|
193
|
+
for (const childZoneId of directChildZoneIds) {
|
|
194
|
+
if (!visitedZoneIds.has(childZoneId)) {
|
|
195
|
+
const found = await traverseZoneHierarchy(childZoneId, propertyId);
|
|
196
|
+
// Early exit: if we found access group in any child, we can stop
|
|
197
|
+
if (found && stopOnFirstFound) {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return accessGroupsMap.size > 0;
|
|
204
|
+
};
|
|
205
|
+
// Start recursive traversal from the given zone
|
|
206
|
+
await traverseZoneHierarchy(zoneId, zone.propertyId);
|
|
207
|
+
return Array.from(accessGroupsMap.values());
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
console.error("Error in getAccessgroupBySubParentZoneId:", error);
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
136
214
|
async getZone(zoneId, propertyId) {
|
|
137
215
|
if (!zoneId) {
|
|
138
216
|
throw new Error("Zone ID is required");
|