dt-common-device
Version:
A secure and robust device management library for IoT applications
509 lines (508 loc) • 22.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminRepository = void 0;
const typedi_1 = __importStar(require("typedi"));
const utils_1 = require("../../utils");
const Device_repository_1 = require("../device/local/repository/Device.repository");
const db_1 = require("../../db/db");
const interfaces_1 = require("../device/cloud/interfaces");
const services_1 = require("../device/local/services");
const config_1 = require("../../config/config");
let AdminRepository = (() => {
let _classDecorators = [(0, typedi_1.Service)()];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var AdminRepository = _classThis = class {
constructor() {
this.deviceRepository = typedi_1.default.get(Device_repository_1.DeviceRepository);
this.postgres = (0, db_1.getPostgresClient)();
this.localDeviceService = typedi_1.default.get(services_1.LocalDeviceService);
this.redisUtils = typedi_1.default.get(utils_1.RedisUtils);
}
async getZonesByAccessGroupIds(accessGroupIds, propertyId) {
// If not cached, get the result from the database
const result = await this.postgres.query(`SELECT
"zc"."id" AS "zoneCollectionMapId",
"zc"."collectionId",
"zc"."zoneId",
"z"."id" AS "zoneId",
"z"."name" AS "zoneName",
"z"."zoneTypeId",
"zt"."name" AS "zoneTypeName"
FROM "dt_zones_collection_map" AS "zc"
INNER JOIN "dt_zones" AS "z" ON "zc"."zoneId" = "z"."id"
LEFT JOIN "dt_zoneTypes" AS "zt" ON "z"."zoneTypeId" = "zt"."id"
WHERE "zc"."collectionId" = ANY($1)
ORDER BY "zc"."id" ASC`, [accessGroupIds]);
const response = result.rows;
const _zones = (nestedZones, allZones = []) => {
nestedZones.forEach((z) => {
const onlyZone = { ...z };
delete onlyZone.childZones;
allZones.push(onlyZone);
if (!Array.isArray(z.childZones)) {
if (z.childZones.id)
z.childZones = [z.childZones];
}
if (z.childZones.length) {
_zones(z.childZones, allZones);
}
});
return allZones.map((e) => e.id);
};
const collectionZone = [];
for (let zone of response) {
let zoneIds = [];
let zones = null;
const redisKey = `${propertyId}:childZones:${zone.zoneId}`;
const zonesCache = await this.redisUtils.get(redisKey);
if (zonesCache !== null && zonesCache !== undefined) {
(0, config_1.getLogger)().info(`Got child zones from redis`);
zones = JSON.parse(zonesCache);
}
else {
const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zone.zoneId}`);
zones = response?.data?.data;
await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
}
zoneIds.push(zone.zoneId);
if (zones.childZones?.length > 0) {
const nestedZoneIds = new Set(_zones(zones.childZones));
zoneIds = [...zoneIds, ...nestedZoneIds];
}
if (collectionZone.length == 0) {
const obj = {
collectionId: zone.collectionId,
zoneIds,
};
collectionZone.push(obj);
}
else {
const obj = collectionZone.find((e) => e.collectionId == zone.collectionId);
if (obj) {
obj.zoneIds = [...obj.zoneIds, ...zoneIds];
}
else {
collectionZone.push({
collectionId: zone.collectionId,
zoneIds,
});
}
}
}
let _zoneIds = collectionZone.flatMap((e) => {
return e.zoneIds.map((z) => z);
});
if (_zoneIds.length === 0)
return [];
const deviceDetails = await this.deviceRepository.queryDevices({
zoneIds: _zoneIds,
excludeDeviceType: interfaces_1.DeviceType.HUB,
});
const _collectionZone = collectionZone.map((e) => {
const zones = e.zoneIds;
let devices = [];
let zonesData = [];
zones.forEach((element) => {
const device = deviceDetails.filter((d) => d.zoneId == element);
// Add collectionId to each device
device.forEach((dev) => {
dev.collectionId = e.collectionId;
});
const _devices = devices.concat(device);
devices = _devices;
// Create zone data for each zone
const zoneInfo = response.find((r) => r.zoneId === element);
const zoneData = {
zoneId: element,
deviceIds: device?.map((d) => d.deviceId), // Get first device ID if available
zoneName: zoneInfo?.zoneName || "",
zoneType: zoneInfo?.zoneTypeName || null,
};
zonesData.push(zoneData);
});
e.devices = devices;
e.zones = zonesData;
e.parentZone = response;
return e;
});
const collectionZoneDevices = Array.from(new Set(_collectionZone));
// Cache the result
// await this.redisUtils.set(
// redisKey,
// JSON.stringify(collectionZoneDevices),
// 60 * 60 * 24
// );
return collectionZoneDevices;
}
async getZonesByAccessGroups(accessGroupIds, type) {
// Fetch zone IDs associated with these access groups
const zonesIdsQuery = `
SELECT DISTINCT z."zoneId"
FROM dt_zones_collection_map z
WHERE z."collectionId" = ANY($1)
`;
const zonesIdsResult = await this.postgres.query(zonesIdsQuery, [
accessGroupIds,
]);
const zonesIds = zonesIdsResult.rows.map((row) => row.zoneId);
if (zonesIds.length === 0) {
return [];
}
// Use default types if not provided
const zoneTypesToFilter = type || ["Guest Room", "Room"];
// Fetch zone type IDs for the specified type
// Using IN with unnest() for better compatibility with string arrays
const zoneTypesQuery = `
SELECT id
FROM "dt_zoneTypes"
WHERE name IN (SELECT unnest($1::text[]))
`;
const zoneTypes = await this.postgres.query(zoneTypesQuery, [
zoneTypesToFilter,
]);
const guestRoomZoneTypeIds = zoneTypes.rows.map((e) => e.id);
// Fetch zones matching both sets of IDs
const zonesQuery = `
SELECT id
FROM dt_zones
WHERE id = ANY($1) AND "zoneTypeId" = ANY($2)
`;
const zonesResult = await this.postgres.query(zonesQuery, [
zonesIds,
guestRoomZoneTypeIds,
]);
return zonesResult.rows.map((e) => e.id);
}
async getAccessGroup(accessGroupId, propertyId) {
let query;
if (propertyId) {
query = `
SELECT * FROM dt_collections
WHERE "id" = $1 AND "propertyId" = $2
`;
}
else {
query = `
SELECT * FROM dt_collections
WHERE "id" = $1
`;
}
const params = propertyId ? [accessGroupId, propertyId] : [accessGroupId];
const result = await this.postgres.query(query, params);
if (result.rows.length > 0) {
return result.rows[0];
}
return null;
}
async getZoneAccessGroupByZoneId(zoneId) {
const query = `
SELECT * FROM dt_zones_collection_map
WHERE "zoneId" = $1
`;
const result = await this.postgres.query(query, [zoneId]);
if (result.rows.length > 0) {
return result.rows;
}
return null;
}
async getZoneIdsByAccessGroupIds(accessGroupIds) {
if (accessGroupIds.length === 0) {
return [];
}
const query = `
SELECT DISTINCT "zoneId"
FROM dt_zones_collection_map
WHERE "collectionId" = ANY($1)
`;
const result = await this.postgres.query(query, [accessGroupIds]);
return result.rows.map((row) => row.zoneId);
}
async getAllParentZones(zoneId) {
const allParentZoneIds = [];
let currentZoneId = zoneId;
while (currentZoneId) {
const zone = await this.getZone(currentZoneId);
if (!zone || !zone.parentId) {
break;
}
allParentZoneIds.push(zone.parentId);
currentZoneId = zone.parentId;
}
return allParentZoneIds;
}
async getDirectChildZones(zoneId, propertyId) {
const redisKey = propertyId
? `${propertyId}:childZones:${zoneId}`
: `childZones:${zoneId}`;
// Try to get from cache first
const zonesCache = await this.redisUtils.get(redisKey);
let zones = null;
if (zonesCache !== null && zonesCache !== undefined) {
(0, config_1.getLogger)().info(`Got child zones from redis for zone ${zoneId}`);
zones = JSON.parse(zonesCache);
}
else {
const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zoneId}`);
zones = response?.data?.data;
if (zones) {
await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
}
}
// Get only direct children (first level), not all descendants
if (zones && zones.childZones) {
if (Array.isArray(zones.childZones)) {
return zones.childZones
.map((z) => z.id)
.filter((id) => id);
}
else if (zones.childZones.id) {
return [zones.childZones.id];
}
}
return [];
}
async getAllChildZones(zoneId, propertyId) {
const redisKey = propertyId
? `${propertyId}:childZones:${zoneId}`
: `childZones:${zoneId}`;
// Try to get from cache first
const zonesCache = await this.redisUtils.get(redisKey);
let zones = null;
if (zonesCache !== null && zonesCache !== undefined) {
(0, config_1.getLogger)().info(`Got child zones from redis for zone ${zoneId}`);
zones = JSON.parse(zonesCache);
}
else {
const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zoneId}`);
zones = response?.data?.data;
if (zones) {
await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
}
}
// Recursively collect all child zone IDs (using the same pattern as getZonesByAccessGroupIds)
const _zones = (nestedZones, allZones = []) => {
nestedZones.forEach((z) => {
const onlyZone = { ...z };
delete onlyZone.childZones;
allZones.push(onlyZone);
if (!Array.isArray(z.childZones)) {
if (z.childZones && z.childZones.id)
z.childZones = [z.childZones];
}
if (z.childZones && z.childZones.length) {
_zones(z.childZones, allZones);
}
});
return allZones.map((e) => e.id);
};
if (zones && zones.childZones && zones.childZones.length > 0) {
const childZoneIds = _zones(zones.childZones, []);
return childZoneIds;
}
return [];
}
async getAccessGroupsByZoneId(zoneId) {
const query = `
SELECT DISTINCT c.*
FROM dt_collections c
INNER JOIN dt_zones_collection_map zcm ON c.id = zcm."collectionId"
WHERE zcm."zoneId" = $1
AND c."isDeleted" = false
`;
const result = await this.postgres.query(query, [zoneId]);
return result.rows;
}
async getAccessGroupsByZoneIds(zoneIds) {
if (zoneIds.length === 0) {
return [];
}
// Get all access groups associated with any of these zones
const query = `
SELECT DISTINCT c.*
FROM dt_collections c
INNER JOIN dt_zones_collection_map zcm ON c.id = zcm."collectionId"
WHERE zcm."zoneId" = ANY($1)
AND c."isDeleted" = false
`;
const result = await this.postgres.query(query, [zoneIds]);
return result.rows;
}
async getZone(zoneId, propertyId) {
try {
let query;
if (propertyId) {
query = `SELECT * FROM dt_zones WHERE "id" = $1 AND "propertyId" = $2`;
}
else {
query = `SELECT * FROM dt_zones WHERE "id" = $1`;
}
const params = propertyId ? [zoneId, propertyId] : [zoneId];
const zone = await this.postgres.query(query, params);
if (zone.rows.length > 0) {
const zoneData = zone.rows[0];
const zoneType = await this.postgres.query(`SELECT * FROM "dt_zoneTypes" WHERE "id" = $1`, [zoneData.zoneTypeId]);
zoneData.zoneType = {};
zoneData.zoneType = {
id: zoneType.rows[0].id,
name: zoneType.rows[0].name,
};
return zoneData;
}
return null;
}
catch (error) {
console.error("Error in getZone:", error);
throw new Error("Failed to get zone");
}
}
async getZonesByIds(zoneIds) {
if (zoneIds.length === 0) {
return [];
}
try {
// Batch query to get all zones at once
const query = `SELECT * FROM dt_zones WHERE "id" = ANY($1)`;
const result = await this.postgres.query(query, [zoneIds]);
// Get all unique zone type IDs
const zoneTypeIds = [
...new Set(result.rows.map((row) => row.zoneTypeId)),
];
// Batch query for zone types
let zoneTypesMap = new Map();
if (zoneTypeIds.length > 0) {
const zoneTypesQuery = `SELECT * FROM "dt_zoneTypes" WHERE "id" = ANY($1)`;
const zoneTypesResult = await this.postgres.query(zoneTypesQuery, [
zoneTypeIds,
]);
zoneTypesResult.rows.forEach((zt) => {
zoneTypesMap.set(zt.id, { id: zt.id, name: zt.name });
});
}
// Map zone types to zones
return result.rows.map((zoneData) => {
zoneData.zoneType = zoneTypesMap.get(zoneData.zoneTypeId) || {};
return zoneData;
});
}
catch (error) {
console.error("Error in getZonesByIds:", error);
return [];
}
}
async getUser(userId) {
const user = await this.postgres.query(`SELECT * FROM dt_users WHERE "id" = $1`, [userId]);
if (user.rows.length > 0) {
return user.rows[0];
}
return null;
}
async getZoneByDeviceId(deviceId) {
try {
const device = await this.localDeviceService.getDevice(deviceId);
return await this.getZone(device.zoneId);
}
catch (error) {
console.error("Error in getZoneByDeviceId:", error);
throw new Error("Failed to get zone by device ID");
}
}
async getAccessGroups(propertyId, accessibleBy) {
try {
let accessGroups;
if (accessibleBy) {
accessGroups = await this.postgres.query(`SELECT * FROM dt_collections WHERE "propertyId" = $1 AND "accessibleBy" = $2 AND "isDeleted" = false`, [propertyId, accessibleBy]);
return accessGroups.rows;
}
accessGroups = await this.postgres.query(`SELECT * FROM dt_collections WHERE "propertyId" = $1 AND "isDeleted" = false`, [propertyId]);
return accessGroups.rows;
}
catch (error) {
console.error("Error in getAccessGroups:", error);
throw new Error("Failed to get access groups");
}
}
};
__setFunctionName(_classThis, "AdminRepository");
(() => {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
AdminRepository = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return AdminRepository = _classThis;
})();
exports.AdminRepository = AdminRepository;