dt-common-device 3.0.2 → 3.0.4
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/README.md +7 -2
- package/dist/alerts/Alert.model.js +8 -2
- package/dist/alerts/Alert.repository.d.ts +3 -3
- package/dist/alerts/Alert.repository.js +28 -5
- package/dist/alerts/Alert.service.d.ts +18 -4
- package/dist/alerts/Alert.service.js +34 -3
- package/dist/alerts/AlertBuilder.d.ts +1 -1
- package/dist/alerts/AlertBuilder.js +1 -1
- package/dist/alerts/AlertService.example.js +5 -3
- package/dist/alerts/alert.types.d.ts +3 -3
- package/dist/config/config.d.ts +1 -1
- package/dist/config/config.js +3 -3
- package/dist/connection/Connection.repository.js +1 -1
- package/dist/constants/ConnectionProviders.d.ts +11 -0
- package/dist/constants/ConnectionProviders.js +14 -0
- package/dist/constants/Event.d.ts +14 -0
- package/dist/constants/Event.js +14 -0
- package/dist/constants/Service.d.ts +15 -0
- package/dist/constants/Service.js +19 -0
- package/dist/constants/index.d.ts +3 -0
- package/dist/constants/index.js +19 -0
- package/dist/db/redis.js +1 -0
- package/dist/device/cloud/entities/CloudDevice.d.ts +2 -2
- package/dist/device/cloud/entities/CloudDeviceService.d.ts +1 -1
- package/dist/device/cloud/entities/DeviceFactory.d.ts +1 -1
- package/dist/device/cloud/entities/DeviceFactory.js +1 -1
- package/dist/device/local/interfaces/IDevice.d.ts +3 -2
- package/dist/device/local/repository/Device.repository.js +3 -3
- package/dist/device/local/repository/Hub.repository.js +3 -3
- package/dist/device/local/repository/Schedule.repository.js +2 -2
- package/dist/device/local/services/Device.service.d.ts +11 -2
- package/dist/device/local/services/Device.service.js +145 -25
- package/dist/events/BaseEventHandler.d.ts +2 -2
- package/dist/events/BaseEventHandler.js +2 -2
- package/dist/events/BaseEventTransformer.d.ts +1 -1
- package/dist/events/BaseEventTransformer.js +1 -1
- package/dist/events/DeviceEventHandler.d.ts +1 -1
- package/dist/events/DeviceEventHandler.js +4 -3
- package/dist/events/EventHandler.js +1 -1
- package/dist/events/EventHandlerOrchestrator.js +1 -1
- package/dist/events/EventProcessingService.js +1 -1
- package/dist/events/InternalEventSubscription.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/issues/Issue.service.d.ts +11 -1
- package/dist/issues/Issue.service.js +16 -3
- package/dist/issues/IssueService.example.js +4 -2
- package/package.json +1 -1
- package/src/alerts/Alert.model.ts +8 -2
- package/src/alerts/Alert.repository.ts +28 -6
- package/src/alerts/Alert.service.ts +91 -7
- package/src/alerts/AlertBuilder.ts +2 -2
- package/src/alerts/AlertService.example.ts +5 -3
- package/src/alerts/alert.types.ts +3 -3
- package/src/config/config.ts +3 -3
- package/src/connection/Connection.repository.ts +1 -1
- package/src/constants/ConnectionProviders.ts +11 -0
- package/src/constants/Event.ts +14 -0
- package/src/constants/Service.ts +17 -0
- package/src/constants/index.ts +3 -0
- package/src/db/redis.ts +1 -0
- package/src/device/cloud/entities/CloudDevice.ts +2 -2
- package/src/device/cloud/entities/CloudDeviceService.ts +1 -1
- package/src/device/cloud/entities/DeviceFactory.ts +2 -2
- package/src/device/local/interfaces/IDevice.ts +3 -2
- package/src/device/local/repository/Device.repository.ts +3 -3
- package/src/device/local/repository/Hub.repository.ts +3 -3
- package/src/device/local/repository/Schedule.repository.ts +2 -2
- package/src/device/local/services/Device.service.ts +231 -29
- package/src/events/BaseEventHandler.ts +3 -3
- package/src/events/BaseEventTransformer.ts +2 -2
- package/src/events/DeviceEventHandler.ts +6 -4
- package/src/events/EventHandler.ts +1 -1
- package/src/events/EventHandlerOrchestrator.ts +2 -2
- package/src/events/EventProcessingService.ts +2 -2
- package/src/events/InternalEventSubscription.ts +2 -2
- package/src/index.ts +3 -0
- package/src/issues/Issue.service.ts +67 -7
- package/src/issues/IssueService.example.ts +4 -2
- package/tsconfig.json +0 -4
|
@@ -4,14 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.LocalDeviceService = void 0;
|
|
7
|
-
const EventHandler_1 = require("
|
|
7
|
+
const EventHandler_1 = require("../../../events/EventHandler");
|
|
8
8
|
const lodash_1 = require("lodash");
|
|
9
9
|
const Device_repository_1 = require("../repository/Device.repository");
|
|
10
10
|
const typedi_1 = __importDefault(require("typedi"));
|
|
11
|
+
const Alert_service_1 = require("../../../alerts/Alert.service");
|
|
12
|
+
const Issue_service_1 = require("../../../issues/Issue.service");
|
|
13
|
+
const config_1 = require("../../../config/config");
|
|
11
14
|
class LocalDeviceService {
|
|
12
15
|
constructor() {
|
|
13
16
|
this.eventHandler = new EventHandler_1.EventHandler();
|
|
14
17
|
this.deviceRepository = typedi_1.default.get(Device_repository_1.DeviceRepository);
|
|
18
|
+
this.alertService = typedi_1.default.get(Alert_service_1.AlertService);
|
|
19
|
+
this.issueService = typedi_1.default.get(Issue_service_1.IssueService);
|
|
20
|
+
this.logger = (0, config_1.getConfig)().LOGGER;
|
|
15
21
|
}
|
|
16
22
|
async createDevice(body) {
|
|
17
23
|
const device = await this.deviceRepository.createDevice(body);
|
|
@@ -80,50 +86,164 @@ class LocalDeviceService {
|
|
|
80
86
|
}
|
|
81
87
|
return await this.deviceRepository.getStatus(deviceId);
|
|
82
88
|
}
|
|
83
|
-
async setStatus(deviceId, newStatus) {
|
|
89
|
+
async setStatus(deviceId, newStatus, source, reason) {
|
|
84
90
|
if (!deviceId || !newStatus) {
|
|
85
91
|
throw new Error("Device ID and new status are required");
|
|
86
92
|
}
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
93
|
+
const device = await this.getDevice(deviceId);
|
|
94
|
+
const oldStatus = device.status;
|
|
95
|
+
const currentTime = new Date().toISOString();
|
|
96
|
+
// Determine if the new status is ONLINE or OFFLINE
|
|
97
|
+
const isNewStatusOnline = newStatus.liveStatus === "ONLINE";
|
|
98
|
+
const isNewStatusOffline = newStatus.liveStatus === "OFFLINE";
|
|
99
|
+
if (isNewStatusOffline) {
|
|
100
|
+
// New Status = OFFLINE
|
|
101
|
+
await this.handleOfflineStatus(deviceId, device, oldStatus, newStatus, source, reason, currentTime);
|
|
102
|
+
}
|
|
103
|
+
else if (isNewStatusOnline) {
|
|
104
|
+
// New Status = ONLINE
|
|
105
|
+
await this.handleOnlineStatus(deviceId, device, oldStatus, newStatus, source, reason, currentTime);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// For any other status, just update normally
|
|
109
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
110
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async handleOfflineStatus(deviceId, device, oldStatus, newStatus, source, reason, currentTime) {
|
|
114
|
+
const isExistingStatusOnline = oldStatus?.online === true;
|
|
115
|
+
const isExistingStatusOffline = oldStatus?.online === false;
|
|
116
|
+
if (isExistingStatusOnline) {
|
|
117
|
+
// Existing status is Online
|
|
118
|
+
newStatus.online = true;
|
|
119
|
+
newStatus.liveStatus = "OFFLINE";
|
|
120
|
+
newStatus.lastUpdated = currentTime;
|
|
121
|
+
newStatus.error = {
|
|
122
|
+
type: "offline",
|
|
123
|
+
message: reason || "Device went offline",
|
|
124
|
+
default: {},
|
|
125
|
+
};
|
|
90
126
|
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
91
127
|
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
92
128
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
else if (isExistingStatusOffline) {
|
|
130
|
+
// Existing status is Offline
|
|
131
|
+
const timeLapsed = oldStatus?.lastUpdated
|
|
132
|
+
? Date.now() - new Date(oldStatus.lastUpdated).getTime()
|
|
133
|
+
: 0;
|
|
134
|
+
const baselineTime = await this.getDeviceBaseline(deviceId);
|
|
135
|
+
if (timeLapsed > baselineTime) {
|
|
136
|
+
// When the time lapsed is higher than the baseline time
|
|
137
|
+
newStatus.online = false;
|
|
138
|
+
newStatus.liveStatus = "OFFLINE";
|
|
139
|
+
newStatus.lastUpdated = currentTime;
|
|
140
|
+
newStatus.error = {
|
|
141
|
+
type: "offline",
|
|
142
|
+
message: reason || "Device has been offline for longer than baseline",
|
|
143
|
+
default: {},
|
|
144
|
+
};
|
|
145
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
146
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
147
|
+
// Raise alert
|
|
148
|
+
await this.alertService.raiseDeviceOfflineAlert(device, source, reason);
|
|
149
|
+
// Raise issue when the device goes offline if longer than the baseline
|
|
150
|
+
await this.issueService.createDeviceOfflineIssue(device, source, reason);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async handleOnlineStatus(deviceId, device, oldStatus, newStatus, source, reason, currentTime) {
|
|
155
|
+
const isExistingStatusOnline = oldStatus?.online === true;
|
|
156
|
+
const isExistingStatusOffline = oldStatus?.online === false;
|
|
157
|
+
if (isExistingStatusOnline) {
|
|
158
|
+
// Existing status is Online
|
|
159
|
+
if (oldStatus?.liveStatus === "ONLINE") {
|
|
160
|
+
// liveStatus = Online → Do nothing
|
|
98
161
|
return;
|
|
99
162
|
}
|
|
163
|
+
else if (oldStatus?.liveStatus === "OFFLINE") {
|
|
164
|
+
// liveStatus = Offline → Follow the step #2 (same as existing status is Offline)
|
|
165
|
+
newStatus.online = true;
|
|
166
|
+
newStatus.liveStatus = "ONLINE";
|
|
167
|
+
newStatus.lastUpdated = currentTime;
|
|
168
|
+
newStatus.error = {}; // Clear the error
|
|
169
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
170
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
171
|
+
//TODO: ALERT NEEDED?
|
|
172
|
+
// Raise alert
|
|
173
|
+
await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (isExistingStatusOffline) {
|
|
177
|
+
// Existing status is Offline
|
|
178
|
+
newStatus.online = true;
|
|
179
|
+
newStatus.liveStatus = "ONLINE";
|
|
180
|
+
newStatus.lastUpdated = currentTime;
|
|
181
|
+
newStatus.error = undefined; // Clear the error
|
|
182
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
183
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
184
|
+
//TODO: ALERT NEEDED?
|
|
185
|
+
// Raise alert
|
|
186
|
+
await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
|
|
100
187
|
}
|
|
101
188
|
}
|
|
189
|
+
async getDeviceBaseline(deviceId) {
|
|
190
|
+
// TODO: Implement device baseline retrieval
|
|
191
|
+
// This should return the baseline time in milliseconds for the specific device
|
|
192
|
+
// For now, returning a default value of 5 minutes (300000ms)
|
|
193
|
+
// In a real implementation, this would fetch from device configuration or settings
|
|
194
|
+
return 3600000; // 1 hour in milliseconds
|
|
195
|
+
}
|
|
102
196
|
async getBatteryLevel(deviceId) {
|
|
103
197
|
if (!deviceId) {
|
|
104
198
|
throw new Error("Device ID is required");
|
|
105
199
|
}
|
|
106
200
|
return await this.deviceRepository.getBatteryLevel(deviceId);
|
|
107
201
|
}
|
|
108
|
-
async setBatteryLevel(deviceId, batteryLevel) {
|
|
202
|
+
async setBatteryLevel(deviceId, batteryLevel, source) {
|
|
203
|
+
if (!deviceId || batteryLevel === undefined || batteryLevel === null) {
|
|
204
|
+
throw new Error("Device ID and battery level are required");
|
|
205
|
+
}
|
|
206
|
+
// Get device information
|
|
207
|
+
const device = await this.getDevice(deviceId);
|
|
109
208
|
// Fetch the old battery level state
|
|
110
|
-
const oldBatteryLevel =
|
|
209
|
+
const oldBatteryLevel = device.state?.batteryPercentage;
|
|
210
|
+
// Check if battery level has changed
|
|
111
211
|
const isDifferent = !(0, lodash_1.isEqual)(oldBatteryLevel?.value, batteryLevel);
|
|
112
212
|
if (isDifferent) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
213
|
+
// Check if current time is greater than or equal to last updated time (8-hour logic)
|
|
214
|
+
const shouldUpdate = this.shouldUpdateBatteryLevel(oldBatteryLevel?.lastUpdated);
|
|
215
|
+
if (shouldUpdate) {
|
|
216
|
+
// Save the battery level in the device
|
|
217
|
+
await this.deviceRepository.setBatteryLevel(deviceId, batteryLevel);
|
|
218
|
+
await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel);
|
|
219
|
+
// Get property threshold
|
|
220
|
+
const propertyThreshold = await this.getPropertyBatteryThreshold(device.propertyId);
|
|
221
|
+
// Check if battery level is below threshold
|
|
222
|
+
if (batteryLevel < propertyThreshold) {
|
|
223
|
+
// Raise alert
|
|
224
|
+
await this.alertService.raiseDeviceBatteryAlert(device, batteryLevel, propertyThreshold, source);
|
|
225
|
+
// Raise issue when the level is below threshold
|
|
226
|
+
await this.issueService.createDeviceBatteryIssue(device, batteryLevel, propertyThreshold, source);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
shouldUpdateBatteryLevel(lastUpdated) {
|
|
232
|
+
if (!lastUpdated) {
|
|
233
|
+
return true; // No previous update, so we should update
|
|
126
234
|
}
|
|
235
|
+
const lastUpdateTime = new Date(lastUpdated).getTime();
|
|
236
|
+
const currentTime = Date.now();
|
|
237
|
+
const eightHoursInMs = 8 * 60 * 60 * 1000; // 8 hours in milliseconds
|
|
238
|
+
// Return true if current time is greater than or equal to last updated time + 8 hours
|
|
239
|
+
return currentTime >= lastUpdateTime + eightHoursInMs;
|
|
240
|
+
}
|
|
241
|
+
async getPropertyBatteryThreshold(propertyId) {
|
|
242
|
+
// TODO: Implement property battery threshold retrieval
|
|
243
|
+
// This should return the battery threshold for the specific property
|
|
244
|
+
// For now, returning a default value of 20%
|
|
245
|
+
// In a real implementation, this would fetch from property configuration or settings
|
|
246
|
+
return 20; // 20% default threshold
|
|
127
247
|
}
|
|
128
248
|
async getMetaData(deviceId) {
|
|
129
249
|
if (!deviceId) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
2
2
|
import { IEventHandler } from "./interfaces/IEventHandler";
|
|
3
|
-
import { ILogger } from "
|
|
4
|
-
import { LocalDeviceService } from "
|
|
3
|
+
import { ILogger } from "../config/config.types";
|
|
4
|
+
import { LocalDeviceService } from "../device/local/services/Device.service";
|
|
5
5
|
export declare abstract class BaseEventHandler implements IEventHandler {
|
|
6
6
|
protected readonly supportedEventTypes: string[];
|
|
7
7
|
protected readonly priority: number;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseEventHandler = void 0;
|
|
4
|
-
const config_1 = require("
|
|
5
|
-
const Device_service_1 = require("
|
|
4
|
+
const config_1 = require("../config/config");
|
|
5
|
+
const Device_service_1 = require("../device/local/services/Device.service");
|
|
6
6
|
class BaseEventHandler {
|
|
7
7
|
constructor(supportedEventTypes, priority = 100) {
|
|
8
8
|
this.supportedEventTypes = supportedEventTypes;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ILogger } from "
|
|
1
|
+
import { ILogger } from "../config/config.types";
|
|
2
2
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
3
3
|
import { IEventTransformer } from "./interfaces/IEventTransformer";
|
|
4
4
|
export declare abstract class BaseEventTransformer implements IEventTransformer {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseEventTransformer = void 0;
|
|
4
|
-
const config_1 = require("
|
|
4
|
+
const config_1 = require("../config/config");
|
|
5
5
|
class BaseEventTransformer {
|
|
6
6
|
constructor(deviceType, rawData) {
|
|
7
7
|
this.deviceType = deviceType;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDevice } from "
|
|
1
|
+
import { IDevice } from "../device/local/interfaces";
|
|
2
2
|
import { BaseEventHandler } from "./BaseEventHandler";
|
|
3
3
|
import { DeviceEvent, DeviceEventEntity, EventConstructionOptions } from "./interfaces/DeviceEvent";
|
|
4
4
|
export declare class DeviceEventHandler extends BaseEventHandler {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DeviceEventHandler = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const Event_1 = require("../constants/Event");
|
|
6
|
+
const services_1 = require("../device/local/services");
|
|
6
7
|
const BaseEventHandler_1 = require("./BaseEventHandler");
|
|
7
8
|
class DeviceEventHandler extends BaseEventHandler_1.BaseEventHandler {
|
|
8
9
|
constructor() {
|
|
@@ -57,7 +58,7 @@ class DeviceEventHandler extends BaseEventHandler_1.BaseEventHandler {
|
|
|
57
58
|
});
|
|
58
59
|
break;
|
|
59
60
|
case Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.CHANGED:
|
|
60
|
-
await this.localDeviceService.setBatteryLevel(deviceData.deviceId, event?.data?.batteryLevel ?? 0);
|
|
61
|
+
await this.localDeviceService.setBatteryLevel(deviceData.deviceId, event?.data?.batteryLevel ?? 0, constants_1.Source.CLOUD_EVENT);
|
|
61
62
|
break;
|
|
62
63
|
}
|
|
63
64
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.EventHandler = void 0;
|
|
4
4
|
const dt_pub_sub_1 = require("dt-pub-sub");
|
|
5
5
|
const dt_audit_library_1 = require("dt-audit-library");
|
|
6
|
-
const Event_1 = require("
|
|
6
|
+
const Event_1 = require("../constants/Event");
|
|
7
7
|
class EventHandler {
|
|
8
8
|
constructor() {
|
|
9
9
|
this.source = "dt-common-device";
|
|
@@ -40,7 +40,7 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.EventHandlerOrchestrator = void 0;
|
|
42
42
|
const typedi_1 = require("typedi");
|
|
43
|
-
const config_1 = require("
|
|
43
|
+
const config_1 = require("../config/config");
|
|
44
44
|
let EventHandlerOrchestrator = (() => {
|
|
45
45
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
46
46
|
let _classDescriptor;
|
|
@@ -41,7 +41,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
41
41
|
exports.EventProcessingService = void 0;
|
|
42
42
|
const typedi_1 = require("typedi");
|
|
43
43
|
const DeviceEventHandler_1 = require("./DeviceEventHandler");
|
|
44
|
-
const config_1 = require("
|
|
44
|
+
const config_1 = require("../config/config");
|
|
45
45
|
const EventHandlerOrchestrator_1 = require("./EventHandlerOrchestrator");
|
|
46
46
|
let EventProcessingService = (() => {
|
|
47
47
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InternalEventSubscription = exports.InternalEventType = void 0;
|
|
4
4
|
const dt_pub_sub_1 = require("dt-pub-sub");
|
|
5
|
-
const config_1 = require("
|
|
5
|
+
const config_1 = require("../config/config");
|
|
6
6
|
// Event types enum for better type safety
|
|
7
7
|
var InternalEventType;
|
|
8
8
|
(function (InternalEventType) {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -16,6 +16,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.shutdown = exports.getConfig = exports.initialize = exports.LocalScheduleService = exports.LocalHubService = exports.LocalDeviceService = exports.DeviceFactory = exports.CloudDeviceService = exports.CloudDevice = void 0;
|
|
19
|
+
// CONSTANTS EXPORTS
|
|
20
|
+
__exportStar(require("./constants"), exports);
|
|
19
21
|
// DEVICE EXPORTS
|
|
20
22
|
var entities_1 = require("./device/cloud/entities");
|
|
21
23
|
Object.defineProperty(exports, "CloudDevice", { enumerable: true, get: function () { return entities_1.CloudDevice; } });
|
|
@@ -2,6 +2,8 @@ import { IssueRepository } from "./Issue.repository";
|
|
|
2
2
|
import { IIssueDocument } from "./Issue.model";
|
|
3
3
|
import { CreateIssueData, UpdateIssueData, AddCommentData, IssueStatus, IssuePriority, IssuesCategory, EntityType } from "./issue.types";
|
|
4
4
|
import { IssueBuilder } from "./IssueBuilder";
|
|
5
|
+
import { Source } from "../constants/Service";
|
|
6
|
+
import { IDevice } from "../device/local/interfaces";
|
|
5
7
|
export declare class IssueService {
|
|
6
8
|
private readonly issueRepository;
|
|
7
9
|
constructor(issueRepository: IssueRepository);
|
|
@@ -24,7 +26,7 @@ export declare class IssueService {
|
|
|
24
26
|
/**
|
|
25
27
|
* Create a device-specific issue using IssueBuilder
|
|
26
28
|
*/
|
|
27
|
-
createDeviceIssue(deviceId: string, propertyId: string, title: string, description: string,
|
|
29
|
+
createDeviceIssue(deviceId: string, propertyId: string, title: string, description: string, source: Source, category?: IssuesCategory, priority?: IssuePriority, assignedTo?: string, dueDate?: Date): Promise<IIssueDocument>;
|
|
28
30
|
/**
|
|
29
31
|
* Create a hub-specific issue using IssueBuilder
|
|
30
32
|
*/
|
|
@@ -33,6 +35,14 @@ export declare class IssueService {
|
|
|
33
35
|
* Create a user-specific issue using IssueBuilder
|
|
34
36
|
*/
|
|
35
37
|
createUserIssue(userId: string, propertyId: string, title: string, description: string, createdBy: string, category?: IssuesCategory, priority?: IssuePriority, assignedTo?: string, dueDate?: Date): Promise<IIssueDocument>;
|
|
38
|
+
/**
|
|
39
|
+
* Create issue for device going offline longer than baseline
|
|
40
|
+
*/
|
|
41
|
+
createDeviceOfflineIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument>;
|
|
42
|
+
/**
|
|
43
|
+
* Create issue for device battery level below threshold
|
|
44
|
+
*/
|
|
45
|
+
createDeviceBatteryIssue(device: IDevice, batteryLevel: number, threshold: number, source: Source): Promise<IIssueDocument>;
|
|
36
46
|
/**
|
|
37
47
|
* Create a maintenance issue using IssueBuilder
|
|
38
48
|
*/
|
|
@@ -131,11 +131,11 @@ let IssueService = (() => {
|
|
|
131
131
|
/**
|
|
132
132
|
* Create a device-specific issue using IssueBuilder
|
|
133
133
|
*/
|
|
134
|
-
async createDeviceIssue(deviceId, propertyId, title, description,
|
|
134
|
+
async createDeviceIssue(deviceId, propertyId, title, description, source, category, priority, assignedTo, dueDate) {
|
|
135
135
|
const issueBuilder = IssueBuilder_1.IssueBuilder.createDeviceIssue(deviceId, propertyId)
|
|
136
136
|
.setTitle(title)
|
|
137
137
|
.setDescription(description)
|
|
138
|
-
.setCreatedBy(
|
|
138
|
+
.setCreatedBy(source);
|
|
139
139
|
if (category)
|
|
140
140
|
issueBuilder.setCategory(category);
|
|
141
141
|
if (priority)
|
|
@@ -182,6 +182,18 @@ let IssueService = (() => {
|
|
|
182
182
|
issueBuilder.setDueDate(dueDate);
|
|
183
183
|
return await this.createIssue(issueBuilder);
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Create issue for device going offline longer than baseline
|
|
187
|
+
*/
|
|
188
|
+
async createDeviceOfflineIssue(device, source, reason) {
|
|
189
|
+
return await this.createDeviceIssue(device.deviceId, device.propertyId, "Device Offline - Requires Attention", `Device ${device.name} (${device.deviceId}) has been offline for longer than the baseline time. ${reason ? `Reason: ${reason}` : ""} This requires immediate attention to restore device functionality.`, source, issue_types_1.IssuesCategory.OPERATIONS, issue_types_1.IssuePriority.HIGH);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Create issue for device battery level below threshold
|
|
193
|
+
*/
|
|
194
|
+
async createDeviceBatteryIssue(device, batteryLevel, threshold, source) {
|
|
195
|
+
return await this.createDeviceIssue(device.deviceId, device.propertyId, "Device Battery Low - Requires Attention", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%. This requires immediate attention to replace or charge the device battery.`, source, issue_types_1.IssuesCategory.ENERGY, issue_types_1.IssuePriority.MEDIUM);
|
|
196
|
+
}
|
|
185
197
|
/**
|
|
186
198
|
* Create a maintenance issue using IssueBuilder
|
|
187
199
|
*/
|
|
@@ -230,7 +242,8 @@ let IssueService = (() => {
|
|
|
230
242
|
processedIssueData.priority = this.determineDefaultPriority(processedIssueData.category);
|
|
231
243
|
}
|
|
232
244
|
// Business logic: Validate due date is in the future
|
|
233
|
-
if (processedIssueData.dueDate &&
|
|
245
|
+
if (processedIssueData.dueDate &&
|
|
246
|
+
processedIssueData.dueDate <= new Date()) {
|
|
234
247
|
throw new Error("Due date must be in the future");
|
|
235
248
|
}
|
|
236
249
|
return await this.issueRepository.create(processedIssueData);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.IssueServiceExample = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
4
5
|
const IssueBuilder_1 = require("./IssueBuilder");
|
|
5
6
|
const issue_types_1 = require("./issue.types");
|
|
6
7
|
/**
|
|
@@ -49,11 +50,11 @@ class IssueServiceExample {
|
|
|
49
50
|
*/
|
|
50
51
|
async createDeviceIssues() {
|
|
51
52
|
// Create a device issue with default category and priority
|
|
52
|
-
const deviceIssue1 = await this.issueService.createDeviceIssue("device123", "prop456", "Device Battery Low", "Device battery level is below 20%",
|
|
53
|
+
const deviceIssue1 = await this.issueService.createDeviceIssue("device123", "prop456", "Device Battery Low", "Device battery level is below 20%", constants_1.Source.CLOUD_EVENT, undefined, // Use default category
|
|
53
54
|
undefined, // Use default priority
|
|
54
55
|
"maintenance-team", new Date("2024-01-12"));
|
|
55
56
|
// Create a device issue with custom category and priority
|
|
56
|
-
const deviceIssue2 = await this.issueService.createDeviceIssue("device789", "prop456", "Device Firmware Update Available", "New firmware version is available for installation",
|
|
57
|
+
const deviceIssue2 = await this.issueService.createDeviceIssue("device789", "prop456", "Device Firmware Update Available", "New firmware version is available for installation", constants_1.Source.CLOUD_EVENT, issue_types_1.IssuesCategory.READINESS, issue_types_1.IssuePriority.MEDIUM, "admin", new Date("2024-01-20"));
|
|
57
58
|
return { deviceIssue1, deviceIssue2 };
|
|
58
59
|
}
|
|
59
60
|
/**
|
|
@@ -168,6 +169,7 @@ class IssueServiceExample {
|
|
|
168
169
|
assignedTo: "tech-support",
|
|
169
170
|
createdBy: "legacy-system",
|
|
170
171
|
dueDate: new Date("2024-01-20"),
|
|
172
|
+
source: constants_1.Source.CLOUD_EVENT,
|
|
171
173
|
};
|
|
172
174
|
// This still works with the updated createIssue method
|
|
173
175
|
const issue = await this.issueService.createIssue(issueData);
|
package/package.json
CHANGED
|
@@ -47,9 +47,15 @@ interface IAlertModel extends Model<IAlertDocument, {}, IAlertMethods> {
|
|
|
47
47
|
const AlertSchema = new Schema<IAlertDocument, IAlertModel, IAlertMethods>(
|
|
48
48
|
{
|
|
49
49
|
category: {
|
|
50
|
-
type: String,
|
|
50
|
+
type: [String],
|
|
51
51
|
enum: Object.values(AlertCategory),
|
|
52
52
|
required: true,
|
|
53
|
+
validate: {
|
|
54
|
+
validator: function (categories: string[]) {
|
|
55
|
+
return categories && categories.length > 0;
|
|
56
|
+
},
|
|
57
|
+
message: "At least one category is required",
|
|
58
|
+
},
|
|
53
59
|
},
|
|
54
60
|
propertyId: {
|
|
55
61
|
type: String,
|
|
@@ -198,7 +204,7 @@ AlertSchema.statics.findByCategory = function (
|
|
|
198
204
|
category: AlertCategory,
|
|
199
205
|
includeDeleted = false
|
|
200
206
|
) {
|
|
201
|
-
const query: any = { category };
|
|
207
|
+
const query: any = { category: { $in: [category] } };
|
|
202
208
|
if (!includeDeleted) {
|
|
203
209
|
query.isDeleted = false;
|
|
204
210
|
}
|
|
@@ -61,7 +61,7 @@ export class AlertRepository {
|
|
|
61
61
|
async findAll(
|
|
62
62
|
filters: {
|
|
63
63
|
propertyId?: string;
|
|
64
|
-
category?: AlertCategory;
|
|
64
|
+
category?: AlertCategory | AlertCategory[];
|
|
65
65
|
severity?: AlertSeverity;
|
|
66
66
|
entityType?: EntityType;
|
|
67
67
|
entityId?: string;
|
|
@@ -77,7 +77,13 @@ export class AlertRepository {
|
|
|
77
77
|
const query: any = {};
|
|
78
78
|
|
|
79
79
|
if (filters.propertyId) query.propertyId = filters.propertyId;
|
|
80
|
-
if (filters.category)
|
|
80
|
+
if (filters.category) {
|
|
81
|
+
if (Array.isArray(filters.category)) {
|
|
82
|
+
query.category = { $in: filters.category };
|
|
83
|
+
} else {
|
|
84
|
+
query.category = { $in: [filters.category] };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
81
87
|
if (filters.severity) query.severity = filters.severity;
|
|
82
88
|
if (filters.entityType) query.entityType = filters.entityType;
|
|
83
89
|
if (filters.entityId) query.entityId = filters.entityId;
|
|
@@ -170,7 +176,7 @@ export class AlertRepository {
|
|
|
170
176
|
async count(
|
|
171
177
|
filters: {
|
|
172
178
|
propertyId?: string;
|
|
173
|
-
category?: AlertCategory;
|
|
179
|
+
category?: AlertCategory | AlertCategory[];
|
|
174
180
|
severity?: AlertSeverity;
|
|
175
181
|
entityType?: EntityType;
|
|
176
182
|
entityId?: string;
|
|
@@ -183,7 +189,13 @@ export class AlertRepository {
|
|
|
183
189
|
const query: any = {};
|
|
184
190
|
|
|
185
191
|
if (filters.propertyId) query.propertyId = filters.propertyId;
|
|
186
|
-
if (filters.category)
|
|
192
|
+
if (filters.category) {
|
|
193
|
+
if (Array.isArray(filters.category)) {
|
|
194
|
+
query.category = { $in: filters.category };
|
|
195
|
+
} else {
|
|
196
|
+
query.category = { $in: [filters.category] };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
187
199
|
if (filters.severity) query.severity = filters.severity;
|
|
188
200
|
if (filters.entityType) query.entityType = filters.entityType;
|
|
189
201
|
if (filters.entityId) query.entityId = filters.entityId;
|
|
@@ -246,11 +258,20 @@ export class AlertRepository {
|
|
|
246
258
|
* Find alerts by category
|
|
247
259
|
*/
|
|
248
260
|
async findByCategory(
|
|
249
|
-
category: AlertCategory,
|
|
261
|
+
category: AlertCategory | AlertCategory[],
|
|
250
262
|
includeDeleted = false
|
|
251
263
|
): Promise<IAlertDocument[]> {
|
|
252
264
|
try {
|
|
253
|
-
|
|
265
|
+
if (Array.isArray(category)) {
|
|
266
|
+
// Use $in operator for array of categories
|
|
267
|
+
const query: any = { category: { $in: category } };
|
|
268
|
+
if (!includeDeleted) {
|
|
269
|
+
query.isDeleted = false;
|
|
270
|
+
}
|
|
271
|
+
return await AlertModel.find(query).sort({ createdAt: -1 });
|
|
272
|
+
} else {
|
|
273
|
+
return await AlertModel.findByCategory(category, includeDeleted);
|
|
274
|
+
}
|
|
254
275
|
} catch (error) {
|
|
255
276
|
throw new Error(
|
|
256
277
|
`Failed to find alerts by category: ${
|
|
@@ -368,6 +389,7 @@ export class AlertRepository {
|
|
|
368
389
|
]),
|
|
369
390
|
AlertModel.aggregate([
|
|
370
391
|
{ $match: query },
|
|
392
|
+
{ $unwind: "$category" },
|
|
371
393
|
{ $group: { _id: "$category", count: { $sum: 1 } } },
|
|
372
394
|
]),
|
|
373
395
|
]);
|