dt-common-device
Version:
A secure and robust device management library for IoT applications
844 lines (843 loc) • 39.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.AlertService = void 0;
const typedi_1 = __importStar(require("typedi"));
const Alert_repository_1 = require("./Alert.repository");
const Alert_model_1 = require("./Alert.model");
const alert_types_1 = require("./alert.types");
const AlertBuilder_1 = require("./AlertBuilder");
const constants_1 = require("../constants");
const issues_1 = require("../issues");
const audit_1 = require("../audit");
let AlertService = (() => {
let _classDecorators = [(0, typedi_1.Service)()];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var AlertService = _classThis = class {
constructor() {
this.alertRepository = typedi_1.default.get(Alert_repository_1.AlertRepository);
}
/**
* Create an operations alert using AlertBuilder
*/
async raiseOperationsAlert(data) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createOperationsAlert()
.setPropertyId(data.propertyId)
.setTitle(data.title)
.setDescription(data.description);
if (data.entityId)
alertBuilder.setEntityId(data.entityId);
if (data.entityType)
alertBuilder.setEntityType(data.entityType);
if (data.entitySubType)
alertBuilder.setEntitySubType(data.entitySubType);
if (data.createdBy)
alertBuilder.setCreatedBy(data.createdBy);
if (data.zoneId)
alertBuilder.setZoneId(data.zoneId);
return await this.createAlert(alertBuilder);
}
/**
* Create a security alert using AlertBuilder
*/
async raiseSecurityAlert(data) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createSecurityAlert()
.setPropertyId(data.propertyId)
.setTitle(data.title)
.setDescription(data.description);
if (data.entityId)
alertBuilder.setEntityId(data.entityId);
if (data.entityType)
alertBuilder.setEntityType(data.entityType);
if (data.entitySubType)
alertBuilder.setEntitySubType(data.entitySubType);
if (data.createdBy)
alertBuilder.setCreatedBy(data.createdBy);
if (data.zoneId)
alertBuilder.setZoneId(data.zoneId);
return await this.createAlert(alertBuilder);
}
async raiseDeviceAlert(data) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createDeviceAlert(data.entityId || "", data.propertyId)
.setTitle(data.title)
.setDescription(data.description);
if (data.category)
alertBuilder.setCategory(data.category);
if (data.severity)
alertBuilder.setSeverity(data.severity);
if (data.type)
alertBuilder.setType(data.type);
if (data.createdBy)
alertBuilder.setCreatedBy(data.createdBy);
if (data.entitySubType)
alertBuilder.setEntitySubType(data.entitySubType);
if (data.zoneId)
alertBuilder.setZoneId(data.zoneId);
return await this.createAlert(alertBuilder);
}
/**
* Create a hub-specific alert using AlertBuilder
*/
async raiseHubAlert(data) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(data.entityId || "", data.propertyId)
.setTitle(data.title)
.setDescription(data.description);
if (data.category)
alertBuilder.setCategory(data.category);
if (data.severity)
alertBuilder.setSeverity(data.severity);
if (data.type)
alertBuilder.setType(data.type);
if (data.createdBy)
alertBuilder.setCreatedBy(data.createdBy);
if (data.entitySubType)
alertBuilder.setEntitySubType(data.entitySubType);
if (data.zoneId)
alertBuilder.setZoneId(data.zoneId);
return await this.createAlert(alertBuilder);
}
async raiseDeviceTamperAttemptAlert(device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Device Tamper Attempt",
description: `System detected a tamper attempt on ${device.name}.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.CRITICAL,
type: alert_types_1.AlertType.DEVICE_TAMPER_ATTEMPT,
});
}
async raiseDoorLeftOpenAlert(device, zone, openThreshold, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Door Left Open",
description: `${zone?.name} has a door left open, for more than ${openThreshold} minutes.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.CRITICAL,
type: alert_types_1.AlertType.DOOR_LEFT_OPEN,
});
}
async raiseIncorrectCodeAlert(device, zone, source, accessCount, timeWindow) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Incorrect Code Used Too Many Times",
description: `Incorrect code used ${accessCount} times on ${zone?.name}. Between ${timeWindow.startDate} and ${timeWindow.endDate}.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.CRITICAL,
type: alert_types_1.AlertType.INCORRECT_CODE_USED,
});
}
async raiseNewDeviceAlert(connection, propertyId, source) {
return await this.createAlert({
entityId: connection.id,
entityType: alert_types_1.EntityType.CLOUD_DEVICE_ACCOUNT,
entitySubType: connection.provider,
propertyId: propertyId,
title: "New Device Detected",
description: `${connection.deviceCount} new device(s), have been detected on the ${connection.provider} account.`,
createdBy: source,
category: alert_types_1.AlertCategory.OPERATIONS,
severity: alert_types_1.AlertSeverity.INFO,
type: alert_types_1.AlertType.ACCOUNT_NEW_DEVICE,
});
}
async raiseDoorOpenFrequentAlert(device, zone, accessTimes, openThreshold, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Door Open Frequently",
description: `${zone?.name} has been opened ${accessTimes} times in the last ${openThreshold} minutes.`,
createdBy: source,
category: alert_types_1.AlertCategory.OPERATIONS,
severity: alert_types_1.AlertSeverity.HIGH,
type: alert_types_1.AlertType.DOOR_OPEN_FREQUENT,
});
}
async raiseDoorOpenOutsideBusinessHoursAlert(device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Door Open Outside Business Hours",
description: `${zone?.name} has been opened outside business hours.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.HIGH,
type: alert_types_1.AlertType.DOOR_OPEN_OUTSIDE_BIZ_HOURS,
});
}
/**
* Raise alert for device coming online (OPERATIONAL only)
*/
async raiseDeviceOnlineAlert(device, source) {
return await this.raiseDeviceAlert({
entityId: device.deviceId,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Device Online",
description: `Device ${device.name} is now online.`,
category: alert_types_1.AlertCategory.OPERATIONS,
severity: alert_types_1.AlertSeverity.INFO,
createdBy: source,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
type: alert_types_1.AlertType.DEVICE_ONLINE,
});
}
async raiseLockAccessEmergencyCodeAlert(device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Emergency Code Used",
description: `${zone?.name} has been accessed using the emergency code.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.HIGH,
type: alert_types_1.AlertType.LOCK_ACCESS_EMERGENCY_CODE,
});
}
async raiseLockAccessEmergencyRfidAlert(device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Emergency RFID Card Used",
description: `${zone?.name} has been accessed using the emergency RFID card.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.HIGH,
type: alert_types_1.AlertType.LOCK_ACCESS_EMERGENCY_RFID,
});
}
async raiseLockAccessMasterRfidAlert(device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Master RFID Card Used",
description: `${zone?.name} has been accessed using the master RFID card.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.HIGH,
type: alert_types_1.AlertType.LOCK_ACCESS_MASTER_RFID,
});
}
async raiseLockAccessMasterCodeAlert(device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Master Code Used",
description: `${zone?.name} has been accessed using the master code.`,
createdBy: source,
category: alert_types_1.AlertCategory.SECURITY,
severity: alert_types_1.AlertSeverity.HIGH,
type: alert_types_1.AlertType.LOCK_ACCESS_MASTER_CODE,
});
}
async raiseSpecificDoorAccessAlert(userName, device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Specific Door Access",
description: `${userName} has accessed ${zone?.name}.`,
createdBy: source,
category: alert_types_1.AlertCategory.OTHER,
severity: alert_types_1.AlertSeverity.INFO,
type: alert_types_1.AlertType.SPECIFIC_DOOR_ACCESS,
});
}
async raiseGuestLockFirstAccessAlert(userName, device, zone, source) {
return await this.createAlert({
entityId: device.deviceId,
entityType: alert_types_1.EntityType.DEVICE,
entitySubType: device.deviceType.type,
propertyId: device.propertyId,
zoneId: device.zoneId,
title: "Guest Used Code for First Time",
description: `${userName} has used the code for the first time to access ${zone?.name}.`,
createdBy: source,
category: alert_types_1.AlertCategory.OTHER,
severity: alert_types_1.AlertSeverity.INFO,
type: alert_types_1.AlertType.GUEST_LOCK_FIRST_ACCESS,
});
}
async raiseZoneNotMappedToAccessGroupAlert(zone, source) {
return await this.createAlert({
zoneId: zone.zoneId,
propertyId: zone.propertyId,
entityId: zone.zoneId,
entityType: alert_types_1.EntityType.ZONE,
entitySubType: issues_1.EntitySubType.ZONE,
title: `Zone Not Mapped to Access Group`,
description: `${zone?.name} is not mapped to any access group. Only Emergency Access Modes Generated. Add to an Access group to generate Guest and Staff Access Modes!`,
createdBy: source,
category: alert_types_1.AlertCategory.OPERATIONS,
severity: alert_types_1.AlertSeverity.INFO,
type: alert_types_1.AlertType.ZONE_NOT_MAPPED_TO_ACCESS_GROUP,
});
}
/**
* Create a new alert with business logic validation
* Accepts either a CreateAlertData object or an AlertBuilder instance
*/
async createAlert(alertData) {
let processedAlertData;
try {
// Handle AlertBuilder instance
if (alertData instanceof AlertBuilder_1.AlertBuilder) {
processedAlertData = alertData.build();
}
else {
processedAlertData = alertData;
}
// Business logic: Validate alert data
this.validateAlertData(processedAlertData);
// Business logic: Set default severity if not provided
if (!processedAlertData.severity) {
processedAlertData.severity = this.determineDefaultSeverity(processedAlertData.category, processedAlertData.type);
}
// Business logic: Validate snooze date is in the future
if (processedAlertData.snoozeUntil &&
new Date(processedAlertData.snoozeUntil) <= new Date()) {
throw new Error("Snooze date must be in the future");
}
const existingAlert = await this.queryAlerts({
propertyId: processedAlertData.propertyId,
zoneId: processedAlertData.zoneId,
entityId: processedAlertData.entityId,
entityType: processedAlertData.entityType,
entitySubType: processedAlertData.entitySubType,
isActive: true,
});
if (existingAlert.length > 0) {
(0, audit_1.pushAudit)({
auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.SKIPPED,
auditData: {
reason: "Alert already exists",
resource: audit_1.Resource.ALERT,
source: processedAlertData.createdBy,
propertyId: processedAlertData.propertyId,
entityId: processedAlertData.entityId,
entityType: processedAlertData.entityType,
entitySubType: processedAlertData.entitySubType,
},
});
return null;
}
const alert = await this.alertRepository.create(processedAlertData);
(0, audit_1.pushAudit)({
auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.SUCCESS,
auditData: {
resource: audit_1.Resource.ALERT,
source: constants_1.Source.USER,
propertyId: processedAlertData.propertyId,
zoneId: processedAlertData.zoneId,
entityId: processedAlertData.entityId,
entityType: processedAlertData.entityType,
entitySubType: processedAlertData.entitySubType,
type: processedAlertData.type,
createdBy: processedAlertData.createdBy,
createdAt: new Date(),
},
});
return alert;
}
catch (error) {
const createAlertData = alertData instanceof AlertBuilder_1.AlertBuilder ? alertData.build() : alertData;
(0, audit_1.pushAudit)({
auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.FAILED,
auditData: {
resource: audit_1.Resource.ALERT,
source: constants_1.Source.USER,
propertyId: createAlertData?.propertyId || "",
zoneId: createAlertData?.zoneId || "",
errorMessage: error instanceof Error ? error.message : "Unknown error",
errorStack: error instanceof Error ? error.stack : "unknown error",
createdBy: createAlertData?.createdBy || "",
},
});
throw error;
}
}
/**
* Get alert by ID with business logic
*/
async getAlertById(id, includeDeleted = false) {
if (!id) {
throw new Error("Alert ID is required");
}
const alert = await this.alertRepository.findById(id, includeDeleted);
// Business logic: Check if alert is snoozed and expired
if (alert?.snoozeUntil && new Date(alert.snoozeUntil) <= new Date()) {
console.warn(`Alert ${id} snooze has expired`);
}
return alert;
}
/**
* Get all alerts with business logic filtering
*/
async queryAlerts(filters = {}) {
// Business logic: Validate filters
this.validateFilters(filters);
// Business logic: Apply business rules to filters
const enhancedFilters = this.applyBusinessRules(filters);
return await this.alertRepository.query(enhancedFilters);
}
async alertCount(filters) {
// Business logic: Apply business rules to filters
const enhancedFilters = this.applyBusinessRules(filters);
return await this.alertRepository.count(enhancedFilters);
}
/**
* Update an alert with business logic validation
*/
async updateAlert(id, updateData) {
if (!id) {
throw new Error("Alert ID is required");
}
// Business logic: Validate update data
this.validateUpdateData(updateData);
// Business logic: Check if alert exists and is not deleted
const existingAlert = await this.alertRepository.findById(id);
if (!existingAlert) {
throw new Error("Alert not found");
}
// Business logic: Handle snooze validation
if (updateData.snoozeUntil) {
this.validateSnoozeDate(new Date(updateData.snoozeUntil));
}
return await this.alertRepository.update(id, updateData);
}
async deleteAlerts(filters, deletedBy, softDelete = true) {
try {
if (!filters || Object.keys(filters).length === 0) {
throw new Error("Filters are required");
}
if (!deletedBy) {
throw new Error("Deleted by user is required");
}
const alerts = await this.queryAlerts(filters);
if (softDelete) {
for (const alert of alerts) {
await this.alertRepository.softDelete(alert.id || alert._id, deletedBy);
}
}
else {
for (const alert of alerts) {
await this.alertRepository.hardDelete(alert.id || alert._id);
}
}
return true;
}
catch (error) {
throw new Error(`Failed to delete alerts: ${error instanceof Error ? error.message : error}`);
}
}
/**
* Soft delete an alert with business logic
*/
async deleteAlert(id, deletedBy) {
if (!id || !deletedBy) {
throw new Error("Alert ID and deleted by user are required");
}
// Business logic: Check if alert can be deleted
const alert = await this.alertRepository.findById(id);
if (!alert) {
throw new Error("Alert not found");
}
// Business logic: Prevent deletion of critical alerts (optional rule)
if (alert.severity === alert_types_1.AlertSeverity.CRITICAL) {
throw new Error("Cannot delete critical alerts");
}
return await this.alertRepository.softDelete(id, deletedBy);
}
/**
* Mark alert as read with business logic
*/
async markAsRead(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.markAsRead(updatedBy);
return await alertModel.save();
}
/**
* Mark alert as unread with business logic
*/
async markAsUnread(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.markAsUnread(updatedBy);
return await alertModel.save();
}
/**
* Activate an alert with business logic
*/
async activateAlert(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.activate(updatedBy);
return await alertModel.save();
}
/**
* Deactivate an alert with business logic
*/
async deactivateAlert(query, updatedBy) {
if (!query || !updatedBy)
throw new Error("Alert query and updated by user are required");
const alerts = await this.queryAlerts(query);
if (!alerts.length)
return null;
for (const alert of alerts) {
const alertModel = await Alert_model_1.AlertModel.findById(alert._id || alert.id);
if (!alertModel)
return null;
alertModel.deactivate(updatedBy);
await alertModel.save();
}
return null;
}
/**
* Snooze an alert with business logic
*/
async snoozeAlert(id, updatedBy, until) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
until ?? (until = new Date(Date.now() + 1000 * 60 * 60 * 24)); // 1 day
// Business logic: Validate snooze date
this.validateSnoozeDate(until);
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.snooze(until, updatedBy);
return await alertModel.save();
}
/**
* Unsnooze an alert with business logic
*/
async unsnoozeAlert(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.unsnooze(updatedBy);
return await alertModel.save();
}
/**
* Get alerts by category with business logic
*/
async getAlertsByCategory(category, includeDeleted = false) {
if (!category) {
throw new Error("Alert category is required");
}
return await this.alertRepository.findByCategory(category, includeDeleted);
}
/**
* Get snoozed alerts with business logic
*/
async getSnoozedAlerts(includeDeleted = false) {
return await this.alertRepository.findSnoozed(includeDeleted);
}
/**
* Get expired snooze alerts with business logic
*/
async getExpiredSnoozeAlerts(includeDeleted = false) {
const expiredAlerts = await this.alertRepository.findExpiredSnooze(includeDeleted);
// Business logic: Log expired snooze alerts
if (expiredAlerts.length > 0) {
console.warn(`Found ${expiredAlerts.length} alerts with expired snooze`);
}
return expiredAlerts;
}
/**
* Get alert statistics with business logic
*/
async getAlertStatistics(propertyId, zoneId) {
const stats = await this.alertRepository.getStatistics(propertyId, zoneId);
// Business logic: Add alerts for critical metrics
if (stats.unread > 0) {
console.warn(`Alert: ${stats.unread} unread alerts require attention`);
}
if (stats.bySeverity[alert_types_1.AlertSeverity.CRITICAL] > 0) {
console.error(`Alert: ${stats.bySeverity[alert_types_1.AlertSeverity.CRITICAL]} critical alerts require immediate attention`);
}
if (stats.bySeverity[alert_types_1.AlertSeverity.HIGH] > 0) {
console.warn(`Alert: ${stats.bySeverity[alert_types_1.AlertSeverity.HIGH]} high severity alerts require attention`);
}
return stats;
}
/**
* Get alerts by zone ID
*/
async getAlertsByZoneId(zoneId, includeDeleted = false) {
if (!zoneId) {
throw new Error("Zone ID is required");
}
return await this.alertRepository.findByZoneId(zoneId, includeDeleted);
}
/**
* Get alerts by zone ID and category
*/
async getAlertsByZoneIdAndCategory(zoneId, category, includeDeleted = false) {
if (!zoneId) {
throw new Error("Zone ID is required");
}
if (!category) {
throw new Error("Alert category is required");
}
return await this.alertRepository.findByZoneIdAndCategory(zoneId, category, includeDeleted);
}
/**
* Get alerts by zone ID and severity
*/
async getAlertsByZoneIdAndSeverity(zoneId, severity, includeDeleted = false) {
if (!zoneId) {
throw new Error("Zone ID is required");
}
if (!severity) {
throw new Error("Alert severity is required");
}
return await this.alertRepository.findByZoneIdAndSeverity(zoneId, severity, includeDeleted);
}
/**
* Get alerts by multiple zone IDs
*/
async getAlertsByZoneIds(zoneIds, includeDeleted = false) {
if (!zoneIds || zoneIds.length === 0) {
throw new Error("Zone IDs array is required and cannot be empty");
}
return await this.alertRepository.findByZoneIds(zoneIds, includeDeleted);
}
/**
* Get alert statistics by zone ID and severity
*/
async getAlertStatisticsByZoneAndSeverity(zoneId, severity) {
if (!zoneId) {
throw new Error("Zone ID is required");
}
const stats = await this.alertRepository.getStatisticsByZoneAndSeverity(zoneId, severity);
// Business logic: Add alerts for critical metrics
if (stats.unread > 0) {
console.warn(`Alert: ${stats.unread} unread alerts in zone ${zoneId} require attention`);
}
if (severity === alert_types_1.AlertSeverity.CRITICAL && stats.total > 0) {
console.error(`Alert: ${stats.total} critical alerts in zone ${zoneId} require immediate attention`);
}
return stats;
}
/**
* Get alerts by zone ID and active status
*/
async getAlertsByZoneIdAndActiveStatus(zoneId, isActive, includeDeleted = false) {
if (!zoneId) {
throw new Error("Zone ID is required");
}
return await this.alertRepository.findByZoneIdAndActiveStatus(zoneId, isActive, includeDeleted);
}
/**
* Get alerts by zone ID and read status
*/
async getAlertsByZoneIdAndReadStatus(zoneId, isRead, includeDeleted = false) {
if (!zoneId) {
throw new Error("Zone ID is required");
}
return await this.alertRepository.findByZoneIdAndReadStatus(zoneId, isRead, includeDeleted);
}
// Private business logic methods
validateAlertData(data) {
if (!data.title || data.title.trim().length < 3) {
throw new Error("Alert title must be at least 3 characters long");
}
if (!data.description || data.description.trim().length < 5) {
throw new Error("Alert description must be at least 5 characters long");
}
if (!data.propertyId) {
throw new Error("Property ID is required");
}
if (!data.entityType) {
throw new Error("Entity type is required");
}
if (!data.type) {
throw new Error("Alert type is required");
}
}
validateFilters(filters) {
if (filters.limit && (filters.limit < 1 || filters.limit > 100)) {
throw new Error("Limit must be between 1 and 100");
}
if (filters.skip && filters.skip < 0) {
throw new Error("Skip must be non-negative");
}
// Validate date filters
if (filters.startDate &&
filters.endDate &&
filters.startDate > filters.endDate) {
throw new Error("Start date must be before or equal to end date");
}
}
validateUpdateData(data) {
if (data.title && data.title.trim().length < 3) {
throw new Error("Alert title must be at least 3 characters long");
}
if (data.description && data.description.trim().length < 5) {
throw new Error("Alert description must be at least 5 characters long");
}
}
validateSnoozeDate(snoozeUntil) {
if (snoozeUntil && snoozeUntil <= new Date()) {
throw new Error("Snooze date must be in the future");
}
}
determineDefaultSeverity(category, type) {
// Business logic: Determine default severity based on category
const categorySeverities = {
[alert_types_1.AlertCategory.OPERATIONS]: alert_types_1.AlertSeverity.HIGH,
[alert_types_1.AlertCategory.SECURITY]: alert_types_1.AlertSeverity.CRITICAL,
[alert_types_1.AlertCategory.ENERGY]: alert_types_1.AlertSeverity.LOW,
[alert_types_1.AlertCategory.OTHER]: alert_types_1.AlertSeverity.LOW,
};
return categorySeverities[category] || alert_types_1.AlertSeverity.LOW;
}
applyBusinessRules(filters) {
// Business logic: Apply additional filters based on business rules
const enhancedFilters = { ...filters };
// Example: Always exclude deleted alerts unless explicitly requested
if (!enhancedFilters.includeDeleted) {
enhancedFilters.includeDeleted = false;
}
// Example: Always exclude snoozed alerts unless explicitly requested
if (!enhancedFilters.includeSnoozed) {
enhancedFilters.includeSnoozed = false;
}
return enhancedFilters;
}
};
__setFunctionName(_classThis, "AlertService");
(() => {
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);
AlertService = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return AlertService = _classThis;
})();
exports.AlertService = AlertService;