dt-common-device 7.4.0 → 7.5.0
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.
- package/dist/alerts/Alert.model.js +8 -1
- package/dist/alerts/Alert.service.d.ts +17 -20
- package/dist/alerts/Alert.service.js +141 -139
- package/dist/alerts/AlertBuilder.d.ts +5 -0
- package/dist/alerts/AlertBuilder.js +7 -0
- package/dist/alerts/alert.types.d.ts +10 -4
- package/dist/alerts/alert.types.js +1 -0
- package/dist/entities/device/local/services/Device.service.d.ts +0 -1
- package/dist/entities/device/local/services/Device.service.js +4 -46
- package/dist/events/EventHandler.d.ts +0 -1
- package/dist/events/EventHandler.js +0 -10
- package/dist/issues/Issue.service.d.ts +16 -1
- package/dist/issues/Issue.service.js +43 -24
- package/package.json +1 -1
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.AlertSchema = exports.AlertModel = void 0;
|
|
37
37
|
const mongoose_1 = __importStar(require("mongoose"));
|
|
38
38
|
const alert_types_1 = require("./alert.types");
|
|
39
|
+
const issues_1 = require("../issues");
|
|
39
40
|
// Main Alert schema
|
|
40
41
|
const AlertSchema = new mongoose_1.Schema({
|
|
41
42
|
category: {
|
|
@@ -50,7 +51,7 @@ const AlertSchema = new mongoose_1.Schema({
|
|
|
50
51
|
},
|
|
51
52
|
zoneId: {
|
|
52
53
|
type: String,
|
|
53
|
-
required:
|
|
54
|
+
required: false,
|
|
54
55
|
index: true,
|
|
55
56
|
},
|
|
56
57
|
title: {
|
|
@@ -74,6 +75,12 @@ const AlertSchema = new mongoose_1.Schema({
|
|
|
74
75
|
required: true,
|
|
75
76
|
index: true,
|
|
76
77
|
},
|
|
78
|
+
entitySubType: {
|
|
79
|
+
type: String,
|
|
80
|
+
enum: Object.values(issues_1.EntitySubType),
|
|
81
|
+
required: true,
|
|
82
|
+
index: true,
|
|
83
|
+
},
|
|
77
84
|
severity: {
|
|
78
85
|
type: String,
|
|
79
86
|
enum: Object.values(alert_types_1.AlertSeverity),
|
|
@@ -1,45 +1,42 @@
|
|
|
1
1
|
import { IAlertDocument } from "./Alert.model";
|
|
2
2
|
import { CreateAlertData, UpdateAlertData, AlertCategory, AlertSeverity, IAlertQuery } from "./alert.types";
|
|
3
3
|
import { AlertBuilder } from "./AlertBuilder";
|
|
4
|
+
import { IDevice } from "../entities/device/local/interfaces";
|
|
5
|
+
import { Source } from "../constants";
|
|
4
6
|
export declare class AlertService {
|
|
5
7
|
private readonly alertRepository;
|
|
6
8
|
constructor();
|
|
7
9
|
/**
|
|
8
10
|
* Create an operations alert using AlertBuilder
|
|
9
11
|
*/
|
|
10
|
-
raiseOperationsAlert(data: CreateAlertData): Promise<IAlertDocument>;
|
|
12
|
+
raiseOperationsAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
|
|
11
13
|
/**
|
|
12
14
|
* Create a security alert using AlertBuilder
|
|
13
15
|
*/
|
|
14
|
-
raiseSecurityAlert(data: CreateAlertData): Promise<IAlertDocument>;
|
|
15
|
-
|
|
16
|
-
* Create an energy alert using AlertBuilder
|
|
17
|
-
*/
|
|
18
|
-
raiseEnergyAlert(data: CreateAlertData): Promise<IAlertDocument>;
|
|
19
|
-
/**
|
|
20
|
-
* Create a device-specific alert using AlertBuilder
|
|
21
|
-
*/
|
|
16
|
+
raiseSecurityAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
|
|
17
|
+
raiseDeviceAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
|
|
22
18
|
/**
|
|
23
19
|
* Create a hub-specific alert using AlertBuilder
|
|
24
20
|
*/
|
|
25
|
-
raiseHubAlert(data: CreateAlertData): Promise<IAlertDocument>;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
raiseHubAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
|
|
22
|
+
raiseDoorLeftOpenAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument | null>;
|
|
23
|
+
raiseNewDeviceAlert(device: {
|
|
24
|
+
deviceId: string;
|
|
25
|
+
deviceType: {
|
|
26
|
+
type: any;
|
|
27
|
+
};
|
|
28
|
+
propertyId: string;
|
|
29
|
+
name: string;
|
|
30
|
+
}, source: Source, description?: string): Promise<IAlertDocument | null>;
|
|
29
31
|
/**
|
|
30
32
|
* Raise alert for device coming online (OPERATIONAL only)
|
|
31
33
|
*/
|
|
32
|
-
|
|
33
|
-
* Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
34
|
-
*/
|
|
35
|
-
/**
|
|
36
|
-
* Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
|
|
37
|
-
*/
|
|
34
|
+
raiseDeviceOnlineAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument | null>;
|
|
38
35
|
/**
|
|
39
36
|
* Create a new alert with business logic validation
|
|
40
37
|
* Accepts either a CreateAlertData object or an AlertBuilder instance
|
|
41
38
|
*/
|
|
42
|
-
createAlert(alertData: CreateAlertData | AlertBuilder): Promise<IAlertDocument>;
|
|
39
|
+
createAlert(alertData: CreateAlertData | AlertBuilder): Promise<IAlertDocument | null>;
|
|
43
40
|
/**
|
|
44
41
|
* Get alert by ID with business logic
|
|
45
42
|
*/
|
|
@@ -77,6 +77,9 @@ const Alert_repository_1 = require("./Alert.repository");
|
|
|
77
77
|
const Alert_model_1 = require("./Alert.model");
|
|
78
78
|
const alert_types_1 = require("./alert.types");
|
|
79
79
|
const AlertBuilder_1 = require("./AlertBuilder");
|
|
80
|
+
const constants_1 = require("../constants");
|
|
81
|
+
const admin_1 = require("../entities/admin");
|
|
82
|
+
const audit_1 = require("../audit");
|
|
80
83
|
let AlertService = (() => {
|
|
81
84
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
82
85
|
let _classDescriptor;
|
|
@@ -92,13 +95,15 @@ let AlertService = (() => {
|
|
|
92
95
|
async raiseOperationsAlert(data) {
|
|
93
96
|
const alertBuilder = AlertBuilder_1.AlertBuilder.createOperationsAlert()
|
|
94
97
|
.setPropertyId(data.propertyId)
|
|
95
|
-
.setZoneId(data.zoneId)
|
|
98
|
+
.setZoneId(data.zoneId || "")
|
|
96
99
|
.setTitle(data.title)
|
|
97
100
|
.setDescription(data.description);
|
|
98
101
|
if (data.entityId)
|
|
99
102
|
alertBuilder.setEntityId(data.entityId);
|
|
100
103
|
if (data.entityType)
|
|
101
104
|
alertBuilder.setEntityType(data.entityType);
|
|
105
|
+
if (data.entitySubType)
|
|
106
|
+
alertBuilder.setEntitySubType(data.entitySubType);
|
|
102
107
|
if (data.createdBy)
|
|
103
108
|
alertBuilder.setCreatedBy(data.createdBy);
|
|
104
109
|
return await this.createAlert(alertBuilder);
|
|
@@ -109,56 +114,40 @@ let AlertService = (() => {
|
|
|
109
114
|
async raiseSecurityAlert(data) {
|
|
110
115
|
const alertBuilder = AlertBuilder_1.AlertBuilder.createSecurityAlert()
|
|
111
116
|
.setPropertyId(data.propertyId)
|
|
112
|
-
.setZoneId(data.zoneId)
|
|
117
|
+
.setZoneId(data.zoneId || "")
|
|
113
118
|
.setTitle(data.title)
|
|
114
119
|
.setDescription(data.description);
|
|
115
120
|
if (data.entityId)
|
|
116
121
|
alertBuilder.setEntityId(data.entityId);
|
|
117
122
|
if (data.entityType)
|
|
118
123
|
alertBuilder.setEntityType(data.entityType);
|
|
124
|
+
if (data.entitySubType)
|
|
125
|
+
alertBuilder.setEntitySubType(data.entitySubType);
|
|
119
126
|
if (data.createdBy)
|
|
120
127
|
alertBuilder.setCreatedBy(data.createdBy);
|
|
121
128
|
return await this.createAlert(alertBuilder);
|
|
122
129
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
*/
|
|
126
|
-
async raiseEnergyAlert(data) {
|
|
127
|
-
const alertBuilder = AlertBuilder_1.AlertBuilder.createEnergyAlert()
|
|
128
|
-
.setPropertyId(data.propertyId)
|
|
129
|
-
.setZoneId(data.zoneId)
|
|
130
|
+
async raiseDeviceAlert(data) {
|
|
131
|
+
const alertBuilder = AlertBuilder_1.AlertBuilder.createDeviceAlert(data.entityId || "", data.propertyId, data.zoneId || "")
|
|
130
132
|
.setTitle(data.title)
|
|
131
133
|
.setDescription(data.description);
|
|
132
|
-
if (data.
|
|
133
|
-
alertBuilder.
|
|
134
|
-
if (data.
|
|
135
|
-
alertBuilder.
|
|
134
|
+
if (data.category)
|
|
135
|
+
alertBuilder.setCategory(data.category);
|
|
136
|
+
if (data.severity)
|
|
137
|
+
alertBuilder.setSeverity(data.severity);
|
|
138
|
+
if (data.type)
|
|
139
|
+
alertBuilder.setType(data.type);
|
|
136
140
|
if (data.createdBy)
|
|
137
141
|
alertBuilder.setCreatedBy(data.createdBy);
|
|
142
|
+
if (data.entitySubType)
|
|
143
|
+
alertBuilder.setEntitySubType(data.entitySubType);
|
|
138
144
|
return await this.createAlert(alertBuilder);
|
|
139
145
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Create a device-specific alert using AlertBuilder
|
|
142
|
-
*/
|
|
143
|
-
// async raiseDeviceAlert(data: CreateAlertData): Promise<IAlertDocument> {
|
|
144
|
-
// const alertBuilder = AlertBuilder.createDeviceAlert(
|
|
145
|
-
// data.entityId || "",
|
|
146
|
-
// data.propertyId,
|
|
147
|
-
// data.zoneId
|
|
148
|
-
// )
|
|
149
|
-
// .setTitle(data.title)
|
|
150
|
-
// .setDescription(data.description);
|
|
151
|
-
// if (data.category) alertBuilder.setCategory(data.category);
|
|
152
|
-
// if (data.severity) alertBuilder.setSeverity(data.severity);
|
|
153
|
-
// if (data.type) alertBuilder.setType(data.type);
|
|
154
|
-
// if (data.createdBy) alertBuilder.setCreatedBy(data.createdBy);
|
|
155
|
-
// return await this.createAlert(alertBuilder);
|
|
156
|
-
// }
|
|
157
146
|
/**
|
|
158
147
|
* Create a hub-specific alert using AlertBuilder
|
|
159
148
|
*/
|
|
160
149
|
async raiseHubAlert(data) {
|
|
161
|
-
const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(data.entityId || "", data.propertyId, data.zoneId)
|
|
150
|
+
const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(data.entityId || "", data.propertyId, data.zoneId || "")
|
|
162
151
|
.setTitle(data.title)
|
|
163
152
|
.setDescription(data.description);
|
|
164
153
|
if (data.category)
|
|
@@ -169,125 +158,138 @@ let AlertService = (() => {
|
|
|
169
158
|
alertBuilder.setType(data.type);
|
|
170
159
|
if (data.createdBy)
|
|
171
160
|
alertBuilder.setCreatedBy(data.createdBy);
|
|
161
|
+
if (data.entitySubType)
|
|
162
|
+
alertBuilder.setEntitySubType(data.entitySubType);
|
|
172
163
|
return await this.createAlert(alertBuilder);
|
|
173
164
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
165
|
+
async raiseDoorLeftOpenAlert(device, source, reason) {
|
|
166
|
+
const zone = await typedi_1.default.get(admin_1.AdminService).getZone(device.zoneId);
|
|
167
|
+
return await this.createAlert({
|
|
168
|
+
entityId: device.deviceId,
|
|
169
|
+
entityType: alert_types_1.EntityType.DEVICE,
|
|
170
|
+
entitySubType: device.deviceType.type,
|
|
171
|
+
propertyId: device.propertyId,
|
|
172
|
+
zoneId: device.zoneId,
|
|
173
|
+
title: "Door Left Open - Requires Attention",
|
|
174
|
+
description: `${zone?.name} has a door left open, for more than 10 minutes. ${reason ? `Reason: ${reason}.` : ""}`,
|
|
175
|
+
createdBy: source,
|
|
176
|
+
category: alert_types_1.AlertCategory.SECURITY,
|
|
177
|
+
severity: alert_types_1.AlertSeverity.HIGH,
|
|
178
|
+
type: alert_types_1.AlertType.DOOR_LEFT_OPEN,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
async raiseNewDeviceAlert(device, source, description) {
|
|
182
|
+
return await this.createAlert({
|
|
183
|
+
entityId: device.deviceId,
|
|
184
|
+
entityType: alert_types_1.EntityType.DEVICE,
|
|
185
|
+
entitySubType: device?.deviceType?.type,
|
|
186
|
+
propertyId: device?.propertyId,
|
|
187
|
+
title: "New Device Detected",
|
|
188
|
+
description: description || `New device ${device?.name} has been detected.`,
|
|
189
|
+
createdBy: source,
|
|
190
|
+
category: alert_types_1.AlertCategory.OPERATIONS,
|
|
191
|
+
severity: alert_types_1.AlertSeverity.INFO,
|
|
192
|
+
type: alert_types_1.AlertType.ACCOUNT_NEW_DEVICE,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
197
195
|
/**
|
|
198
196
|
* Raise alert for device coming online (OPERATIONAL only)
|
|
199
197
|
*/
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// createdBy: source,
|
|
216
|
-
// entityType: EntityType.DEVICE,
|
|
217
|
-
// type: AlertType.DEVICE_ONLINE,
|
|
218
|
-
// });
|
|
219
|
-
// }
|
|
220
|
-
/**
|
|
221
|
-
* Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
222
|
-
*/
|
|
223
|
-
// async raiseDeviceBatteryAlert(
|
|
224
|
-
// device: IDevice,
|
|
225
|
-
// batteryLevel: number,
|
|
226
|
-
// threshold: number,
|
|
227
|
-
// source: Source
|
|
228
|
-
// ): Promise<IAlertDocument> {
|
|
229
|
-
// return await this.raiseDeviceAlert({
|
|
230
|
-
// entityId: device.deviceId,
|
|
231
|
-
// propertyId: device.propertyId,
|
|
232
|
-
// zoneId: device.zoneId,
|
|
233
|
-
// title: "Device Battery Low",
|
|
234
|
-
// description: `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`,
|
|
235
|
-
// category: AlertCategory.ENERGY,
|
|
236
|
-
// severity: AlertSeverity.HIGH,
|
|
237
|
-
// createdBy: source,
|
|
238
|
-
// entityType: EntityType.DEVICE,
|
|
239
|
-
// type: AlertType.DEVICE_BATTERY_LOW,
|
|
240
|
-
// });
|
|
241
|
-
// }
|
|
242
|
-
/**
|
|
243
|
-
* Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
|
|
244
|
-
*/
|
|
245
|
-
// async raiseDeviceIssueAlert(
|
|
246
|
-
// device: IDevice,
|
|
247
|
-
// issueType: string,
|
|
248
|
-
// source: Source,
|
|
249
|
-
// reason?: string
|
|
250
|
-
// ): Promise<IAlertDocument> {
|
|
251
|
-
// return await this.raiseDeviceAlert({
|
|
252
|
-
// entityId: device.deviceId,
|
|
253
|
-
// propertyId: device.propertyId,
|
|
254
|
-
// zoneId: device.zoneId,
|
|
255
|
-
// title: `Device Issue - ${issueType}`,
|
|
256
|
-
// description: `Device ${device.name} has an issue: ${issueType}. ${
|
|
257
|
-
// reason ? `Reason: ${reason}` : ""
|
|
258
|
-
// }`,
|
|
259
|
-
// category: AlertCategory.OPERATIONS,
|
|
260
|
-
// severity: AlertSeverity.HIGH,
|
|
261
|
-
// createdBy: source,
|
|
262
|
-
// entityType: EntityType.DEVICE,
|
|
263
|
-
// type: AlertType.DEVICE_ISSUE,
|
|
264
|
-
// });
|
|
265
|
-
// }
|
|
198
|
+
async raiseDeviceOnlineAlert(device, source, reason) {
|
|
199
|
+
return await this.raiseDeviceAlert({
|
|
200
|
+
entityId: device.deviceId,
|
|
201
|
+
propertyId: device.propertyId,
|
|
202
|
+
zoneId: device.zoneId,
|
|
203
|
+
title: "Device Online",
|
|
204
|
+
description: `Device ${device.name} is now online.`,
|
|
205
|
+
category: alert_types_1.AlertCategory.OPERATIONS,
|
|
206
|
+
severity: alert_types_1.AlertSeverity.INFO,
|
|
207
|
+
createdBy: source,
|
|
208
|
+
entityType: alert_types_1.EntityType.DEVICE,
|
|
209
|
+
entitySubType: device.deviceType.type,
|
|
210
|
+
type: alert_types_1.AlertType.DEVICE_ONLINE,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
266
213
|
/**
|
|
267
214
|
* Create a new alert with business logic validation
|
|
268
215
|
* Accepts either a CreateAlertData object or an AlertBuilder instance
|
|
269
216
|
*/
|
|
270
217
|
async createAlert(alertData) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
processedAlertData.snoozeUntil
|
|
288
|
-
|
|
218
|
+
try {
|
|
219
|
+
let processedAlertData;
|
|
220
|
+
// Handle AlertBuilder instance
|
|
221
|
+
if (alertData instanceof AlertBuilder_1.AlertBuilder) {
|
|
222
|
+
processedAlertData = alertData.build();
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
processedAlertData = alertData;
|
|
226
|
+
}
|
|
227
|
+
// Business logic: Validate alert data
|
|
228
|
+
this.validateAlertData(processedAlertData);
|
|
229
|
+
// Business logic: Set default severity if not provided
|
|
230
|
+
if (!processedAlertData.severity) {
|
|
231
|
+
processedAlertData.severity = this.determineDefaultSeverity(processedAlertData.category, processedAlertData.type);
|
|
232
|
+
}
|
|
233
|
+
// Business logic: Validate snooze date is in the future
|
|
234
|
+
if (processedAlertData.snoozeUntil &&
|
|
235
|
+
processedAlertData.snoozeUntil <= new Date()) {
|
|
236
|
+
throw new Error("Snooze date must be in the future");
|
|
237
|
+
}
|
|
238
|
+
const existingAlert = await this.queryAlerts({
|
|
239
|
+
propertyId: processedAlertData.propertyId,
|
|
240
|
+
zoneId: processedAlertData.zoneId,
|
|
241
|
+
entityId: processedAlertData.entityId,
|
|
242
|
+
entityType: processedAlertData.entityType,
|
|
243
|
+
entitySubType: processedAlertData.entitySubType,
|
|
244
|
+
});
|
|
245
|
+
if (existingAlert.length > 0) {
|
|
246
|
+
await (0, audit_1.pushAudit)({
|
|
247
|
+
auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.SKIPPED,
|
|
248
|
+
auditData: {
|
|
249
|
+
reason: "Alert already exists",
|
|
250
|
+
resource: audit_1.Resource.ALERT,
|
|
251
|
+
source: processedAlertData.createdBy,
|
|
252
|
+
propertyId: processedAlertData.propertyId,
|
|
253
|
+
entityId: processedAlertData.entityId,
|
|
254
|
+
entityType: processedAlertData.entityType,
|
|
255
|
+
entitySubType: processedAlertData.entitySubType,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const alert = await this.alertRepository.create(processedAlertData);
|
|
261
|
+
await (0, audit_1.pushAudit)({
|
|
262
|
+
auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.SUCCESS,
|
|
263
|
+
auditData: {
|
|
264
|
+
resource: audit_1.Resource.ALERT,
|
|
265
|
+
source: constants_1.Source.USER,
|
|
266
|
+
propertyId: processedAlertData.propertyId,
|
|
267
|
+
zoneId: processedAlertData.zoneId,
|
|
268
|
+
entityId: processedAlertData.entityId,
|
|
269
|
+
entityType: processedAlertData.entityType,
|
|
270
|
+
entitySubType: processedAlertData.entitySubType,
|
|
271
|
+
type: processedAlertData.type,
|
|
272
|
+
createdBy: processedAlertData.createdBy,
|
|
273
|
+
createdAt: new Date(),
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
return alert;
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
await (0, audit_1.pushAudit)({
|
|
280
|
+
auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.FAILED,
|
|
281
|
+
auditData: {
|
|
282
|
+
resource: audit_1.Resource.ALERT,
|
|
283
|
+
source: constants_1.Source.USER,
|
|
284
|
+
propertyId: alertData?.propertyId || "",
|
|
285
|
+
zoneId: alertData?.zoneId || "",
|
|
286
|
+
errorMessage: error.message,
|
|
287
|
+
error: error,
|
|
288
|
+
createdBy: alertData?.createdBy || "",
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
throw error;
|
|
289
292
|
}
|
|
290
|
-
return await this.alertRepository.create(processedAlertData);
|
|
291
293
|
}
|
|
292
294
|
/**
|
|
293
295
|
* Get alert by ID with business logic
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EntitySubType } from "../issues";
|
|
1
2
|
import { CreateAlertData, AlertCategory, AlertSeverity, EntityType, AlertType } from "./alert.types";
|
|
2
3
|
/**
|
|
3
4
|
* AlertBuilder - A builder pattern implementation for constructing CreateAlertData objects
|
|
@@ -48,6 +49,10 @@ export declare class AlertBuilder {
|
|
|
48
49
|
* Sets the entity type
|
|
49
50
|
*/
|
|
50
51
|
setEntityType(entityType: EntityType): this;
|
|
52
|
+
/**
|
|
53
|
+
* Sets the entity sub type
|
|
54
|
+
*/
|
|
55
|
+
setEntitySubType(entitySubType: EntitySubType): this;
|
|
51
56
|
/**
|
|
52
57
|
* Sets the alert severity (optional, defaults to LOW)
|
|
53
58
|
*/
|
|
@@ -88,6 +88,13 @@ class AlertBuilder {
|
|
|
88
88
|
this.data.entityType = entityType;
|
|
89
89
|
return this;
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Sets the entity sub type
|
|
93
|
+
*/
|
|
94
|
+
setEntitySubType(entitySubType) {
|
|
95
|
+
this.data.entitySubType = entitySubType;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
91
98
|
/**
|
|
92
99
|
* Sets the alert severity (optional, defaults to LOW)
|
|
93
100
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityType } from "../issues/issue.types";
|
|
1
|
+
import { EntitySubType, EntityType } from "../issues/issue.types";
|
|
2
2
|
export declare enum AlertCategory {
|
|
3
3
|
OPERATIONS = "OPERATIONS",
|
|
4
4
|
SECURITY = "SECURITY",
|
|
@@ -20,18 +20,20 @@ export declare enum AlertType {
|
|
|
20
20
|
LOCK_ACCESS_EMERGENCY_CODE = "LOCK_ACCESS_EMERGENCY_CODE",
|
|
21
21
|
LOCK_ACCESS_MASTER_CODE = "LOCK_ACCESS_MASTER_CODE",
|
|
22
22
|
SPECIFIC_DOOR_ACCESS = "SPECIFIC_DOOR_ACCESS",
|
|
23
|
-
GUEST_LOCK_FIRST_ACCESS = "GUEST_LOCK_FIRST_ACCESS"
|
|
23
|
+
GUEST_LOCK_FIRST_ACCESS = "GUEST_LOCK_FIRST_ACCESS",
|
|
24
|
+
DEVICE_ONLINE = "DEVICE_ONLINE"
|
|
24
25
|
}
|
|
25
26
|
export interface AlertDocument {
|
|
26
27
|
_id: string;
|
|
27
28
|
category: AlertCategory;
|
|
28
29
|
propertyId: string;
|
|
29
|
-
zoneId
|
|
30
|
+
zoneId?: string;
|
|
30
31
|
type: AlertType;
|
|
31
32
|
title: string;
|
|
32
33
|
description: string;
|
|
33
34
|
entityId?: string;
|
|
34
35
|
entityType: EntityType;
|
|
36
|
+
entitySubType: EntitySubType;
|
|
35
37
|
severity: AlertSeverity;
|
|
36
38
|
isRead: boolean;
|
|
37
39
|
isActive: boolean;
|
|
@@ -45,11 +47,12 @@ export interface AlertDocument {
|
|
|
45
47
|
export interface CreateAlertData {
|
|
46
48
|
category: AlertCategory;
|
|
47
49
|
propertyId: string;
|
|
48
|
-
zoneId
|
|
50
|
+
zoneId?: string;
|
|
49
51
|
title: string;
|
|
50
52
|
description: string;
|
|
51
53
|
entityId?: string;
|
|
52
54
|
entityType: EntityType;
|
|
55
|
+
entitySubType: EntitySubType;
|
|
53
56
|
severity?: AlertSeverity;
|
|
54
57
|
type?: AlertType;
|
|
55
58
|
createdBy?: string;
|
|
@@ -59,8 +62,10 @@ export interface UpdateAlertData {
|
|
|
59
62
|
category?: AlertCategory;
|
|
60
63
|
title?: string;
|
|
61
64
|
description?: string;
|
|
65
|
+
zoneId?: string;
|
|
62
66
|
entityId?: string;
|
|
63
67
|
entityType?: EntityType;
|
|
68
|
+
entitySubType?: EntitySubType;
|
|
64
69
|
severity?: AlertSeverity;
|
|
65
70
|
type?: AlertType;
|
|
66
71
|
isRead?: boolean;
|
|
@@ -74,6 +79,7 @@ export interface IAlertQuery {
|
|
|
74
79
|
category?: AlertCategory;
|
|
75
80
|
severity?: AlertSeverity;
|
|
76
81
|
entityType?: EntityType;
|
|
82
|
+
entitySubType?: EntitySubType;
|
|
77
83
|
entityId?: string;
|
|
78
84
|
type?: AlertType | AlertType[];
|
|
79
85
|
isActive?: boolean;
|
|
@@ -26,6 +26,7 @@ var AlertType;
|
|
|
26
26
|
AlertType["LOCK_ACCESS_MASTER_CODE"] = "LOCK_ACCESS_MASTER_CODE";
|
|
27
27
|
AlertType["SPECIFIC_DOOR_ACCESS"] = "SPECIFIC_DOOR_ACCESS";
|
|
28
28
|
AlertType["GUEST_LOCK_FIRST_ACCESS"] = "GUEST_LOCK_FIRST_ACCESS";
|
|
29
|
+
AlertType["DEVICE_ONLINE"] = "DEVICE_ONLINE";
|
|
29
30
|
})(AlertType || (exports.AlertType = AlertType = {}));
|
|
30
31
|
// Re-export EntityType from issue.types.ts to avoid duplication
|
|
31
32
|
var issue_types_1 = require("../issues/issue.types");
|
|
@@ -29,7 +29,6 @@ export declare class LocalDeviceService {
|
|
|
29
29
|
private shouldUpdateBatteryLevel;
|
|
30
30
|
updateBatteryState(deviceId: string, batteryState: any): Promise<void>;
|
|
31
31
|
private getPropertyBatteryThreshold;
|
|
32
|
-
private checkForDeviceMalfunctions;
|
|
33
32
|
getMetaData(deviceId: string): Promise<any>;
|
|
34
33
|
setMetaData(deviceId: string, metaData: Record<string, any>, auditBody: IAuditProperties): Promise<any>;
|
|
35
34
|
getDevicesByZone(zoneId: string): Promise<import("../interfaces").IDtDevice[]>;
|
|
@@ -358,32 +358,21 @@ let LocalDeviceService = (() => {
|
|
|
358
358
|
await this.deviceRepository.setBatteryLevel(deviceId, batteryLevel);
|
|
359
359
|
await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel, auditBody);
|
|
360
360
|
if (oldBatteryLevel?.value < batteryLevel &&
|
|
361
|
-
batteryLevel - oldBatteryLevel?.value >
|
|
362
|
-
// Battery level has increased (considering as battery has been replaced)
|
|
363
|
-
await this.eventHandler.onBatteryReplaced(deviceId, batteryLevel, auditBody);
|
|
364
|
-
}
|
|
365
|
-
// Additional condition: if battery level is less than 50, update battery state to "replace"
|
|
366
|
-
if (batteryLevel < 50) {
|
|
361
|
+
batteryLevel - oldBatteryLevel?.value > 50) {
|
|
362
|
+
// Battery level has increased more than 50% (considering as battery has been replaced)
|
|
367
363
|
const batteryState = {
|
|
368
364
|
batteryState: {
|
|
369
|
-
value: "
|
|
365
|
+
value: "replaced",
|
|
370
366
|
lastUpdated: new Date().toISOString(),
|
|
371
367
|
},
|
|
372
368
|
};
|
|
373
369
|
await this.updateBatteryState(deviceId, batteryState);
|
|
374
|
-
await this.eventHandler.
|
|
370
|
+
await this.eventHandler.onBatteryReplaced(deviceId, batteryLevel, auditBody);
|
|
375
371
|
}
|
|
376
372
|
// Get property threshold
|
|
377
373
|
const propertyThreshold = await this.getPropertyBatteryThreshold(device.propertyId);
|
|
378
374
|
// Check if battery level is below threshold
|
|
379
375
|
if (batteryLevel < propertyThreshold) {
|
|
380
|
-
// Raise alert
|
|
381
|
-
// await this.alertService.raiseDeviceBatteryAlert(
|
|
382
|
-
// device,
|
|
383
|
-
// batteryLevel,
|
|
384
|
-
// propertyThreshold,
|
|
385
|
-
// source
|
|
386
|
-
// );
|
|
387
376
|
// Raise issue when the level is below threshold
|
|
388
377
|
await this.issueService.createDeviceBatteryIssue(device, batteryLevel, propertyThreshold, issue_types_1.IssuePriority.CRITICAL, source);
|
|
389
378
|
}
|
|
@@ -415,37 +404,6 @@ let LocalDeviceService = (() => {
|
|
|
415
404
|
}
|
|
416
405
|
return preferences?.settings?.batteryPreference?.value ?? 20;
|
|
417
406
|
}
|
|
418
|
-
async checkForDeviceMalfunctions(device, source, reason) {
|
|
419
|
-
// TODO: Implement device malfunction detection logic
|
|
420
|
-
// This should check for:
|
|
421
|
-
// - Lock jammed
|
|
422
|
-
// - Device not accepting codes
|
|
423
|
-
// - Other malfunction indicators
|
|
424
|
-
// For now, we'll check if the reason indicates a malfunction
|
|
425
|
-
const malfunctionIndicators = [
|
|
426
|
-
"jammed",
|
|
427
|
-
"not accepting codes",
|
|
428
|
-
"malfunction",
|
|
429
|
-
"error",
|
|
430
|
-
"failure",
|
|
431
|
-
];
|
|
432
|
-
const hasMalfunction = malfunctionIndicators.some((indicator) => reason?.toLowerCase().includes(indicator));
|
|
433
|
-
// if (hasMalfunction) {
|
|
434
|
-
// // Raise alert for device malfunction (READINESS + OPERATIONAL)
|
|
435
|
-
// await this.alertService.raiseDeviceIssueAlert(
|
|
436
|
-
// device,
|
|
437
|
-
// "Device Malfunction Detected",
|
|
438
|
-
// source,
|
|
439
|
-
// reason
|
|
440
|
-
// );
|
|
441
|
-
// // Raise issue for device malfunction (READINESS + OPERATIONAL)
|
|
442
|
-
// await this.issueService.createDeviceMalfunctionIssue(
|
|
443
|
-
// device,
|
|
444
|
-
// source,
|
|
445
|
-
// reason
|
|
446
|
-
// );
|
|
447
|
-
// }
|
|
448
|
-
}
|
|
449
407
|
async getMetaData(deviceId) {
|
|
450
408
|
if (!deviceId) {
|
|
451
409
|
throw new Error("Device ID is required");
|
|
@@ -9,7 +9,6 @@ export declare class EventHandler {
|
|
|
9
9
|
onStatusChange(deviceId: string, status: any, auditProperties: IAuditProperties, eventType: any): Promise<void>;
|
|
10
10
|
onStatusChangeMany(query: IStatusQuery, status: IStatus, auditProperties: IAuditProperties, eventType: any): Promise<void>;
|
|
11
11
|
onBatteryLevelChange(deviceId: string, batteryLevel: number, auditProperties: IAuditProperties): Promise<void>;
|
|
12
|
-
onBatteryStateChange(deviceId: string, batteryState: any, auditProperties: IAuditProperties): Promise<void>;
|
|
13
12
|
onBatteryReplaced(deviceId: string, batteryLevel: number, auditProperties: IAuditProperties): Promise<void>;
|
|
14
13
|
onDeviceMetaChange(deviceId: string, metaData: Record<string, any>, auditProperties: IAuditProperties): Promise<void>;
|
|
15
14
|
}
|
|
@@ -125,16 +125,6 @@ let EventHandler = (() => {
|
|
|
125
125
|
},
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
-
async onBatteryStateChange(deviceId, batteryState, auditProperties) {
|
|
129
|
-
await (0, audit_1.pushAudit)({
|
|
130
|
-
auditType: Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.STATE.REPLACE,
|
|
131
|
-
auditData: {
|
|
132
|
-
deviceId,
|
|
133
|
-
batteryState,
|
|
134
|
-
...auditProperties,
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
128
|
async onBatteryReplaced(deviceId, batteryLevel, auditProperties) {
|
|
139
129
|
await (0, audit_1.pushAudit)({
|
|
140
130
|
auditType: Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.REPLACED,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IIssueDocument } from "./Issue.model";
|
|
2
|
-
import { CreateIssueData, UpdateIssueData, AddCommentData, IssuePriority, IssuesCategory, EntityType, IIssueQuery, IssueType } from "./issue.types";
|
|
2
|
+
import { CreateIssueData, UpdateIssueData, AddCommentData, IssuePriority, IssuesCategory, EntityType, EntitySubType, IIssueQuery, IssueType } from "./issue.types";
|
|
3
3
|
import { IssueBuilder } from "./IssueBuilder";
|
|
4
4
|
import { Source } from "../constants/Service";
|
|
5
5
|
import { IDevice } from "../entities/device/local/interfaces";
|
|
@@ -43,10 +43,25 @@ export declare class IssueService {
|
|
|
43
43
|
* Create issue for device going offline longer than baseline
|
|
44
44
|
*/
|
|
45
45
|
createDeviceOfflineIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument | null>;
|
|
46
|
+
createHubOfflineIssue(hub: IDevice, source: Source, reason?: string): Promise<IIssueDocument | null>;
|
|
46
47
|
/**
|
|
47
48
|
* Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
48
49
|
*/
|
|
49
50
|
createDeviceBatteryIssue(device: IDevice, batteryLevel: number, threshold: number, priority: IssuePriority, source: Source): Promise<IIssueDocument | null>;
|
|
51
|
+
createAccountMissingDeviceIssue(device: {
|
|
52
|
+
deviceId: string;
|
|
53
|
+
deviceType: {
|
|
54
|
+
type: any;
|
|
55
|
+
};
|
|
56
|
+
propertyId: string;
|
|
57
|
+
name: string;
|
|
58
|
+
}, source: Source, reason?: string): Promise<IIssueDocument | null>;
|
|
59
|
+
createAccountUnauthorizedIssue(account: {
|
|
60
|
+
accountId: string;
|
|
61
|
+
accountType: EntitySubType;
|
|
62
|
+
propertyId: string;
|
|
63
|
+
name: string;
|
|
64
|
+
}, source: Source, reason?: string): Promise<IIssueDocument | null>;
|
|
50
65
|
/**
|
|
51
66
|
* Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
|
|
52
67
|
*/
|
|
@@ -251,30 +251,21 @@ let IssueService = (() => {
|
|
|
251
251
|
type: issue_types_1.IssueType.DEVICE_OFFLINE,
|
|
252
252
|
});
|
|
253
253
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
// } has a door left open, for more than 10 minutes. ${
|
|
270
|
-
// reason ? `Reason: ${reason}.` : ""
|
|
271
|
-
// }`,
|
|
272
|
-
// createdBy: source,
|
|
273
|
-
// category: IssuesCategory.SECURITY,
|
|
274
|
-
// priority: IssuePriority.HIGH,
|
|
275
|
-
// type: IssueType.DOOR_LEFT_OPEN,
|
|
276
|
-
// });
|
|
277
|
-
// }
|
|
254
|
+
async createHubOfflineIssue(hub, source, reason) {
|
|
255
|
+
return await this.createHubIssue({
|
|
256
|
+
entityId: hub.deviceId,
|
|
257
|
+
entityType: issue_types_1.EntityType.DEVICE,
|
|
258
|
+
entitySubType: hub.deviceType.type,
|
|
259
|
+
propertyId: hub.propertyId,
|
|
260
|
+
zoneId: hub.zoneId,
|
|
261
|
+
title: "Hub Offline - Requires Attention",
|
|
262
|
+
description: `${hub.name} has gone offline. ${reason ? `Reason: ${reason}.` : ""}`,
|
|
263
|
+
createdBy: source,
|
|
264
|
+
category: issue_types_1.IssuesCategory.OPERATIONS,
|
|
265
|
+
priority: issue_types_1.IssuePriority.CRITICAL,
|
|
266
|
+
type: issue_types_1.IssueType.HUB_OFFLINE,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
278
269
|
/**
|
|
279
270
|
* Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
280
271
|
*/
|
|
@@ -293,6 +284,34 @@ let IssueService = (() => {
|
|
|
293
284
|
type: issue_types_1.IssueType.BATTERY_LOW,
|
|
294
285
|
});
|
|
295
286
|
}
|
|
287
|
+
async createAccountMissingDeviceIssue(device, source, reason) {
|
|
288
|
+
return await this.createIssue({
|
|
289
|
+
entityId: device.deviceId,
|
|
290
|
+
entityType: issue_types_1.EntityType.DEVICE,
|
|
291
|
+
entitySubType: device.deviceType.type,
|
|
292
|
+
propertyId: device.propertyId,
|
|
293
|
+
title: "Device Missing - Requires Attention",
|
|
294
|
+
description: `${device.name} is missing from the account. ${reason ? `Reason: ${reason}.` : ""}`,
|
|
295
|
+
createdBy: source,
|
|
296
|
+
category: issue_types_1.IssuesCategory.OPERATIONS,
|
|
297
|
+
priority: issue_types_1.IssuePriority.CRITICAL,
|
|
298
|
+
type: issue_types_1.IssueType.ACCOUNT_MISSING_DEVICE,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
async createAccountUnauthorizedIssue(account, source, reason) {
|
|
302
|
+
return await this.createIssue({
|
|
303
|
+
entityId: account.accountId,
|
|
304
|
+
entityType: issue_types_1.EntityType.CLOUD_DEVICE_ACCOUNT,
|
|
305
|
+
entitySubType: account.accountType,
|
|
306
|
+
propertyId: account.propertyId,
|
|
307
|
+
title: "Account re-authorization required",
|
|
308
|
+
description: `${account.name}'s authorization has expired. Please re-authorize the account. ${reason ? `Reason: ${reason}.` : ""}`,
|
|
309
|
+
createdBy: source,
|
|
310
|
+
category: issue_types_1.IssuesCategory.OPERATIONS,
|
|
311
|
+
priority: issue_types_1.IssuePriority.CRITICAL,
|
|
312
|
+
type: issue_types_1.IssueType.ACCOUNT_UNAUTHORIZED,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
296
315
|
/**
|
|
297
316
|
* Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
|
|
298
317
|
*/
|