@internetderdinge/api 1.229.0 → 1.229.1

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.
Files changed (167) hide show
  1. package/dist/src/accounts/accounts.controller.js +89 -0
  2. package/dist/src/accounts/accounts.route.js +101 -0
  3. package/dist/src/accounts/accounts.schemas.js +12 -0
  4. package/dist/src/accounts/accounts.service.js +65 -0
  5. package/dist/src/accounts/accounts.validation.js +99 -0
  6. package/dist/src/accounts/auth0.service.js +188 -0
  7. package/dist/src/config/config.js +48 -0
  8. package/dist/src/config/logger.js +27 -0
  9. package/dist/src/config/morgan.js +16 -0
  10. package/dist/src/config/passport.cjs +28 -0
  11. package/dist/src/config/roles.js +11 -0
  12. package/dist/src/config/tokens.cjs +10 -0
  13. package/dist/src/devices/devices.controller.js +172 -0
  14. package/dist/src/devices/devices.model.js +94 -0
  15. package/dist/src/devices/devices.route.js +153 -0
  16. package/dist/src/devices/devices.schemas.js +84 -0
  17. package/dist/src/devices/devices.service.js +198 -0
  18. package/dist/src/devices/devices.types.js +1 -0
  19. package/dist/src/devices/devices.validation.js +257 -0
  20. package/dist/src/devicesNotifications/devicesNotifications.controller.js +69 -0
  21. package/dist/src/devicesNotifications/devicesNotifications.model.js +39 -0
  22. package/dist/src/devicesNotifications/devicesNotifications.route.js +124 -0
  23. package/dist/src/devicesNotifications/devicesNotifications.schemas.js +10 -0
  24. package/dist/src/devicesNotifications/devicesNotifications.service.js +181 -0
  25. package/dist/src/devicesNotifications/devicesNotifications.validation.js +46 -0
  26. package/dist/src/email/email.service.js +580 -0
  27. package/dist/src/files/upload.service.js +124 -0
  28. package/dist/src/i18n/i18n.js +38 -0
  29. package/dist/src/i18n/saveMissingLocalJsonBackend.js +53 -0
  30. package/dist/src/i18n/types.js +1 -0
  31. package/dist/src/index.js +48 -0
  32. package/dist/src/iotdevice/iotdevice.controller.js +96 -0
  33. package/dist/src/iotdevice/iotdevice.model.js +17 -0
  34. package/dist/src/iotdevice/iotdevice.route.js +143 -0
  35. package/dist/src/iotdevice/iotdevice.schemas.js +60 -0
  36. package/dist/src/iotdevice/iotdevice.service.js +579 -0
  37. package/dist/src/iotdevice/iotdevice.types.js +1 -0
  38. package/dist/src/iotdevice/iotdevice.validation.js +54 -0
  39. package/dist/src/middlewares/auth.js +75 -0
  40. package/dist/src/middlewares/checkJwt.cjs +17 -0
  41. package/dist/src/middlewares/error.js +36 -0
  42. package/dist/src/middlewares/mongooseValidations/ensureSameOrganization.js +13 -0
  43. package/dist/src/middlewares/rateLimiter.js +7 -0
  44. package/dist/src/middlewares/validate.js +18 -0
  45. package/dist/src/middlewares/validateAction.js +35 -0
  46. package/dist/src/middlewares/validateAdmin.js +18 -0
  47. package/dist/src/middlewares/validateAi.js +16 -0
  48. package/dist/src/middlewares/validateCurrentAuthUser.js +17 -0
  49. package/dist/src/middlewares/validateCurrentUser.js +20 -0
  50. package/dist/src/middlewares/validateDevice.js +98 -0
  51. package/dist/src/middlewares/validateDeviceUserOrganization.js +26 -0
  52. package/dist/src/middlewares/validateOrganization.js +63 -0
  53. package/dist/src/middlewares/validateQuerySearchUserAndOrganization.js +44 -0
  54. package/dist/src/middlewares/validateTokens.js +23 -0
  55. package/dist/src/middlewares/validateUser.js +38 -0
  56. package/dist/src/middlewares/validateZod.js +33 -0
  57. package/dist/src/models/plugins/index.js +4 -0
  58. package/dist/src/models/plugins/paginate.plugin.js +117 -0
  59. package/dist/src/models/plugins/paginateNew.plugin.js +185 -0
  60. package/dist/src/models/plugins/simplePopulate.js +16 -0
  61. package/dist/src/models/plugins/toJSON.plugin.js +35 -0
  62. package/dist/src/organizations/organizations.controller.js +64 -0
  63. package/dist/src/organizations/organizations.model.js +41 -0
  64. package/dist/src/organizations/organizations.route.js +98 -0
  65. package/dist/src/organizations/organizations.schemas.js +7 -0
  66. package/dist/src/organizations/organizations.service.js +59 -0
  67. package/dist/src/organizations/organizations.validation.js +62 -0
  68. package/dist/src/pdf/pdf.controller.js +24 -0
  69. package/dist/src/pdf/pdf.route.js +22 -0
  70. package/dist/src/pdf/pdf.schemas.js +6 -0
  71. package/dist/src/pdf/pdf.service.js +65 -0
  72. package/dist/src/pdf/pdf.validation.js +27 -0
  73. package/dist/src/tokens/tokens.controller.js +60 -0
  74. package/dist/src/tokens/tokens.model.js +18 -0
  75. package/dist/src/tokens/tokens.route.js +52 -0
  76. package/dist/src/tokens/tokens.schemas.js +14 -0
  77. package/dist/src/tokens/tokens.service.js +30 -0
  78. package/dist/src/tokens/tokens.validation.js +9 -0
  79. package/dist/src/types/routeSpec.js +1 -0
  80. package/dist/src/users/users.controller.js +147 -0
  81. package/dist/src/users/users.model.js +50 -0
  82. package/dist/src/users/users.route.js +137 -0
  83. package/dist/src/users/users.schemas.js +69 -0
  84. package/dist/src/users/users.service.js +295 -0
  85. package/dist/src/users/users.types.js +1 -0
  86. package/dist/src/users/users.validation.js +144 -0
  87. package/dist/src/utils/ApiError.js +16 -0
  88. package/dist/src/utils/buildRouterAndDocs.js +72 -0
  89. package/dist/src/utils/catchAsync.js +4 -0
  90. package/dist/src/utils/comparePapers.service.js +32 -0
  91. package/dist/src/utils/deviceUtils.js +63 -0
  92. package/dist/src/utils/filterOptions.js +24 -0
  93. package/dist/src/utils/medicationName.js +10 -0
  94. package/dist/src/utils/pick.js +16 -0
  95. package/dist/src/utils/registerOpenApi.js +28 -0
  96. package/dist/src/utils/urlUtils.js +15 -0
  97. package/dist/src/utils/userName.js +22 -0
  98. package/dist/src/utils/zValidations.js +124 -0
  99. package/dist/src/validations/auth.validation.cjs +53 -0
  100. package/dist/src/validations/custom.validation.js +19 -0
  101. package/dist/src/validations/index.cjs +3 -0
  102. package/package.json +13 -3
  103. package/scripts/release-and-sync-paperless.mjs +135 -0
  104. package/src/accounts/accounts.controller.ts +1 -0
  105. package/src/accounts/accounts.service.ts +1 -0
  106. package/src/accounts/accounts.validation.ts +6 -3
  107. package/src/accounts/auth0.service.ts +55 -28
  108. package/src/config/config.ts +6 -0
  109. package/src/config/logger.ts +15 -9
  110. package/src/devices/devices.controller.ts +7 -1
  111. package/src/devices/devices.model.ts +4 -1
  112. package/src/devices/devices.schemas.ts +10 -8
  113. package/src/devices/devices.service.ts +1 -0
  114. package/src/devices/devices.types.ts +1 -0
  115. package/src/devices/devices.validation.ts +85 -23
  116. package/src/devicesNotifications/devicesNotifications.controller.ts +57 -28
  117. package/src/devicesNotifications/devicesNotifications.model.ts +20 -12
  118. package/src/devicesNotifications/devicesNotifications.service.ts +35 -17
  119. package/src/files/upload.service.ts +52 -28
  120. package/src/i18n/i18n.ts +1 -1
  121. package/src/i18n/types.ts +1 -0
  122. package/src/index.ts +47 -0
  123. package/src/iotdevice/iotdevice.controller.ts +1 -0
  124. package/src/iotdevice/iotdevice.model.ts +6 -3
  125. package/src/iotdevice/iotdevice.route.ts +85 -76
  126. package/src/iotdevice/iotdevice.service.ts +4 -3
  127. package/src/iotdevice/iotdevice.types.ts +6 -0
  128. package/src/middlewares/auth.ts +2 -8
  129. package/src/middlewares/error.ts +26 -12
  130. package/src/middlewares/mongooseValidations/ensureSameOrganization.ts +4 -3
  131. package/src/middlewares/validateAi.ts +17 -9
  132. package/src/middlewares/validateDevice.ts +1 -0
  133. package/src/middlewares/validateDeviceUserOrganization.ts +1 -0
  134. package/src/middlewares/validateOrganization.ts +1 -1
  135. package/src/middlewares/validateQuerySearchUserAndOrganization.ts +1 -0
  136. package/src/middlewares/validateTokens.ts +2 -1
  137. package/src/middlewares/validateUser.ts +1 -0
  138. package/src/models/plugins/index.ts +5 -4
  139. package/src/models/plugins/paginate.plugin.ts +26 -16
  140. package/src/models/plugins/paginateNew.plugin.ts +33 -21
  141. package/src/models/plugins/simplePopulate.ts +8 -3
  142. package/src/models/plugins/toJSON.plugin.ts +12 -5
  143. package/src/organizations/organizations.controller.ts +1 -2
  144. package/src/organizations/organizations.model.ts +4 -4
  145. package/src/organizations/organizations.route.ts +1 -1
  146. package/src/organizations/organizations.service.ts +15 -6
  147. package/src/pdf/pdf.controller.ts +18 -1
  148. package/src/pdf/pdf.service.ts +25 -16
  149. package/src/tokens/tokens.controller.ts +6 -8
  150. package/src/tokens/tokens.model.ts +3 -1
  151. package/src/tokens/tokens.service.ts +3 -2
  152. package/src/types/express.d.ts +17 -0
  153. package/src/types/mongoose.d.ts +22 -0
  154. package/src/users/users.controller.ts +8 -9
  155. package/src/users/users.model.ts +6 -5
  156. package/src/users/users.route.ts +0 -1
  157. package/src/users/users.service.ts +16 -0
  158. package/src/users/users.types.ts +1 -0
  159. package/src/users/users.validation.ts +6 -2
  160. package/src/utils/ApiError.ts +8 -1
  161. package/src/utils/buildRouterAndDocs.ts +56 -21
  162. package/src/utils/catchAsync.ts +27 -3
  163. package/src/utils/medicationName.ts +5 -4
  164. package/src/utils/pick.ts +5 -1
  165. package/src/utils/userName.ts +1 -0
  166. package/src/utils/zValidations.ts +78 -26
  167. package/tsconfig.json +13 -4
@@ -0,0 +1,38 @@
1
+ import path from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { join } from "path";
4
+ import { existsSync, readdirSync } from "fs";
5
+ import i18next from "i18next";
6
+ import Backend, { setLocalesFolder } from "./saveMissingLocalJsonBackend";
7
+ import config from "../config/config";
8
+ // Fix for __dirname in ES modules
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+ export function initI18n(options = {}) {
12
+ const localesFolder = options.generatedPath
13
+ ? path.resolve(options.generatedPath)
14
+ : join(__dirname, "./generated");
15
+ setLocalesFolder(localesFolder);
16
+ const hasLocalesFolder = existsSync(localesFolder);
17
+ if (!i18next.isInitialized) {
18
+ i18next.use(Backend).init({
19
+ initImmediate: false, // setting initImmediate to false, will load the resources synchronously
20
+ fallbackLng: "de",
21
+ preload: hasLocalesFolder
22
+ ? readdirSync(localesFolder)
23
+ .filter((fileName) => path.extname(fileName) === ".json")
24
+ .map((fileName) => path.basename(fileName, ".json"))
25
+ : [],
26
+ debug: false,
27
+ saveMissing: config.env !== "production",
28
+ ns: ["api"],
29
+ defaultNS: "api",
30
+ keySeparator: false,
31
+ interpolation: {
32
+ escapeValue: false,
33
+ },
34
+ });
35
+ }
36
+ return i18next;
37
+ }
38
+ export default i18next;
@@ -0,0 +1,53 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ // Fix for __dirname in ES modules
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ let localesFolder = path.join(__dirname, "./generated");
8
+ export function setLocalesFolder(nextPath) {
9
+ localesFolder = nextPath
10
+ ? path.resolve(nextPath)
11
+ : path.join(__dirname, "./generated");
12
+ }
13
+ async function createMissingTranslation({ content, namespace, language, key, }) {
14
+ const response = await fetch(`${process.env.REACT_APP_WEB_BACKEND_URL}/translations/create-missing`, {
15
+ method: "POST",
16
+ headers: {
17
+ "Content-Type": "application/json",
18
+ },
19
+ body: JSON.stringify({
20
+ key,
21
+ content: content || key,
22
+ namespace,
23
+ language,
24
+ secret: process.env.REACT_APP_TRANSLATION_SECRET,
25
+ }),
26
+ });
27
+ return response;
28
+ }
29
+ const backend = {
30
+ type: "backend",
31
+ read(language, namespace, callback) {
32
+ const filePath = path.join(localesFolder, `${language}.json`);
33
+ try {
34
+ const data = fs.readFileSync(filePath, "utf8");
35
+ const jsonData = JSON.parse(data);
36
+ /* return resources */
37
+ callback(null, jsonData);
38
+ }
39
+ catch (error) {
40
+ callback(error, null);
41
+ }
42
+ },
43
+ create(languages, namespace, key, fallbackValue) {
44
+ console.log("missing translation saved", languages, namespace, key, fallbackValue);
45
+ createMissingTranslation({
46
+ key,
47
+ content: fallbackValue || key,
48
+ namespace,
49
+ language: "en",
50
+ }).catch((error) => console.error("Error creating missing translation:", error));
51
+ },
52
+ };
53
+ export default backend;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ export { default as config } from "../src/config/config";
2
+ export { default as logger } from "../src/config/logger";
3
+ export { default as morgan } from "../src/config/morgan";
4
+ export { default as auth } from "../src/middlewares/auth";
5
+ export { errorConverter, errorHandler } from "../src/middlewares/error";
6
+ export { default as validate } from "../src/middlewares/validate";
7
+ export { validateDevice, validateDeviceIsInOrganization, validateDeviceOrOrganizationQuery, validateDeviceQuery, } from "../src/middlewares/validateDevice";
8
+ export { initI18n } from "../src/i18n/i18n";
9
+ export { default as usersRoute } from "../src/users/users.route";
10
+ export { default as accountsRoute } from "../src/accounts/accounts.route";
11
+ export { default as accountsService } from "../src/accounts/accounts.service";
12
+ export { default as organizationsRoute } from "../src/organizations/organizations.route";
13
+ export { default as organizationsService } from "../src/organizations/organizations.service";
14
+ export { default as Organization } from "../src/organizations/organizations.model";
15
+ export { default as devicesRoute } from "../src/devices/devices.route";
16
+ export { default as devicesService } from "../src/devices/devices.service";
17
+ export { default as Device } from "../src/devices/devices.model";
18
+ export * from "../src/devices/devices.validation";
19
+ export { default as devicesNotificationsRoute } from "./devicesNotifications/devicesNotifications.route";
20
+ export { default as devicesNotificationsService } from "../src/devicesNotifications/devicesNotifications.service";
21
+ export { default as iotDevicesService } from "../src/iotdevice/iotdevice.service";
22
+ export { SIMILARITY_THRESHOLD } from "../src/iotdevice/iotdevice.service";
23
+ export { default as pdfRoute } from "../src/pdf/pdf.route";
24
+ export { default as tokensRoute } from "../src/tokens/tokens.route";
25
+ export * from "../src/tokens/tokens.service";
26
+ export { default as Token } from "../src/tokens/tokens.model";
27
+ export * as usersService from "../src/users/users.service";
28
+ export { User } from "../src/users/users.model";
29
+ export { isAdmin, validateAdmin } from "../src/middlewares/validateAdmin";
30
+ export { sendEmail } from "../src/email/email.service";
31
+ export { default as catchAsync } from "../src/utils/catchAsync";
32
+ export { default as buildRouterAndDocs } from "../src/utils/buildRouterAndDocs";
33
+ export { default as pick } from "../src/utils/pick";
34
+ export { paginate, toJSON } from "../src/models/plugins/index";
35
+ export { compareImages } from "../src/utils/comparePapers.service";
36
+ export { resolvePossiblyRelativeUrl } from "../src/utils/urlUtils";
37
+ export { getSignedFileUrl } from "../src/files/upload.service";
38
+ export * from "../src/utils/ApiError";
39
+ export * from "../src/utils/buildRouterAndDocs";
40
+ export * from "../src/utils/comparePapers.service";
41
+ export * from "../src/utils/deviceUtils";
42
+ export * from "../src/utils/filterOptions";
43
+ export * from "../src/utils/medicationName";
44
+ export * from "../src/utils/pick";
45
+ export * from "../src/utils/registerOpenApi";
46
+ export * from "../src/utils/urlUtils";
47
+ export * from "../src/utils/userName";
48
+ export * from "../src/utils/zValidations";
@@ -0,0 +1,96 @@
1
+ import catchAsync from "../utils/catchAsync";
2
+ import devicesService from "../devices/devices.service";
3
+ import iotDevicesService from "./iotdevice.service";
4
+ import httpStatus from "http-status";
5
+ import ApiError from "../utils/ApiError";
6
+ export const getIotDevices = catchAsync(async (req, res) => {
7
+ const iotDevices = await iotDevicesService.getDeviceStatusList();
8
+ res.send({ results: iotDevices });
9
+ });
10
+ export const getEvents = catchAsync(async (req, res) => {
11
+ const device = await devicesService.getById(req.params.deviceId);
12
+ const events = await iotDevicesService.getEvents({
13
+ ...req.query,
14
+ DeviceId: device.deviceId,
15
+ });
16
+ res.send({ ...events, device });
17
+ });
18
+ export const getDevice = catchAsync(async (req, res) => {
19
+ const events = await iotDevicesService.getDevice(req.body.deviceId);
20
+ res.send(events);
21
+ });
22
+ export const activateDevice = catchAsync(async (req, res) => {
23
+ const events = await iotDevicesService.activateDevice(req.body.deviceId);
24
+ res.send(events);
25
+ });
26
+ export const pingDevice = catchAsync(async (req, res) => {
27
+ const events = await iotDevicesService.pingDevice(req.body.deviceId);
28
+ res.send(events);
29
+ });
30
+ export const shadowAlarmUpdate = catchAsync(async (req, res) => {
31
+ const device = await devicesService.getById(req.params.deviceId);
32
+ const { shadowName, ...others } = req.body;
33
+ const shadow = await iotDevicesService.shadowAlarmUpdate(device.deviceId, others, shadowName);
34
+ res.send({ device, shadow });
35
+ });
36
+ export const shadowAlarmGet = catchAsync(async (req, res) => {
37
+ const device = await devicesService.getById(req.params.deviceId);
38
+ const shadow = await iotDevicesService.shadowAlarmGet(device.deviceId, req.body);
39
+ res.send({ device, shadow });
40
+ });
41
+ export const shadowAdmin = catchAsync(async (req, res) => {
42
+ const shadow = await iotDevicesService.shadowAlarmGet(req.params.nrfId, req.params.shadowName);
43
+ res.send(shadow);
44
+ });
45
+ export const getDeviceStatus = catchAsync(async (req, res) => {
46
+ const events = await iotDevicesService.getDeviceStatus(req.params.deviceId);
47
+ res.send(events);
48
+ });
49
+ export const ledLightHint = catchAsync(async (req, res) => {
50
+ const device = await devicesService.getById(req.params.deviceId);
51
+ const shadow = await iotDevicesService.ledLightHint(device.deviceId, req.body);
52
+ res.send({ device, shadow });
53
+ });
54
+ export const resetDevice = catchAsync(async (req, res) => {
55
+ const device = await devicesService.getById(req.params.deviceId);
56
+ const shadow = await iotDevicesService.resetDevice(device.deviceId, req.body);
57
+ res.send({ device, shadow });
58
+ });
59
+ export const getEntry = catchAsync(async (req, res) => {
60
+ const iotDevice = await iotDevicesService.getDevice([req.params.deviceId]);
61
+ if (!iotDevice?.message?.[0]) {
62
+ throw new ApiError(httpStatus.NOT_FOUND, "IoT Device not found");
63
+ }
64
+ res.send(iotDevice.message[0]);
65
+ });
66
+ export const updateEntry = catchAsync(async (req, res) => {
67
+ const user = await iotDevicesService.updateById(req.params.stockId, req.body);
68
+ res.send(user);
69
+ });
70
+ export const deleteEntry = catchAsync(async (req, res) => {
71
+ const entry = await iotDevicesService.deleteById(req.params.stockId);
72
+ res.send(entry);
73
+ });
74
+ export const getApiStatus = catchAsync(async (req, res) => {
75
+ const events = await iotDevicesService.getApiStatus(req.params.kind);
76
+ if (!events) {
77
+ throw new ApiError(httpStatus.UNAUTHORIZED, "API unavailable");
78
+ }
79
+ res.send(events);
80
+ });
81
+ export default {
82
+ getEvents,
83
+ getIotDevices,
84
+ getDevice,
85
+ shadowAlarmGet,
86
+ shadowAdmin,
87
+ pingDevice,
88
+ getDeviceStatus,
89
+ ledLightHint,
90
+ shadowAlarmUpdate,
91
+ getEntry,
92
+ getApiStatus,
93
+ updateEntry,
94
+ resetDevice,
95
+ deleteEntry,
96
+ };
@@ -0,0 +1,17 @@
1
+ // @ts-nocheck
2
+ import mongoose from "mongoose";
3
+ import { toJSON, paginate } from "../models/plugins/index";
4
+ const iotDeviceSchema = new mongoose.Schema({
5
+ description: {
6
+ type: String,
7
+ },
8
+ meta: { type: Object },
9
+ deviceId: { type: String },
10
+ }, {
11
+ timestamps: true,
12
+ });
13
+ iotDeviceSchema.plugin(toJSON);
14
+ iotDeviceSchema.plugin(paginate);
15
+ export const IotDevices = mongoose.models.IotDevice ||
16
+ mongoose.model("IotDevice", iotDeviceSchema);
17
+ export default IotDevices;
@@ -0,0 +1,143 @@
1
+ import { Router } from "express";
2
+ import buildRouterAndDocs from "../utils/buildRouterAndDocs";
3
+ import auth from "../middlewares/auth";
4
+ import { validateAdmin } from "../middlewares/validateAdmin";
5
+ import { validateDevice } from "../middlewares/validateDevice";
6
+ import { getEventsSchema, getDeviceSchema, getEntrySchema, updateEntrySchema, pingDeviceSchema, iotDevicesSchema, shadowAlarmValidationSchema, apiStatusRequestSchema,
7
+ // add other input schemas as needed
8
+ } from "./iotdevice.validation";
9
+ import { iotDeviceResponseSchema, eventResponseSchema, deviceResponseSchema, shadowAlarmSchema, pingResponseSchema, deviceStatusSchema, apiStatusSchema, entryResponseSchema, } from "./iotdevice.schemas";
10
+ import { getIotDevices, getEvents, getDevice, shadowAlarmGet, shadowAlarmUpdate, shadowAdmin, pingDevice, getDeviceStatus, getApiStatus, getEntry, updateEntry, } from "./iotdevice.controller";
11
+ export const iotdeviceRouteSpecs = [
12
+ {
13
+ method: "get",
14
+ path: "/",
15
+ validate: [auth("getUsers"), validateAdmin],
16
+ requestSchema: iotDevicesSchema,
17
+ responseSchema: iotDeviceResponseSchema.array(),
18
+ handler: getIotDevices,
19
+ summary: "List all IoT devices",
20
+ description: "Retrieves a list of all registered IoT devices.",
21
+ },
22
+ {
23
+ method: "get",
24
+ path: "/events/:deviceId",
25
+ validate: [auth("getUsers"), validateDevice],
26
+ requestSchema: getEventsSchema,
27
+ responseSchema: eventResponseSchema.array(),
28
+ handler: getEvents,
29
+ summary: "Get events for a device",
30
+ description: "Fetches event records for the specified device by its ID.",
31
+ },
32
+ {
33
+ method: "post",
34
+ path: "/devices",
35
+ validate: [auth("getUsers"), validateAdmin],
36
+ requestSchema: getDeviceSchema,
37
+ responseSchema: deviceResponseSchema,
38
+ handler: getDevice,
39
+ summary: "Fetch a single device by criteria",
40
+ description: "Retrieves a single IoT device matching the provided criteria.",
41
+ },
42
+ {
43
+ method: "get",
44
+ path: "/device/shadowAlarmUpdate/:deviceId",
45
+ validate: [auth("getUsers"), validateAdmin],
46
+ requestSchema: getEntrySchema,
47
+ responseSchema: shadowAlarmSchema,
48
+ handler: shadowAlarmGet,
49
+ summary: "Get shadow alarm settings",
50
+ description: "Fetches the shadow alarm configuration for a specific device.",
51
+ },
52
+ {
53
+ method: "post",
54
+ path: "/device/shadowAlarmUpdate/:deviceId",
55
+ validate: [auth("getUsers"), validateAdmin],
56
+ requestSchema: { body: shadowAlarmSchema },
57
+ responseSchema: shadowAlarmSchema,
58
+ handler: shadowAlarmUpdate,
59
+ summary: "Update shadow alarm settings",
60
+ description: "Updates the shadow alarm configuration for a specific device.",
61
+ },
62
+ {
63
+ method: "get",
64
+ path: "/shadow/:nrfId/:shadowName",
65
+ validate: [auth("getUsers"), validateAdmin],
66
+ requestSchema: shadowAlarmValidationSchema,
67
+ responseSchema: shadowAlarmSchema,
68
+ handler: shadowAdmin,
69
+ summary: "Administer device shadow by nrfId and name",
70
+ description: "Performs administrative operations on a device shadow identified by NRF ID and shadow name.",
71
+ },
72
+ {
73
+ method: "post",
74
+ path: "/ledlight/:deviceId",
75
+ validate: [auth("getUsers"), validateAdmin],
76
+ responseSchema: pingResponseSchema,
77
+ handler: pingDevice,
78
+ summary: "Ping device LED light",
79
+ description: "Sends a ping to the device’s LED light to test its connectivity or response.",
80
+ },
81
+ {
82
+ method: "post",
83
+ path: "/ping/:deviceId",
84
+ validate: [auth("getUsers"), validateAdmin],
85
+ requestSchema: pingDeviceSchema,
86
+ responseSchema: pingResponseSchema,
87
+ handler: pingDevice,
88
+ summary: "Ping device",
89
+ description: "Sends a ping command to the specified device to verify its availability.",
90
+ },
91
+ {
92
+ method: "get",
93
+ path: "/getDeviceStatus/:deviceId",
94
+ validate: [auth("getUsers"), validateAdmin],
95
+ responseSchema: deviceStatusSchema,
96
+ handler: getDeviceStatus,
97
+ summary: "Get current status of a device",
98
+ description: "Retrieves the current operational status of the specified device.",
99
+ },
100
+ {
101
+ method: "get",
102
+ path: "/status/:kind",
103
+ validate: [],
104
+ requestSchema: apiStatusRequestSchema,
105
+ responseSchema: apiStatusSchema,
106
+ handler: getApiStatus,
107
+ summary: "Get API status by kind",
108
+ description: "Retrieves the API status information for a given status kind.",
109
+ },
110
+ {
111
+ method: "get",
112
+ path: "/:deviceId",
113
+ validate: [auth("getUsers"), validateDevice, validateAdmin],
114
+ requestSchema: getEntrySchema,
115
+ responseSchema: entryResponseSchema,
116
+ handler: getEntry,
117
+ summary: "Get one entry for a device",
118
+ description: "Fetches a single data entry for the specified device by ID.",
119
+ },
120
+ {
121
+ method: "post",
122
+ path: "/:deviceId",
123
+ validate: [auth("manageUsers"), validateDevice, validateAdmin],
124
+ requestSchema: updateEntrySchema,
125
+ responseSchema: entryResponseSchema,
126
+ handler: updateEntry,
127
+ summary: "Create or replace an entry for a device",
128
+ description: "Creates or replaces a data entry for the specified device.",
129
+ },
130
+ {
131
+ method: "patch",
132
+ path: "/:deviceId",
133
+ validate: [auth("manageUsers"), validateDevice, validateAdmin],
134
+ requestSchema: updateEntrySchema,
135
+ responseSchema: entryResponseSchema,
136
+ handler: updateEntry,
137
+ summary: "Update an entry for a device",
138
+ description: "Applies a partial update to an existing data entry for the specified device.",
139
+ },
140
+ ];
141
+ const router = Router();
142
+ buildRouterAndDocs(router, iotdeviceRouteSpecs, "/iotdevice", ["IoTDevice"]);
143
+ export default router;
@@ -0,0 +1,60 @@
1
+ import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
2
+ import { z } from 'zod';
3
+ extendZodWithOpenApi(z);
4
+ // Represents a device in the system
5
+ export const iotDeviceResponseSchema = z.object({
6
+ deviceId: z.string(),
7
+ name: z.string(),
8
+ model: z.string().optional(),
9
+ firmwareVersion: z.string().optional(),
10
+ registeredAt: z.string(), // ISO timestamp
11
+ lastSeenAt: z.string().optional(), // ISO timestamp
12
+ });
13
+ // An event generated by a device
14
+ export const eventResponseSchema = z.object({
15
+ eventId: z.string(),
16
+ deviceId: z.string(),
17
+ timestamp: z.string(), // ISO timestamp
18
+ type: z.string(),
19
+ payload: z.any(),
20
+ });
21
+ // A single device fetched by criteria
22
+ export const deviceResponseSchema = z.object({
23
+ deviceId: z.string(),
24
+ serialNumber: z.string(),
25
+ type: z.string(),
26
+ owner: z.string(),
27
+ registeredAt: z.string(),
28
+ });
29
+ // Shadow alarm settings
30
+ export const shadowAlarmSchema = z.object({
31
+ enabled: z.boolean(),
32
+ threshold: z.number(),
33
+ mode: z.enum(['auto', 'manual']).optional(),
34
+ });
35
+ // Ping / LED light response
36
+ export const pingResponseSchema = z.object({
37
+ success: z.boolean(),
38
+ message: z.string().optional(),
39
+ timestamp: z.string(),
40
+ });
41
+ // Current status of a device
42
+ export const deviceStatusSchema = z.object({
43
+ deviceId: z.string(),
44
+ online: z.boolean(),
45
+ batteryLevel: z.number().min(0).max(100).optional(),
46
+ lastSeenAt: z.string(),
47
+ });
48
+ // API status by kind
49
+ export const apiStatusSchema = z.object({
50
+ kind: z.string(),
51
+ status: z.enum(['ok', 'degraded', 'down']),
52
+ uptimeSeconds: z.number(),
53
+ });
54
+ // Single entry for a device
55
+ export const entryResponseSchema = z.object({
56
+ entryId: z.string(),
57
+ deviceId: z.string(),
58
+ timestamp: z.string(),
59
+ data: z.any(),
60
+ });