diff --git a/.env b/.env index 60be5dc..2f34361 100644 --- a/.env +++ b/.env @@ -1,8 +1,11 @@ -# MONGO_URI=mongodb://127.0.0.1:27017/ -MONGO_USER=admin -MONGO_PASSWORD=admin321 -MONGO_AUTH_DB=admin - -MONGO_URI=mongodb://mongo/ -API_PORT=5000 +# MONGO_URI=mongodb://192.168.0.111/ +# MONGO_USER=mydata +# MONGO_PASSWORD=mongodb@hexr2002 +# MONGO_AUTH_DB=admin + +MONGO_USER=admin +MONGO_PASSWORD=admin321 +MONGO_AUTH_DB=admin +MONGO_URI=mongodb://mongo/ +API_PORT=5000 SOCKET_PORT=8000 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 174fae3..a9e0e96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "bcryptjs": "^2.4.3", "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^4.21.1", + "fs": "^0.0.1-security", "http": "^0.0.1-security", "ip": "^2.0.1", "jsonwebtoken": "^9.0.2", @@ -22,6 +22,7 @@ "swagger-ui-express": "^5.0.1" }, "devDependencies": { + "@types/bcryptjs": "^3.0.0", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", "@types/ip": "^1.1.3", @@ -113,6 +114,16 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "node_modules/@types/bcryptjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-3.0.0.tgz", + "integrity": "sha512-WRZOuCuaz8UcZZE4R5HXTco2goQSI2XxjGY3hbM/xDvwmqFWd4ivooImsMx65OKM6CtNKbnZ5YL+YwAwK7c1dg==", + "deprecated": "This is a stub types definition. bcryptjs provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "bcryptjs": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -339,9 +350,13 @@ } }, "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "dev": true, + "bin": { + "bcrypt": "bin/bcrypt" + } }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -799,6 +814,11 @@ "node": ">= 0.6" } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", diff --git a/package.json b/package.json index a2b1de1..e5682e4 100644 --- a/package.json +++ b/package.json @@ -3,19 +3,20 @@ "version": "1.0.0", "description": "", "main": "index.js", + "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start:api": "nodemon --exec ts-node src/api-server/main.ts", - "start:socket": "nodemon --exec ts-node src/socket-server/index.ts" + "start:api": "nodemon --exec tsx src/api-server/main.ts", + "start:socket": "nodemon --exec tsx src/socket-server/index.ts" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { - "bcryptjs": "^2.4.3", "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^4.21.1", + "fs": "^0.0.1-security", "http": "^0.0.1-security", "ip": "^2.0.1", "jsonwebtoken": "^9.0.2", @@ -25,6 +26,7 @@ "swagger-ui-express": "^5.0.1" }, "devDependencies": { + "@types/bcryptjs": "^3.0.0", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", "@types/ip": "^1.1.3", diff --git a/src/api-server/Dockerfile b/src/api-server/Dockerfile index cd31368..942e1bd 100644 --- a/src/api-server/Dockerfile +++ b/src/api-server/Dockerfile @@ -7,7 +7,7 @@ ENV NODE_ENV development WORKDIR /usr/src/app -RUN npm install -g npm +RUN npm install -g tsx COPY package.json /usr/src/app/package.json diff --git a/src/api-server/Routes/assetfloorRoutes.ts b/src/api-server/Routes/assetfloorRoutes.ts new file mode 100644 index 0000000..92c4811 --- /dev/null +++ b/src/api-server/Routes/assetfloorRoutes.ts @@ -0,0 +1,7 @@ +import * as express from "express"; +import { assetsFloorservice } from "../controller/simulation/assetsFloorservice.ts"; +const router = express.Router(); +router.post("/setasset", assetsFloorservice.setFloorassets); +router.get("/floorAssets/:organization", assetsFloorservice.getFloorItems); +// router.get("/pointData/:modelfileID/:organization", assetsFloorservice.gettypePoints); +export default router; diff --git a/src/api-server/Routes/assetpointRoutes.ts b/src/api-server/Routes/assetpointRoutes.ts new file mode 100644 index 0000000..533eabd --- /dev/null +++ b/src/api-server/Routes/assetpointRoutes.ts @@ -0,0 +1,6 @@ +import * as express from "express"; +import { pointService } from "../controller/assets/pointService.ts"; +const router = express.Router(); +router.post("/pointSchema", pointService.addPoints); +router.get("/pointData/:modelfileID/:organization", pointService.gettypePoints); +export default router; diff --git a/src/api-server/Routes/camera-Routes.ts b/src/api-server/Routes/camera-Routes.ts index a3f9d29..9f2bc5f 100644 --- a/src/api-server/Routes/camera-Routes.ts +++ b/src/api-server/Routes/camera-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { camera } from '../controller/camera/camera-Controlle'; +import { camera } from '../controller/camera/camera-Services.ts'; const router = express.Router(); diff --git a/src/api-server/Routes/environments-Routes.ts b/src/api-server/Routes/environments-Routes.ts index 17046c9..d70035d 100644 --- a/src/api-server/Routes/environments-Routes.ts +++ b/src/api-server/Routes/environments-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { environment } from '../controller/environments/environments-controller'; +import { environment } from '../controller/environments/environments-Services.ts'; const router = express.Router(); router.post('/setEvironments',environment.setEnvironment) diff --git a/src/api-server/Routes/floadWidgetRoute.ts b/src/api-server/Routes/floadWidgetRoute.ts new file mode 100644 index 0000000..784b218 --- /dev/null +++ b/src/api-server/Routes/floadWidgetRoute.ts @@ -0,0 +1,11 @@ +import * as express from "express"; +import { floatWidgetService } from "../controller/visualization/floatWidgetService.ts"; +const router = express.Router(); +router.post("/floatwidget/save", floatWidgetService.addfloatWidget); +router.patch("/floatwidget/delete", floatWidgetService.deletefloatWidget); +router.get( + "/floadData/:zoneId/:organization", + floatWidgetService.getfloatWidget +); +router.get("/A_floatWidget/:floatWidgetID/:organization",floatWidgetService.getsinglefloatWidget) +export default router; \ No newline at end of file diff --git a/src/api-server/Routes/flooritem-Routes.ts b/src/api-server/Routes/flooritem-Routes.ts index 02568b8..44892a4 100644 --- a/src/api-server/Routes/flooritem-Routes.ts +++ b/src/api-server/Routes/flooritem-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { floorItems } from '../controller/assets/flooritem-Controller'; +import { floorItems } from '../controller/assets/flooritem-Services.ts'; const router = express.Router(); router.post('/setfloorItems',floorItems.setFloorItems) diff --git a/src/api-server/Routes/lines-Routes.ts b/src/api-server/Routes/lines-Routes.ts index 2bfcff8..24f72dc 100644 --- a/src/api-server/Routes/lines-Routes.ts +++ b/src/api-server/Routes/lines-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { lines } from '../controller/lines/line-Controller'; +import { lines } from '../controller/lines/line-Services.ts'; const router = express.Router(); diff --git a/src/api-server/Routes/panelRoutes.ts b/src/api-server/Routes/panelRoutes.ts new file mode 100644 index 0000000..931c533 --- /dev/null +++ b/src/api-server/Routes/panelRoutes.ts @@ -0,0 +1,140 @@ +import * as express from "express"; +import { panelService } from "../controller/visualization/panelService.ts"; +const router = express.Router(); +/** + * @swagger + * tags: + * - name: Panels + * description: API operations related to panels + */ +/** + * @swagger + * components: + * schemas: + * Panel: + * type: object + * properties: + * _id: + * type: string + * example: "60d0fe4f5311236168a109ca" + * zoneId: + * type: string + * example: "67e3d030ed12ffa47b4eade3" + * panelName: + * type: string + * example: "New Panel" + * widgets: + * type: array + * items: + * type: string + * example: [] + * isArchive: + * type: boolean + * example: false + * required: + * - zoneId + * - panelName + * - widgets + * - isArchive + */ + +/** + * @swagger + * /panel/save: + * post: + * summary: Create new panels for a given zone + * tags: [Panels] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * organization: + * type: string + * example: "NEWORG" + * zoneId: + * type: string + * example: "67e3d030ed12ffa47b4eade3" + * panelOrder: + * type: array + * items: + * type: string + * example: ["up", "right", "left", "down"] + * responses: + * 201: + * description: Panels created successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Panels created successfully" + * panelID: + * type: array + * items: + * type: string + * example: ["60d0fe4f5311236168a109ca", "60d0fe4f5311236168a109cb"] + * 200: + * description: No new panels were created as they already exist + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "No new panels were created. All panels already exist." + * 404: + * description: Zone not found + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone not found" + * 500: + * description: Server error + */ +router.post("/panel/save", panelService.AddPanel); + +/** + * @swagger + * /panel/delete: + * patch: + * summary: Delete the panel on the Zone + * tags: [Panels] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * organization: + * type: string + * example: "NEWORG" + * zoneId: + * type: string + * example: "0114-58-064-925" + * panelID: + * type: string + * example: "67e4f754cc778ad6c123394b" + * responses: + * 200: + * description: Panel deleted successfully + * 409: + * description: Panel Already Deleted + * 404: + * description: Zone not found + * 500: + * description: Server error + */ +router.patch("/panel/delete", panelService.deletePanel); +// router.get("/zone/:sceneID", Zoneservice.allZones); +export default router; diff --git a/src/api-server/Routes/share-Routes.ts b/src/api-server/Routes/share-Routes.ts index cb41051..57c4b7f 100644 --- a/src/api-server/Routes/share-Routes.ts +++ b/src/api-server/Routes/share-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { share } from '../controller/share/share-Controller'; +import { share } from '../controller/share/share-Controller.ts'; const router = express.Router(); diff --git a/src/api-server/Routes/templateRoutes.ts b/src/api-server/Routes/templateRoutes.ts new file mode 100644 index 0000000..26410ac --- /dev/null +++ b/src/api-server/Routes/templateRoutes.ts @@ -0,0 +1,12 @@ +import * as express from "express"; +import { templateService } from "../controller/visualization/templateService.ts"; +const router = express.Router(); +router.post("/template/save", templateService.AddTemplate); +router.get("/templateData/:organization", templateService.GetAllTemplates); +router.post("/TemplatetoZone", templateService.AddToZone); +router.patch( + "/TemplateDelete/:templateID/:organization", + templateService.Deletezone +); //delete zone + +export default router; diff --git a/src/api-server/Routes/user-Routes.ts b/src/api-server/Routes/user-Routes.ts index 64c321b..4f5815a 100644 --- a/src/api-server/Routes/user-Routes.ts +++ b/src/api-server/Routes/user-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { user } from '../controller/user-Controller'; +import { user } from '../controller/user-Controller.ts'; const router = express.Router(); diff --git a/src/api-server/Routes/wallItems-Routes.ts b/src/api-server/Routes/wallItems-Routes.ts index 143d5aa..6b7c52a 100644 --- a/src/api-server/Routes/wallItems-Routes.ts +++ b/src/api-server/Routes/wallItems-Routes.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { wallItems } from '../controller/assets/wallitem-Controller'; +import { wallItems } from '../controller/assets/wallitem-Services.ts'; const router = express.Router(); diff --git a/src/api-server/Routes/widget3dRoutes.ts b/src/api-server/Routes/widget3dRoutes.ts new file mode 100644 index 0000000..31a169f --- /dev/null +++ b/src/api-server/Routes/widget3dRoutes.ts @@ -0,0 +1,6 @@ +import * as express from "express"; +import { widget3dService } from "../controller/visualization/3dWidgetService.ts"; +const router = express.Router(); +router.post("/3dwidget/save", widget3dService.add3Dwidget); +router.get("/3dwidgetData/:zoneId/:organization", widget3dService.get3Dwiget); +export default router; diff --git a/src/api-server/Routes/widgetRoute.ts b/src/api-server/Routes/widgetRoute.ts new file mode 100644 index 0000000..df5f7c3 --- /dev/null +++ b/src/api-server/Routes/widgetRoute.ts @@ -0,0 +1,144 @@ +import * as express from "express"; +import { widgetService } from "../controller/visualization/widgetService.ts"; +const router = express.Router(); +/** + * @swagger + * tags: + * - name: Widgets + * description: API operations related to widgets + */ +/** + * @swagger + * components: + * schemas: + * Widget: + * type: object + * properties: + * _id: + * type: string + * example: "60d0fe4f5311236168a109cd" + * widgetName: + * type: string + * example: "Temperature Widget" + * widgetside: + * type: string + * example: "right" + * widgetID: + * type: string + * example: "wid-12345" + * widgetOrder: + * type: string + * example: "1" + * elementType: + * type: string + * example: "chart" + * elementColor: + * type: string + * example: "#FF5733" + * fontFamily: + * type: string + * example: "Arial" + * fontStyle: + * type: string + * example: "bold" + * fontWeight: + * type: string + * example: "600" + * isArchive: + * type: boolean + * example: false + * panelID: + * type: string + * example: "67e3d030ed12ffa47b4eade3" + * Data: + * type: array + * items: + * type: object + * example: [] + * required: + * - widgetName + * - widgetID + * - widgetOrder + * - elementType + * - panelID + * + */ +/** + * @swagger + * /widget/save: + * post: + * summary: Create a new widget inside a panel + * tags: [Widgets] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * organization: + * type: string + * example: "NEWORG" + * panelID: + * type: string + * example: "67e3d030ed12ffa47b4eade3" + * widgetName: + * type: string + * example: "Temperature Widget" + * widgetOrder: + * type: string + * example: "1" + * type: + * type: string + * example: "chart" + * widgetID: + * type: string + * example: "wid-12345" + * panel: + * type: string + * example: "right" + * responses: + * 201: + * description: Widget created successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Widget created successfully" + * widgetID: + * type: string + * example: "60d0fe4f5311236168a109cd" + * 404: + * description: Panel not found + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "PanelID not found" + * 409: + * description: Widget with the given widgetID already exists + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Widget already exists for the widgetID" + * 500: + * description: Server error + */ +router.post("/widget/save", widgetService.addWidget); +router.patch("/widget/:widgetID", widgetService.updatewidget); +router.patch("/delete/widget", widgetService.deleteWidget); +router.get( + "/WidgetData/:widgetID/:organization", + widgetService.getDatafromWidget +); +export default router; diff --git a/src/api-server/Routes/zone-Routes.ts b/src/api-server/Routes/zone-Routes.ts index 84a838d..4293328 100644 --- a/src/api-server/Routes/zone-Routes.ts +++ b/src/api-server/Routes/zone-Routes.ts @@ -1,13 +1,13 @@ import express from 'express'; -import { zone } from '../controller/lines/zone-Controller'; +import { zone } from '../controller/lines/zone-Services.ts'; const router = express.Router(); router.post('/setZone',zone.setZone) router.delete('/deleteZone',zone.deleteZone) router.get('/findZones/:organization',zone.getZones) -router.get('/A_zone/:zoneID/:organization',zone.ZoneData) +// router.get('/A_zone/:zoneId/:organization',zone.ZoneData) diff --git a/src/api-server/Routes/zoneRoutes.ts b/src/api-server/Routes/zoneRoutes.ts new file mode 100644 index 0000000..9f45e47 --- /dev/null +++ b/src/api-server/Routes/zoneRoutes.ts @@ -0,0 +1,541 @@ +import * as express from "express"; +import { Zoneservice } from "../controller/lines/zoneService.ts"; +const router = express.Router(); +/** + * @swagger + * components: + * schemas: + * Zone: + * type: object + * required: + * - zoneName + * - zoneUUID + * - sceneID + * - createdBy + * - layer + * - viewPortCenter + * - viewPortposition + * properties: + * zoneName: + * type: string + * description: Name of the zone + * zoneUUID: + * type: string + * description: Unique identifier for the zone + * sceneID: + * type: string + * description: ID of the scene associated with the zone + * createdBy: + * type: string + * description: User ID who created the zone + * layer: + * type: integer + * description: Layer number in the scene + * zonePoints: + * type: array + * description: List of points defining the zone + * items: + * type: array + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * viewPortCenter: + * type: array + * description: Center position of the viewport + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * viewPortposition: + * type: array + * description: Position of the viewport + * items: + * type: object + * properties: + * x: + * type: number + * panelOrder: + * type: array + * description: Order of panels + * items: + * type: string + * enum: ["left", "right", "up", "down"] + * lockedPanel: + * type: array + * description: Locked panels in the zone + * items: + * type: string + * enum: ["left", "right", "up", "down"] + * isArchive: + * type: boolean + * description: Flag to mark if the zone is archived + * createdAt: + * type: string + * format: date-time + * description: Timestamp when the zone was created + * updatedAt: + * type: string + * format: date-time + * description: Timestamp when the zone was last updated + * example: + * zoneName: "Zone 2" + * zoneUUID: "0114-58-064-9" + * sceneID: "125789632548" + * createdBy: "012357894268" + * layer: 1 + * zonePoints: [[{"x":5,"y":5}], [{"x":5,"y":5}], [{"x":5,"y":5}]] + * viewPortCenter: [{"x":5, "y":5}] + * viewPortposition: [{"x":5}] + * panelOrder: ["left", "right"] + * lockedPanel: ["up"] + * isArchive: false + * createdAt: "2025-01-01T00:00:00Z" + * updatedAt: "2025-01-01T00:00:00Z" + */ + +/** + * @swagger + * tags: + * name: Zones + * description: API for managing zones + */ + +/** + * @swagger + * /zone/save: + * post: + * summary: Create or update a zone + * tags: [Zones] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - organization + * - zonesdata + * properties: + * organization: + * type: string + * description: Organization name + * example: "NEWORG" + * zonesdata: + * type: object + * required: + * - zonename + * - zoneId + * - sceneID + * - userid + * - layer + * - points + * - viewportPosition + * properties: + * zonename: + * type: string + * description: Name of the zone + * example: "Zone 2" + * zoneId: + * type: string + * description: Unique identifier for the zone + * example: "0114-58-064-9" + * sceneID: + * type: string + * description: ID of the scene associated with the zone + * example: "125789632548" + * userid: + * type: string + * description: User ID who created the zone + * example: "012357894268" + * layer: + * type: integer + * description: Layer number in the scene + * example: 1 + * points: + * type: array + * description: List of points defining the zone + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * example: [{"x":5,"y":5}, {"x":10,"y":10}] + * viewportPosition: + * type: array + * description: Position of the viewport + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * example: [{"x":5, "y":5}] + * viewPortCenter: + * type: array + * description: Center of the viewport + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * example: [{"x":10, "y":10}] + * responses: + * 200: + * description: Zone created or updated successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone created successfully" + * zoneData: + * type: object + * properties: + * zoneName: + * type: string + * points: + * type: array + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * viewPortposition: + * type: array + * items: + * type: object + * viewPortCenter: + * type: array + * items: + * type: object + * 404: + * description: Zone not updated + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone not updated" + * 500: + * description: Server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: "Internal server error" + */ +router.post("/zone/save", Zoneservice.addandUpdateZone); //Zone create and update for the points + +/** + * @swagger + * /zones/{sceneID}: + * get: + * summary: Get all zones for a scene + * tags: [Zones] + * parameters: + * - in: path + * name: sceneID + * required: true + * schema: + * type: string + * description: ID of the scene + * - in: query + * name: organization + * required: true + * schema: + * type: string + * description: Organization name + * responses: + * 200: + * description: List of zones retrieved successfully + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * zoneName: + * type: string + * description: Name of the zone + * sceneID: + * type: string + * description: Scene ID associated with the zone + * zoneUUID: + * type: string + * description: Unique identifier for the zone + * 404: + * description: No zones found for the given scene ID + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone not found for the UUID" + * 500: + * description: Server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: "Internal Server Error" + * examples: + * Successful Response: + * value: + * - zoneName: "Zone A" + * sceneID: "scene123" + * zoneUUID: "UUID-12345" + * - zoneName: "Zone B" + * sceneID: "scene123" + * zoneUUID: "UUID-67890" + * Not Found Response: + * value: + * message: "Zone not found for the UUID" + */ +router.get("/zones/:sceneID", Zoneservice.allZones); + +router.get("/pageZodeData", Zoneservice.vizAllDatas); + +/** + * @swagger + * /ZoneVisualization/{zoneId}: + * get: + * summary: Get Zone Panel Data + * tags: [Zones] + * description: Fetches zone panel details including widgets, panel order, locked panels, and points. + * parameters: + * - in: path + * name: zoneId + * required: true + * description: The unique identifier of the zone. + * schema: + * type: string + * - in: query + * name: organization + * required: true + * description: The organization name to filter data. + * schema: + * type: string + * responses: + * 200: + * description: Zone panel data retrieved successfully. + * content: + * application/json: + * schema: + * type: object + * properties: + * zoneName: + * type: string + * activeSides: + * type: array + * items: + * type: string + * panelOrder: + * type: array + * items: + * type: string + * lockedPanels: + * type: array + * items: + * type: string + * points: + * type: array + * items: + * type: object + * properties: + * x: + * type: number + * y: + * type: number + * widgets: + * type: array + * items: + * type: object + * properties: + * id: + * type: string + * type: + * type: string + * title: + * type: string + * panel: + * type: string + * data: + * type: array + * items: + * type: object + * example: + * zoneName: "Zone 2" + * activeSides: [] + * panelOrder: [] + * lockedPanels: [] + * points: + * - x: 5 + * y: 5 + * - x: 10 + * y: 10 + * widgets: [] + * 404: + * description: Zone not found + * content: + * application/json: + * example: + * message: "Zone not found for the UUID" + * 500: + * description: Internal Server Error + * content: + * application/json: + * example: + * error: "Internal Server Error" + */ +router.get("/ZoneVisualization/:zoneId", Zoneservice.singleZonePanelDatas); + +/** + * @swagger + * /A_zone/{zoneId}: + * get: + * summary: Get a specific zone's data + * tags: [Zones] + * parameters: + * - in: path + * name: zoneId + * required: true + * schema: + * type: string + * description: Unique identifier of the zone + * - in: query + * name: organization + * required: true + * schema: + * type: string + * description: Organization name + * responses: + * 200: + * description: Zone data retrieved successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * zoneUUID: + * type: string + * description: Unique identifier of the zone + * zoneName: + * type: string + * description: Name of the zone + * isArchive: + * type: boolean + * description: Indicates if the zone is archived + * 404: + * description: Zone not found + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone not found" + * 500: + * description: Server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: "Internal Server Error" + * examples: + * Successful Response: + * value: + * zoneUUID: "abc123" + * zoneName: "Zone A" + * isArchive: false + * otherProperties: {} + * Not Found Response: + * value: + * message: "Zone not found" + */ +router.get("/A_zone/:zoneId/:organization", Zoneservice.ZoneData); + +/** + * @swagger + * /zone/{zoneId}: + * patch: + * summary: Soft delete a zone + * tags: [Zones] + * parameters: + * - in: path + * name: zoneId + * required: true + * schema: + * type: string + * description: Unique identifier of the zone + * - in: query + * name: organization + * required: true + * schema: + * type: string + * description: Organization name + * responses: + * 200: + * description: Zone successfully deleted + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone deleted successfully" + * 404: + * description: Zone not found + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: "Zone not found for the UUID" + * 500: + * description: Server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: "Internal Server Error" + */ +router.patch("/zone/:zoneId", Zoneservice.deleteAZone); //delete Zone +// router.get("/zone/:sceneID", Zoneservice.allZones); +export default router; diff --git a/src/api-server/app.ts b/src/api-server/app.ts index bce0703..1a88661 100644 --- a/src/api-server/app.ts +++ b/src/api-server/app.ts @@ -1,34 +1,50 @@ -import express from 'express'; -import cors from 'cors'; -import connectDB from '../shared/connect/mongoose'; -import dotenv from 'dotenv'; -import cameraRoutes from './Routes/camera-Routes' -import environmentsRoutes from './Routes/environments-Routes' -import linesRoutes from './Routes/lines-Routes' -import flooritemRoutes from './Routes/flooritem-Routes' -import WallitemRoutes from './Routes/wallItems-Routes' -import userRoutes from './Routes/user-Routes' -import shareRoutes from './Routes/share-Routes' -import zoneRoutes from './Routes/zone-Routes' - +import express from "express"; +import cors from "cors"; +import connectDB from "../shared/connect/mongoose.ts"; +import dotenv from "dotenv"; +import cameraRoutes from "./Routes/camera-Routes.ts"; +import environmentsRoutes from "./Routes/environments-Routes.ts"; +import linesRoutes from "./Routes/lines-Routes.ts"; +import flooritemRoutes from "./Routes/flooritem-Routes.ts"; +import WallitemRoutes from "./Routes/wallItems-Routes.ts"; +import userRoutes from "./Routes/user-Routes.ts"; +import shareRoutes from "./Routes/share-Routes.ts"; +import zoneRoutes from "./Routes/zone-Routes.ts"; +import zoneRoutes2 from "./Routes/zoneRoutes.ts"; //update +import panelRouter from "./Routes/panelRoutes.ts"; +import widgetRouter from "./Routes/widgetRoute.ts"; +import assetpointRouter from "./Routes/assetpointRoutes.ts"; +import assetfloorRoutes from "./Routes/assetfloorRoutes.ts"; +import floadWidgetRoutes from "./Routes/floadWidgetRoute.ts"; +import templateRoutes from "./Routes/templateRoutes.ts"; +import widget3dRoutes from "./Routes/widget3dRoutes.ts"; const app = express(); app.use(cors()); app.use(express.json()); dotenv.config(); -app.get('/', (req, res) => { - res.send('Hello, I am Major-Dwinzo API!'); - }); +app.get("/", (req, res) => { + res.send("Hello, I am Major-Dwinzo API!"); +}); // connectDB(); -app.get('/health',(req,res)=>{ - res.status(200).json({ message: 'Server is running' }); -}) -app.use('/api/v1', cameraRoutes); -app.use('/api/v1', environmentsRoutes); -app.use('/api/v1', linesRoutes); -app.use('/api/v1', flooritemRoutes); -app.use('/api/v1', WallitemRoutes); -app.use('/api/v1', userRoutes); -app.use('/api/v1', shareRoutes); -app.use('/api/v2', zoneRoutes); +app.get("/health", (req, res) => { + res.status(200).json({ message: "Server is running" }); +}); +app.use("/api/v1", cameraRoutes); +app.use("/api/v1", environmentsRoutes); +app.use("/api/v1", linesRoutes); +app.use("/api/v1", flooritemRoutes); +app.use("/api/v1", WallitemRoutes); +app.use("/api/v1", userRoutes); +app.use("/api/v1", shareRoutes); +app.use("/api/v2", zoneRoutes); +//update +app.use("/api/v2", zoneRoutes2); //updates +app.use("/api/v2", panelRouter); +app.use("/api/v2", widgetRouter); +app.use("/api/v2", assetpointRouter); +app.use("/api/v2", assetfloorRoutes); +app.use("/api/v2", floadWidgetRoutes); +app.use("/api/v2", templateRoutes); +app.use("/api/v2", widget3dRoutes); export default app; diff --git a/src/api-server/controller/assets/flooritem-Controller.ts b/src/api-server/controller/assets/flooritem-Services.ts similarity index 96% rename from src/api-server/controller/assets/flooritem-Controller.ts rename to src/api-server/controller/assets/flooritem-Services.ts index 893af0b..bfd0f4a 100644 --- a/src/api-server/controller/assets/flooritem-Controller.ts +++ b/src/api-server/controller/assets/flooritem-Services.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import floorItemsModel from "../../../shared/model/assets/flooritems-Model"; +import floorItemsModel from "../../../shared/model/assets/flooritems-Model.ts"; export class floorItems { diff --git a/src/api-server/controller/assets/pointService.ts b/src/api-server/controller/assets/pointService.ts new file mode 100644 index 0000000..b6e64e9 --- /dev/null +++ b/src/api-server/controller/assets/pointService.ts @@ -0,0 +1,180 @@ +import { Request, Response } from "express"; +import pointModel from "../../../shared/model/builder/assets/assetPoint-Model.ts"; + +export class pointService { + static async addPoints(req: Request, res: Response): Promise { + const { type, modelfileID, organization } = req.body; + + if (!["Conveyor", "Vehicle"].includes(type)) { + return res.status(400).json({ message: "Invalid type requested" }); + } + + try { + if (type === "Conveyor") { + const pointsData = await pointModel(organization).findOne({ + modelfileID: modelfileID, + type: type, + }); + if (pointsData) return res.send("Data already exists"); + const createData = await pointModel(organization).create({ + type: "Conveyor", + modelfileID: "672a090f80d91ac979f4d0bd", + points: [ + { + uuid: "point1UUID", + position: [0, 0.85, 2.2], + rotation: [0, 0, 0], + actions: [ + { + uuid: "randomUUID", + name: "Action 1", + type: "Inherit", + material: "Inherit", + delay: "Inherit", + spawnInterval: "Inherit", + isUsed: false, + }, + ], + triggers: [ + { + uuid: "randomUUID", + name: "trigger 1", + type: "Inherit", + bufferTime: 0, + // delay: "Inherit", + // spawnInterval: "Inherit", + isUsed: false, + }, + ], + // connections: { + // source: { pathUUID: "modelUUID", pointUUID: "point1UUID" }, + // targets: [], + // }, + }, + { + uuid: "point2UUID", + position: [0, 0.85, 0], + rotation: [0, 0, 0], + actions: [ + { + uuid: "randomUUID", + name: "Action 1", + type: "Inherit", + material: "Inherit", + delay: "Inherit", + spawnInterval: "Inherit", + isUsed: false, + }, + ], + triggers: [ + { + uuid: "randomUUID", + name: "trigger 1", + type: "Inherit", + bufferTime: 0, + // delay: "Inherit", + // spawnInterval: "Inherit", + isUsed: false, + }, + ], + // connections: { + // source: { pathUUID: "modelUUID", pointUUID: "point1UUID" }, + // targets: [], + // }, + }, + { + uuid: "point3UUID", + position: [0, 0.85, -2.2], + rotation: [0, 0, 0], + actions: [ + { + uuid: "randomUUID", + name: "Action 1", + type: "Inherit", + material: "Inherit", + delay: "Inherit", + spawnInterval: "Inherit", + isUsed: false, + }, + ], + triggers: [ + { + uuid: "randomUUID", + name: "trigger 1", + type: "Inherit", + bufferTime: 0, + // delay: "Inherit", + // spawnInterval: "Inherit", + isUsed: false, + }, + ], + // connections: { + // source: { pathUUID: "modelUUID", pointUUID: "point1UUID" }, + // targets: [], + // }, + }, + ], + }); + } + // else if (type === "Vehicle") { + // // responseData = { + // // type: "Vehicle", + // // points: { + // // uuid: "point1UUID", + // // position: [10, 20, 30], + // // rotation: [0, 0, 0], + // // actions: [ + // // { + // // uuid: "randomUUID", + // // name: "Action 1", + // // type: "Inherit", + // // material: "Inherit", + // // delay: "Inherit", + // // spawnInterval: "Inherit", + // // isUsed: false, + // // }, + // // ], + // // triggers: [], + // // connections: { + // // source: { pathUUID: "modelUUID", pointUUID: "point1UUID" }, + // // targets: [], + // // }, + // // }, + // // speed: 1, + // // }; + // } + + res.status(200).json({ message: "point created successfully" }); + } catch (error) { + res.status(500).json({ message: "Server error", error }); + } + } + + static async gettypePoints(req: Request, res: Response): Promise { + const { modelfileID, organization } = req.params; + try { + const getData = await pointModel(organization) + .findOne({ + modelfileID: modelfileID, + }) + .select("-_id -__v -createdAt -updatedAt"); + if (!getData) { + return res.json({ message: "Data not found" }); + } + + const formattedData = { + modelfileID: getData?.modelfileID, + type: getData?.type, + points: Array.isArray(getData?.points) + ? getData.points.map((point: any) => ({ + position: point.position, + rotation: point.rotation, + })) + : [], + }; + return res.status(200).json(formattedData); + } catch (error) { + res.status(500).json({ message: "Server error", error }); + } + } +} diff --git a/src/api-server/controller/assets/wallitem-Controller.ts b/src/api-server/controller/assets/wallitem-Services.ts similarity index 96% rename from src/api-server/controller/assets/wallitem-Controller.ts rename to src/api-server/controller/assets/wallitem-Services.ts index ff9ad78..5be7eee 100644 --- a/src/api-server/controller/assets/wallitem-Controller.ts +++ b/src/api-server/controller/assets/wallitem-Services.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import wallItenmModel from "../../../shared/model/assets/wallitems-Model"; +import wallItenmModel from "../../../shared/model/assets/wallitems-Model.ts"; export class wallItems { diff --git a/src/api-server/controller/camera/camera-Controlle.ts b/src/api-server/controller/camera/camera-Services.ts similarity index 94% rename from src/api-server/controller/camera/camera-Controlle.ts rename to src/api-server/controller/camera/camera-Services.ts index e53c4e3..d9a10f7 100644 --- a/src/api-server/controller/camera/camera-Controlle.ts +++ b/src/api-server/controller/camera/camera-Services.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express"; -import cameraModel from "../../../shared/model/camera/camera-Model"; -import userModel from "../../../shared/model/user-Model"; +import cameraModel from "../../../shared/model/camera/camera-Model.ts"; +import userModel from "../../../shared/model/user-Model.ts"; export class camera { static async createCamera(req: Request, res: Response) { @@ -54,7 +54,7 @@ export class camera { const findactiveUsers = await userModel(organization).find({activeStatus:"online"}) - const cameraDataPromises = findactiveUsers.map(async (activeUser) => { + const cameraDataPromises = findactiveUsers.map(async (activeUser:any) => { const cameraData = await cameraModel(organization) .findOne({ userId: activeUser._id }) .select("position target rotation -_id"); diff --git a/src/api-server/controller/environments/environments-Services.ts b/src/api-server/controller/environments/environments-Services.ts new file mode 100644 index 0000000..9981319 --- /dev/null +++ b/src/api-server/controller/environments/environments-Services.ts @@ -0,0 +1,72 @@ +import { Request, Response } from "express"; +import environmentModel from "../../../shared/model/environments/environments-Model.ts"; + +export class environment { + static async setEnvironment(req: Request, res: Response) { + try { + const { + userId, + roofVisibility, + wallVisibility, + shadowVisibility, + organization, + renderDistance, + limitDistance, + } = req.body; + + const findvalue = await environmentModel(organization).findOne({ + userId: userId, + }); + + if (findvalue) { + const updatevalue = await environmentModel( + organization + ).findOneAndUpdate( + { userId: userId }, + { + roofVisibility: roofVisibility, + renderDistance: renderDistance, + wallVisibility: wallVisibility, + shadowVisibility: shadowVisibility, + limitDistance: limitDistance, + }, + { new: true } + ); + res.status(201).json(updatevalue); + } else { + const newValue = await environmentModel(organization).create({ + userId, + roofVisibility, + wallVisibility, + renderDistance, + shadowVisibility, + limitDistance, + }); + + res.status(201).json(newValue); + } + + // Send response with the created document + } catch (error) { + console.error("Error creating environments:", error); + res.status(500).json({ message: "Failed to create environments" }); + } + } + static async getEnvironment(req: Request, res: Response) { + try { + const { userId, organization } = req.params; + + const findValue = await environmentModel(organization).findOne({ + userId: userId, + }); + if (!findValue) { + res.status(200).json("user not found"); + } else { + res.status(201).json(findValue); + } + } catch (error) { + console.error("Error get environments:", error); + res.status(500).json({ error: "Failed to get environments" }); + } + } +} diff --git a/src/api-server/controller/environments/environments-controller.ts b/src/api-server/controller/environments/environments-controller.ts deleted file mode 100644 index 45a81ef..0000000 --- a/src/api-server/controller/environments/environments-controller.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Request, Response } from "express"; -import environmentModel from "../../../shared/model/environments/environments-Model"; - -export class environment { - static async setEnvironment(req: Request, res: Response) { - try { - const { userId,roofVisibility,wallVisibility,shadowVisibility, organization } = req.body - - - const findvalue = await environmentModel(organization).findOne({ userId: userId }) - - if (findvalue) { - - const updatevalue = await environmentModel(organization).findOneAndUpdate( - { userId: userId }, { roofVisibility:roofVisibility,wallVisibility:wallVisibility,shadowVisibility:shadowVisibility}, { new: true }); - res.status(201).json(updatevalue); - - - } else { - const newValue = await environmentModel(organization).create({ userId, roofVisibility, wallVisibility, }); - - - res.status(201).json(newValue); - - } - - // Send response with the created document - } catch (error) { - console.error('Error creating environments:', error); - res.status(500).json({message:"Failed to create environments"}); - } - } - static async getEnvironment(req: Request, res: Response) { - try { - const { userId, organization } = req.params; - - - const findValue = await environmentModel(organization).findOne({ userId: userId }) - if (!findValue) { - res.status(200).json("user not found"); - } else { - - res.status(201).json(findValue); - } - } catch (error) { - console.error('Error get environments:', error); - res.status(500).json({ error: "Failed to get environments" }); - } - } -} diff --git a/src/api-server/controller/lines/line-Controller.ts b/src/api-server/controller/lines/line-Services.ts similarity index 95% rename from src/api-server/controller/lines/line-Controller.ts rename to src/api-server/controller/lines/line-Services.ts index aee5d59..f9fc7bb 100644 --- a/src/api-server/controller/lines/line-Controller.ts +++ b/src/api-server/controller/lines/line-Services.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import lineModel from "../../../shared/model/lines/lines-Model"; +import lineModel from "../../../shared/model/lines/lines-Model.ts"; export class lines { static async setLines(req: Request, res: Response) { diff --git a/src/api-server/controller/lines/zone-Controller.ts b/src/api-server/controller/lines/zone-Services.ts similarity index 93% rename from src/api-server/controller/lines/zone-Controller.ts rename to src/api-server/controller/lines/zone-Services.ts index e3800ed..6fe520f 100644 --- a/src/api-server/controller/lines/zone-Controller.ts +++ b/src/api-server/controller/lines/zone-Services.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import zoneModel from "../../../shared/model/lines/zone-Model"; +import zoneModel from "../../../shared/model/lines/zone-Model.ts"; export class zone { static async setZone(req: Request, res: Response) { try { @@ -75,9 +75,9 @@ export class zone { static async ZoneData(req: Request, res: Response): Promise { try { const organization = req.params.organization; - const zoneID = req.params.zoneID; + const zoneId = req.params.zoneId; const findZone = await zoneModel(organization) - .findOne({ zoneId: zoneID }) + .findOne({ zoneId: zoneId }) // .select("zoneName"); console.log("findZone: ", findZone); if (findZone) return res.status(200).json(findZone); diff --git a/src/api-server/controller/lines/zoneService.ts b/src/api-server/controller/lines/zoneService.ts new file mode 100644 index 0000000..973be85 --- /dev/null +++ b/src/api-server/controller/lines/zoneService.ts @@ -0,0 +1,264 @@ +import { Request, Response } from "express"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; +export class Zoneservice { + static async addandUpdateZone(req: Request, res: Response): Promise { + console.log("req.body: ", req.body); + try { + const organization = req.body.organization; + const zoneDatas = req.body.zonesdata; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneDatas.zoneId, + isArchive: false, + }); + if (!existingZone) { + const newZone = await zoneSchema(organization).create({ + zoneName: zoneDatas.zonename, + zoneId: zoneDatas.zoneId, + zonePoints: zoneDatas.points, + viewPortposition: zoneDatas.viewportPosition, + viewPortCenter: zoneDatas.viewPortCenter, + createdBy: zoneDatas.userid, + layer: zoneDatas.layer, + sceneID: zoneDatas.sceneID, + }); + if (newZone) + return res.status(200).json({ + message: "Zone created successfully", + zoneData: { + zoneName: newZone.zoneName, + points: newZone.zonePoints, + viewPortposition: zoneDatas.viewPortposition, + viewPortCenter: zoneDatas.viewPortCenter, + }, + }); + } else { + const replaceZone = await zoneSchema(organization).findOneAndUpdate( + { zoneId: zoneDatas.zoneId, isArchive: false }, + { + zonePoints: zoneDatas.points, + viewPortposition: zoneDatas.viewPortposition, + viewPortCenter: zoneDatas.viewPortCenter, + }, + { new: true } + ); + console.log("replaceZone: ", replaceZone); + if (!replaceZone) + return res.status(404).json({ message: "Zone not updated" }); + else + return res.status(200).json({ + message: "updated successfully", + zoneData: { + zoneName: replaceZone.zoneName, + points: replaceZone.zonePoints, + viewPortposition: replaceZone.viewPortposition, + viewPortCenter: replaceZone.viewPortCenter, + }, + }); + } + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + static async deleteAZone(req: Request, res: Response): Promise { + const organization = req.query.organization; + const zoneId = req.params.zoneId; + try { + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) { + return res.status(404).json({ message: "Zone not found for the UUID" }); + } else { + const deleteZone = await zoneSchema(organization).findOneAndUpdate( + { zoneId: zoneId, isArchive: false }, + { + isArchive: true, + }, + { new: true } + ); + + if (deleteZone) { + return res.status(200).json({ message: "Zone deleted successfully" }); + } + } + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + //single zode panel and widget data + static async singleZonePanelDatas(req: Request, res: Response): Promise { + const organization = req.query.organization; + const zoneId = req.params.zoneId; + + try { + const existingZone = await zoneSchema(organization) + .findOne({ + zoneId: zoneId, + isArchive: false, + }) + .select( + "panelOrder zoneName zonePoints lockedPanel zoneId viewPortCenter viewPortposition" + ); + if (!existingZone) { + return res.send({ message: "Zone not found for the UUID" }); + } else { + const panelData = await panelSchema(organization).find({ + zoneId: zoneId, + isArchive: false, + }); + const zoneName = existingZone.zoneName as string; + + const widgets = await Promise.all( + panelData.map(async (data) => { + const widgetDataArray = await widgetSchema(organization).find({ + panelID: data._id, + isArchive: false, + }); + + return widgetDataArray.map((widgetData) => ({ + id: widgetData.widgetID, + type: widgetData.elementType, + title: widgetData.widgetName, + panel: widgetData.widgetside, + data: widgetData.Data || [], + })); + }) + ); + + const flattenedWidgets = widgets.flat(); + + const objectData = { + zoneName, + viewPortposition: existingZone.viewPortposition, + zoneId: existingZone.zoneId, + viewPortCenter: existingZone.viewPortCenter, + activeSides: existingZone.panelOrder || [], + panelOrder: existingZone.panelOrder || [], + lockedPanels: existingZone.lockedPanel || [], + points: existingZone.zonePoints || [], + widgets: flattenedWidgets, + }; + + return res.status(200).json(objectData); + } + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + //page full zone Datas with panel and widget + static async vizAllDatas(req: Request, res: Response): Promise { + const organization = req.query.organization; + try { + const existingZones = await zoneSchema(organization) + .find({ + isArchive: false, + }) + .select( + "panelOrder zoneName zonePoints lockedPanel zoneId viewPortCenter viewPortposition" + ); + if (!existingZones) { + return res.send({ message: "Zone not found for the UUID" }); + } else { + const response = await Promise.all( + existingZones.map(async (zone) => { + // Fetch all panels associated with the current zone + const panelData = await panelSchema(organization).find({ + zoneId: zone._id, + isArchive: false, + }); + + // Fetch widgets for each panel + const widgets = await Promise.all( + panelData.map(async (panel) => { + const widgetDataArray = await widgetSchema(organization).find({ + panelID: panel._id, + isArchive: false, + }); + + return widgetDataArray.map((widget) => ({ + id: widget.widgetID, + type: widget.elementType, + title: widget.widgetName, + panel: widget.widgetside, + data: widget.Data || [], + })); + }) + ); + + return { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + viewPortposition: zone.viewPortposition, + viewPortCenter: zone.viewPortCenter, + activeSides: zone.panelOrder || [], + panelOrder: zone.panelOrder || [], + lockedPanels: zone.lockedPanel || [], + points: zone.zonePoints || [], + widgets: widgets.flat(), + }; + }) + ); + + return res.status(200).json(response); + } + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + //only for the name and zoneID + static async allZones(req: Request, res: Response): Promise { + const organization = req.query.organization; + const sceneID = req.params.sceneID || "scene123"; + try { + const Allzones = await zoneSchema(organization) + .find({ sceneID: sceneID, isArchive: false }) + .select("zoneName zoneId"); + + if (!Allzones || Allzones.length === 0) { + return res.status(404).json({ message: "Zone not found for the UUID" }); + } + return res.status(200).json(Allzones); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + static async ZoneData(req: Request, res: Response): Promise { + try { + console.log("req.params: ", req.params); + const organization = req.params.organization; + const zoneId = req.params.zoneId; + const findZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + }); + // .select("zoneName"); + if (findZone) return res.status(200).json(findZone); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + // static async zoneIdgenerate(req: Request, res: Response): Promise { + // const organization = req.query.organization; + // const sceneID = req.params.sceneID; + // try { + // const Allzones = await zoneSchema(organization) + // .find({ sceneID: sceneID, isArchive: false }) + // .select("zoneName sceneID zoneId"); + + // if (!Allzones || Allzones.length === 0) { + // return res.send({ message: "Zone not found for the UUID" }); + // } + // return res.send(Allzones); + // } catch (error: any) { + // return res.status(500).send(error.message); + // } + // } +} diff --git a/src/api-server/controller/share/share-Controller.ts b/src/api-server/controller/share/share-Controller.ts index d00d05b..4865ae5 100644 --- a/src/api-server/controller/share/share-Controller.ts +++ b/src/api-server/controller/share/share-Controller.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import userModel from "../../../shared/model/user-Model"; +import userModel from "../../../shared/model/user-Model.ts"; export class share { diff --git a/src/api-server/controller/simulation/assetsFloorservice.ts b/src/api-server/controller/simulation/assetsFloorservice.ts new file mode 100644 index 0000000..cc05e19 --- /dev/null +++ b/src/api-server/controller/simulation/assetsFloorservice.ts @@ -0,0 +1,191 @@ +import { Request, Response } from "express"; +// import assetModel from "../../../shared/model/assets/flooritems-Model.ts"; +import assetModel from "../../../shared/model/builder/assets/asset-Model.ts"; +import actionModel from "../../../shared/model/simulation/actionmodel.ts"; +import triggerModel from "../../../shared/model/simulation/triggersmodel.ts"; + +export class assetsFloorservice { + static async setFloorassets(req: Request, res: Response): Promise { + try { + console.log("req.body: ", req.body); + const { + modeluuid, + modelname, + assetPosition, + modelfileID, + assetRotation, + isLocked, + isVisible, + organization, + eventData, // Optional + } = req.body; + + const findvalue = await assetModel(organization).findOne({ + modeluuid, + modelname, + }); + + if (findvalue) { + const updatevalue = await assetModel(organization).findOneAndUpdate( + { modeluuid, modelname }, + { + assetPosition, + assetRotation, + isVisible, + isLocked, + }, + { new: true } + ); + return res.status(201).json(updatevalue); + } else { + let assetData: any = { + modeluuid, + modelname, + assetPosition, + modelfileID, + assetRotation, + isLocked, + isVisible, + }; + + if (eventData) { + let pointRefs: any[] = []; + + if (Array.isArray(eventData.points)) { + for (const point of eventData.points) { + let actionRefs: any[] = []; + let triggerRefs: any[] = []; + + if (Array.isArray(point.actions)) { + for (const action of point.actions) { + const actionDoc = await actionModel(organization).create({ + pointsUUID: point.uuid, + isArchive: false, + uuid: action.uuid, + name: action.name, + type: action.type, + material: action.material, + delay: action.delay, + spawn_Interval: action.spawn_Interval, + }); + await actionDoc.save(); + actionRefs.push(actionDoc._id); + } + } + + if (Array.isArray(point.triggers)) { + for (const trigger of point.triggers) { + const triggerDoc = await triggerModel(organization).create({ + pointsUUID: point.uuid, + isArchive: false, + uuid: trigger.uuid, + name: trigger.name, + type: trigger.type, + bufferTime: trigger.bufferTime, + }); + await triggerDoc.save(); + triggerRefs.push(triggerDoc._id); + } + } + + pointRefs.push({ + uuid: point.uuid, + position: point.position || [], + rotation: point.rotation || [], + actions: actionRefs, + triggers: triggerRefs, + }); + } + } + + assetData.speed = eventData.speed; + assetData.type = eventData.type; + assetData.points = pointRefs; + } + + const assetDoc = await assetModel(organization).create(assetData); + await assetDoc.save(); + + return res.status(201).json({ + message: "Model stored successfully", + modelId: assetDoc._id, + }); + } + } catch (error) { + console.error("Error creating flooritems:", error); + res.status(500).json({ message: "Failed to create flooritems" }); + } + } + static async getFloorItems(req: Request, res: Response): Promise { + try { + const { organization } = req.params; + const findValues = await assetModel(organization) + .find() + .select("-_id") + .populate({ + path: "points", + select: "-_id", + }) + .populate({ + path: "points.actions", + model: actionModel(organization), + select: "-__v -_id -isArchive -pointsUUID -createdAt -updatedAt", + }) + .populate({ + path: "points.triggers", + model: triggerModel(organization), + select: "-__v -_id -isArchive -pointsUUID -createdAt -updatedAt", + }); + if (!findValues) { + res.status(200).json("floorItems not found"); + } else { + return res.status(200).json( + findValues.map((item) => { + let responseItem: any = { + modeluuid: item.modeluuid, + modelname: item.modelname, + assetPosition: item.assetPosition, + modelfileID: item.modelfileID, + assetRotation: item.assetRotation, + isLocked: item.isLocked, + isVisible: item.isVisible, + }; + + if (item.points.length > 1) { + responseItem.eventData = { + speed: item.speed, + points: item.points, + type: item.type, + }; + } + + return responseItem; + }) + ); + } + } catch (error) { + console.error("Error get flooritems:", error); + res.status(500).json({ error: "Failed to get flooritems" }); + } + } + static async deleteFloorItems(req: Request, res: Response) { + try { + const { modeluuid, modelname, organization } = req.body; + + const findValue = await assetModel(organization).findOneAndDelete({ + modeluuid: modeluuid, + modelname: modelname, + }); + if (!findValue) { + res.status(200).json("user not found"); + } else { + res.status(201).json(findValue); + } + } catch (error) { + console.error("Error get flooritems:", error); + res.status(500).json({ error: "Failed to get flooritems" }); + } + } + + static async updateActionsDatas(req: Request, res: Response) {} +} diff --git a/src/api-server/controller/user-Controller.ts b/src/api-server/controller/user-Controller.ts index 8d1a810..46fc579 100644 --- a/src/api-server/controller/user-Controller.ts +++ b/src/api-server/controller/user-Controller.ts @@ -1,8 +1,8 @@ import { Request, Response } from "express"; import { Server } from 'http'; -import userModel from "../../shared/model/user-Model"; +import userModel from "../../shared/model/user-Model.ts"; import { isSharedArrayBuffer } from "util/types"; -const {hashGenerate,hashValidator} = require("../../shared/security/Hasing.ts") +import {hashGenerate,hashValidator} from "../../shared/security/Hasing.ts" // import {hashGenerate} from '../security/Hasing' let serverAlive = true; diff --git a/src/api-server/controller/visualization/3dWidgetService.ts b/src/api-server/controller/visualization/3dWidgetService.ts new file mode 100644 index 0000000..c00687a --- /dev/null +++ b/src/api-server/controller/visualization/3dWidgetService.ts @@ -0,0 +1,106 @@ +import { Request, Response } from "express"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import widget3dModel from "../../../shared/model/vizualization/3dwidget.ts"; +export class widget3dService { + static async add3Dwidget(req: Request, res: Response): Promise { + try { + const { organization, widget, zoneId } = req.body; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return res.status(404).json({ message: "Zone not found" }); + const existing3Dwidget = await widget3dModel(organization).findOne({ + widgetID: widget.id, + isArchive: false, + }); + if (existing3Dwidget) { + const update3dwidget = await widget3dModel( + organization + ).findOneAndUpdate( + { + widgetID: widget.id, + zoneId: zoneId, + isArchive: false, + }, + { position: widget.position }, + { upsert: true, new: true } + ); + if (update3dwidget) + return res + .status(200) + .json({ message: "widget update successfully" }); + else return res.send("Widget not updated"); + } + const newWidget3d = await widget3dModel(organization).create({ + widgetName: widget.type, + widgetID: widget.id, + position: widget.position, + zoneId, + }); + if (newWidget3d) + return res.status(201).json({ message: "Widget created successfully" }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async get3Dwiget(req: Request, res: Response): Promise { + try { + const { organization, zoneId } = req.params; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) return res.send("Zone not found"); + const widgetData = await widget3dModel(organization).find({ + zoneId: zoneId, + isArchive: false, + }); + if (!widgetData || widgetData.length === 0) { + return res.json([]); + } + + const zonebasedWidget = widgetData.map((widget) => ({ + Data: { + measurements: widget.Data?.measurements || {}, + duration: widget.Data?.duration || "1h", + }, + type: widget.widgetName, + id: widget.widgetID, + position: widget.position, + })); + return res.status(200).json(zonebasedWidget); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + // static async update3Dposition(req: Request, res: Response): Promise { + // try { + // const { organization, id, position, zoneId } = req.body; + // const existing3Dwidget = await widget3dModel(organization).findOne({ + // widgetID: id, + // isArchive: false, + // }); + // if (existing3Dwidget) { + // const update3dwidget = await widget3dModel( + // organization + // ).findOneAndUpdate( + // { + // widgetID: id, + // zoneId: zoneId, + // isArchive: false, + // }, + // { position: position }, + // { upsert: true, new: true } + // ); + // if (update3dwidget) + // return res.status(200).send("widget update successfully"); + // } else { + // return res.status(404).send("widget not found"); + // } + // } catch (error: any) { + // return res.status(500).send(error.message); + // } + // } +} diff --git a/src/api-server/controller/visualization/floatWidgetService.ts b/src/api-server/controller/visualization/floatWidgetService.ts new file mode 100644 index 0000000..325e2ad --- /dev/null +++ b/src/api-server/controller/visualization/floatWidgetService.ts @@ -0,0 +1,202 @@ +import { Request, Response } from "express"; +import floatWidgetModel from "../../../shared/model/vizualization/floatWidget.ts"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +export class floatWidgetService { + static async addfloatWidget(req: Request, res: Response): Promise { + try { + const { organization, widget, zoneId } = req.body; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return res + .status(404) + .json({ message: "Zone not found for the zoneId" }); + const existingFloatWidget = await floatWidgetModel(organization).findOne({ + floatWidgetID: widget.id, + isArchive: false, + zoneId: zoneId, + }); + if (existingFloatWidget) { + const updateFloatWidget = await floatWidgetModel( + organization + ).findOneAndUpdate( + { + floatWidgetID: widget.id, + isArchive: false, + }, + { + $set: { + Data: { + measurements: widget?.Data.measurements, + duration: widget?.Data.duration, + }, + header: widget?.header, + position: widget?.position, + }, + }, + { + upsert: true, + new: true, + } + ); + + return res.status(200).json({ message: "Widget updated successfully" }); + } + + const newFloadWidget = await floatWidgetModel(organization).create({ + className: widget.className, + header: widget.header, + floatWidgetID: widget.id, + position: widget.position, + per: widget.per, + value: widget.value, + zoneId: zoneId, + }); + if (newFloadWidget) { + return res + .status(201) + .json({ message: "FloatWidget created successfully" }); + } + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async getfloatWidget(req: Request, res: Response): Promise { + const { organization, zoneId } = req.params; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return res.status(404).json({ message: "Zone not found" }); + const widgetData = await floatWidgetModel(organization) + .find({ + zoneId: zoneId, + isArchive: false, + }) + .select("-_id -zoneId -createdAt -updatedAt -__v"); + if (!widgetData || widgetData.length === 0) { + return res.send([]); + } + + const formattedWidgets = widgetData.map((widget) => ({ + Data: { + measurements: widget.Data?.measurements || {}, + duration: widget.Data?.duration || "1h", + }, + className: widget.className, + header: widget.header, + id: widget.floatWidgetID, + position: widget.position, + per: widget.per, + value: widget.value, + })); + return res.status(200).json(formattedWidgets); + } + + static async deletefloatWidget(req: Request, res: Response): Promise { + try { + const { floatWidgetID, organization } = req.body; + const findfloatWidget = await floatWidgetModel(organization).findOne({ + floatWidgetID: floatWidgetID, + isArchive: false, + }); + if (!findfloatWidget) + return res.status(409).json({ message: "Widget not found" }); + const widgetData = await floatWidgetModel(organization).updateOne( + { _id: findfloatWidget._id, isArchive: false }, + { $set: { isArchive: true } } + ); + return res + .status(200) + .json({ message: "FloatingWidget deleted successfully" }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async getsinglefloatWidget(req: Request, res: Response): Promise { + try { + const { organization, floatWidgetID } = req.params; + const widgetData = await floatWidgetModel(organization) + .findOne({ + floatWidgetID: floatWidgetID, + isArchive: false, + }) + .select("-_id -zoneId -createdAt -updatedAt -__v"); + if (!widgetData || widgetData.length === 0) { + return res.send([]); + } + const Datastructure = { + measurements: widgetData?.Data.measurements || {}, + duration: widgetData?.Data.duration || "1h", + }; + const header = widgetData?.header; + return res.status(200).json({ Data: Datastructure, header }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + // static async updatewidget(req: Request, res: Response): Promise { + // try { + // const { organization, widgetID, values } = req.body; + // const findwidget = await widgetSchema(organization).findOne({ + // widgetID: widgetID, + // isArchive: false, + // }); + // if (!findwidget) + // return res.status(404).send({ message: "Data not found" }); + // const updateData = { + // widgetName: values.widgetName, + // widgetSide: values.widgetSide, // Fixed typo from widgetside to widgetSide + // elementType: values.type, + // Data: { + // measurement: values.Data.measurement, + // duration: values.Data.duration, + // }, + // elementColor: values.color, + // fontFamily: values.fontFamily, + // fontStyle: values.fontStyle, + // fontWeight: values.fontWeight, + // isArchive: false, + // }; + + // const changedWidget = await widgetSchema(organization).findOneAndUpdate( + // { widgetID: widgetID, isArchive: false }, + // updateData, + // { + // new: true, + // upsert: true, + // setDefaultsOnInsert: true, + // } + // ); + + // return res.status(200).json({ + // message: "Widget updated successfully", + // }); + // } catch (error: any) { + // return res.status(500).send(error.message); + // } + // } + + // static async getDatafromWidget(req: Request, res: Response): Promise { + // const { organization, widgetID } = req.params; + // try { + // const existingWidget = await widgetSchema(organization) + // .findOne({ + // widgetID: widgetID, + // isArchive: false, + // }) + // .select("Data -_id"); + // const Datastructure = { + // measurements: existingWidget.Data.measurements || {}, + // duration: existingWidget.Data.duration || "1h", + // }; + + // if (existingWidget) return res.status(200).json({ Data: Datastructure }); + // } catch (error: any) { + // return res.status(500).send(error.message); + // } + // } +} diff --git a/src/api-server/controller/visualization/panelService.ts b/src/api-server/controller/visualization/panelService.ts new file mode 100644 index 0000000..e95cedd --- /dev/null +++ b/src/api-server/controller/visualization/panelService.ts @@ -0,0 +1,108 @@ +import { Request, Response } from "express"; +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; + +export class panelService { + static async AddPanel(req: Request, res: Response): Promise { + try { + const organization = req.body.organization; + const zoneId = req.body.zoneId; + const panelName = req.body.panelName; + const panelOrder = req.body.panelOrder; + const findZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + + if (!findZone) { + return res.status(404).json({ message: "Zone not found" }); + } + const updatezone = await zoneSchema(organization).findOneAndUpdate( + { zoneId: zoneId, isArchive: false }, + { panelOrder: panelOrder }, + { new: true } + ); + const existingPanels = await panelSchema(organization).find({ + zoneId: zoneId, + isArchive: false, + }); + + const existingPanelNames = existingPanels.map( + (panel: any) => panel.panelName + ); + + const missingPanels = panelOrder.filter( + (panelName: string) => !existingPanelNames.includes(panelName) + ); + + const createdPanels = []; + for (const panelName of missingPanels) { + const newPanel = await panelSchema(organization).create({ + zoneId: zoneId, + panelName: panelName, + widgets: [], + isArchive: false, + }); + createdPanels.push(newPanel); + } + + if (createdPanels.length === 0) { + return res.status(200).json({ + message: "No new panels were created. All panels already exist.", + }); + } + // const IDdata = createdPanels.map((ID: any) => { + // return ID._id; + // }); + createdPanels; + return res.status(201).json({ + message: "Panels created successfully", + panelID: createdPanels, + }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async deletePanel(req: Request, res: Response): Promise { + try { + const { organization, panelName, zoneId } = req.body; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return res.status(404).json({ message: "Zone not found" }); + const existingPanel = await panelSchema(organization).findOne({ + zoneId: zoneId, + panelName: panelName, + isArchive: false, + }); + if (!existingPanel) + return res.status(409).json({ message: "Panel Already Deleted" }); + const updatePanel = await panelSchema(organization).updateOne( + { _id: existingPanel._id, isArchive: false }, + { $set: { isArchive: true } } + ); + const existingWidgets = await widgetSchema(organization).find({ + panelID: existingPanel._id, + isArchive: false, + }); + + for (const widgetData of existingWidgets) { + widgetData.isArchive = true; + await widgetData.save(); + } + + if (existingZone.panelOrder.includes(existingPanel.panelName)) { + const index1 = existingZone.panelOrder.indexOf(existingPanel.panelName); + existingZone.panelOrder.splice(index1, 1); + } + await existingZone.save(); + + return res.status(200).json({ message: "Panel deleted successfully" }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } +} diff --git a/src/api-server/controller/visualization/templateService.ts b/src/api-server/controller/visualization/templateService.ts new file mode 100644 index 0000000..44e9843 --- /dev/null +++ b/src/api-server/controller/visualization/templateService.ts @@ -0,0 +1,203 @@ +import { Request, Response } from "express"; +import templateModel from "../../../shared/model/vizualization/templatemodel.ts"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; +import floatWidgetModel from "../../../shared/model/vizualization/floatWidget.ts"; + +export class templateService { + static async AddTemplate(req: Request, res: Response): Promise { + try { + const { + organization, + template, + // id, + // name, + // panelOrder, + // widgets, + // snapshot, + // floatWidgets, + } = req.body; + // console.log("req.body: ", req.body); + const existingTemplate = await templateModel(organization).findOne({ + templateID: template.id, + isArchive: false, + }); + if (existingTemplate) + return res.json({ message: "TemplateID alreay exists" }); + const newTemplate = await templateModel(organization).create({ + templateID: template.id, + templateName: template.name, + panelOrder: template.panelOrder, + widgets: template.widgets, + snapshot: template.snapshot, + floatWidgets: template.floatingWidget, + Widgets3D: template.Widgets3D, + }); + if (newTemplate) + return res.status(200).json({ message: "Template saved successfully" }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async GetAllTemplates(req: Request, res: Response): Promise { + try { + const { organization } = req.params; + const templateDatas = await templateModel(organization) + .find({ + isArchive: false, + }) + .select("-_id -__v -isArchive -createdAt -updatedAt"); + if (!templateDatas) return res.status(200).send([]); + + const formattedTemplates = templateDatas.map((data) => ({ + id: data.templateID, + name: data.templateName, + panelOrder: data.panelOrder, + widgets: data.widgets, + floatingWidget: data.floatWidgets, + widgets3D: data.Widgets3D, + snapshot: data.snapshot, + })); + + return res.status(200).json(formattedTemplates); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async AddToZone(req: Request, res: Response): Promise { + const { zoneId, templateID, organization } = req.body; + try { + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return res.status(404).json({ message: "Zone not found" }); + + const existingTemplate = await templateModel(organization).findOne({ + templateID: templateID, + isArchive: false, + }); + if (!existingTemplate) + return res.status(409).json({ message: "TemplateID not found" }); + if (existingZone.panelOrder.length > 0) { + existingZone.panelOrder = existingTemplate.panelOrder; + await existingZone.save(); + // Clear existing data before adding new data + const archivePanelDatas = await panelSchema(organization).find({ + zoneId, + isArchive: false, + }); + for (const panelData of archivePanelDatas) { + await widgetSchema(organization).deleteMany({ + panelID: panelData._id, + isArchive: false, + }); + } + await panelSchema(organization).deleteMany({ + zoneId, + isArchive: false, + }); + await floatWidgetModel(organization).deleteMany({ + zoneId, + isArchive: false, + }); + } + existingZone.panelOrder = existingTemplate.panelOrder; + await existingZone.save(); + const existingPanels = await panelSchema(organization).find({ + zoneId, + isArchive: false, + }); + const existingPanelNames = existingPanels.map( + (panel: any) => panel.panelName + ); + + const missingPanels = existingTemplate.panelOrder.filter( + (panelName: string) => !existingPanelNames.includes(panelName) + ); + const createdPanels = await Promise.all( + missingPanels.map((panelName: any) => + panelSchema(organization).create({ + zoneId, + panelName, + widgets: [], + isArchive: false, + }) + ) + ); + + for (const widgetData of existingTemplate.widgets) { + const addedExistingPanel = await panelSchema(organization).findOne({ + panelName: widgetData.panel, + zoneId, + isArchive: false, + }); + if (!addedExistingPanel) continue; + + const existingWidget = await widgetSchema(organization).findOne({ + panelID: addedExistingPanel._id, + widgetID: widgetData.id, + isArchive: false, + }); + if (existingWidget) continue; + + const newWidget = await widgetSchema(organization).create({ + widgetID: widgetData.id, + elementType: widgetData.type, + widgetName: widgetData.widgetName || "Widget", + panelID: addedExistingPanel._id, + widgetside: widgetData.panel, + }); + addedExistingPanel.widgets.push(newWidget._id); + await addedExistingPanel.save(); + } + + for (const floatData of existingTemplate.floatWidgets) { + const existingFloatWidget = await floatWidgetModel( + organization + ).findOne({ floatWidgetID: floatData.id, isArchive: false, zoneId }); + if (existingFloatWidget) continue; + + await floatWidgetModel(organization).create({ + className: floatData.className, + header: floatData.header, + floatWidgetID: floatData.id, + position: floatData.position, + per: floatData.per, + value: floatData.value, + zoneId, + }); + } + + return res + .status(201) + .json({ message: "Template placed in Zone", createdPanels }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + static async Deletezone(req: Request, res: Response): Promise { + try { + console.log("req.params: ", req.params); + const { organization, templateID } = req.params; + const existingTemplate = await templateModel(organization).findOne({ + templateID: templateID, + isArchive: false, + }); + if (existingTemplate) { + const newTemplate = await templateModel(organization).updateOne( + { templateID: templateID, isArchive: false }, + { $set: { isArchive: true } } + ); + if (newTemplate) + return res + .status(200) + .json({ message: "Template deleted successfully" }); + } + } catch (error: any) { + return res.status(500).send(error.message); + } + } +} diff --git a/src/api-server/controller/visualization/widgetService.ts b/src/api-server/controller/visualization/widgetService.ts new file mode 100644 index 0000000..3a10d04 --- /dev/null +++ b/src/api-server/controller/visualization/widgetService.ts @@ -0,0 +1,202 @@ +import { Request, Response } from "express"; +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; +export class widgetService { + static async addWidget(req: Request, res: Response): Promise { + try { + // console.log("req.body: ", req.body); + const { + organization, + // panel, + zoneId, + widget, + } = req.body; + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return res.status(404).json({ message: "Zone not found" }); + const existingPanel = await panelSchema(organization).findOne({ + panelName: widget.panel, + zoneId: zoneId, + isArchive: false, + }); + if (!existingPanel) + return res.status(404).json({ message: "panelName not found" }); + + if (existingPanel.panelName === widget.panel) { + const existingWidget = await widgetSchema(organization).findOne({ + panelID: existingPanel._id, + widgetID: widget.id, + isArchive: false, + // widgetOrder: widget.widgetOrder, + }); + // console.log('existingWidget: ', widget.data.measurements); + if (existingWidget) { + const updateWidget = await widgetSchema( + organization + ).findOneAndUpdate( + { + panelID: existingPanel._id, + widgetID: widget.id, + isArchive: false, + }, + { + $set: { + // panelID: existingPanel._id, + // widgetID: widget.id, + widgetName: widget.widgetName, + Data: { + measurements: widget.Data?.measurements || {}, + duration: widget.Data?.duration || "1h", + }, + // isArchive: false, + }, + }, + { upsert: true, new: true } // Upsert: create if not exists, new: return updated document + ); + console.log("updateWidget: ", updateWidget); + return res + .status(200) + .json({ message: "Widget updated successfully" }); + // return res + // .status(409) + // .json({ message: "Widget already exist for the widgetID" }); + } + const newWidget = await widgetSchema(organization).create({ + widgetID: widget.id, + elementType: widget.type, + // widgetOrder: widgetOrder, + widgetName: widget.widgetName, + panelID: existingPanel._id, + widgetside: widget.panel, + // Data: { + // measurements: widget.Data.measurements || {}, + // duration: widget.Data.duration || "1h", + // }, + }); + if (newWidget) { + existingPanel.widgets.push(newWidget._id); + await existingPanel.save(); + return res.status(201).json({ + message: "Widget created successfully", + // widgetID: newWidget._id, + }); + } + } + return res.json({ message: "Type mismatch" }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + static async deleteWidget(req: Request, res: Response): Promise { + try { + const { widgetID, organization } = req.body; + const findWidget = await widgetSchema(organization).findOne({ + widgetID: widgetID, + isArchive: false, + }); + if (!findWidget) + return res.status(409).json({ message: "Widget not found" }); + const widgetData = await widgetSchema(organization).updateOne( + { _id: findWidget._id, isArchive: false }, + { $set: { isArchive: true } } + ); + + if (widgetData) { + // Find all widgets in the same panel and sort them by widgetOrder + const widgets = await widgetSchema(organization).find({ + panelID: findWidget.panelID, + isArchive: false, + }); + // .sort({ widgetOrder: 1 }); + + // Reassign widgetOrder values + // for (let i = 0; i < widgets.length; i++) { + // widgets[i].widgetOrder = (i + 1).toString(); // Convert to string + // await widgets[i].save(); + // } + const panelData = await panelSchema(organization).findOne({ + _id: findWidget.panelID, + isArchive: false, + }); + if (panelData.widgets.includes(findWidget._id)) { + const index1 = panelData.widgets.indexOf(findWidget._id); + panelData.widgets.splice(index1, 1); + } + await panelData.save(); + } + return res.status(200).json({ message: "Widget deleted successfully" }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + static async updatewidget(req: Request, res: Response): Promise { + try { + const { organization, widgetID, values } = req.body; + const findwidget = await widgetSchema(organization).findOne({ + widgetID: widgetID, + isArchive: false, + }); + if (!findwidget) + return res.status(404).send({ message: "Data not found" }); + const updateData = { + widgetName: values.widgetName, + widgetSide: values.widgetSide, // Fixed typo from widgetside to widgetSide + elementType: values.type, + Data: { + measurement: values.Data.measurement, + duration: values.Data.duration, + }, + elementColor: values.color, + fontFamily: values.fontFamily, + fontStyle: values.fontStyle, + fontWeight: values.fontWeight, + isArchive: false, + }; + + const changedWidget = await widgetSchema(organization).findOneAndUpdate( + { widgetID: widgetID, isArchive: false }, + updateData, + { + new: true, + upsert: true, + setDefaultsOnInsert: true, + } + ); + + return res.status(200).json({ + message: "Widget updated successfully", + }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } + + static async getDatafromWidget(req: Request, res: Response): Promise { + const { organization, widgetID } = req.params; + try { + const existingWidget = await widgetSchema(organization) + .findOne({ + widgetID: widgetID, + isArchive: false, + }) + .select("Data widgetName -_id"); + if (!existingWidget) + return res.json({ message: "Widget not found for the widgetID" }); + const Datastructure = { + measurements: existingWidget.Data.measurements || {}, + duration: existingWidget.Data.duration || "1h", + }; + const widgetName = existingWidget.widgetName || "Widget"; + if (existingWidget) + return res.status(200).json({ Data: Datastructure, widgetName }); + } catch (error: any) { + return res.status(500).send(error.message); + } + } +} diff --git a/src/api-server/main.ts b/src/api-server/main.ts index 52a8a12..15f2bcf 100644 --- a/src/api-server/main.ts +++ b/src/api-server/main.ts @@ -1,21 +1,27 @@ -import app from './app'; +import app from './app.ts'; import http from 'http'; import ip from 'ip'; // import { startHealthCheck } from './controller/user-Controller'; import swaggerUi from 'swagger-ui-express'; -import mongoAdminCreation from '../shared/security/mongosecurity'; +import mongoAdminCreation from '../shared/security/mongosecurity.ts'; +import fs from 'fs'; const server = http.createServer(app); -let swaggerDocument; -try { + +let swaggerDocument = {}; +// try { +// swaggerDocument = require('../../swagger-output.json'); - swaggerDocument = require('../../swagger-output.json'); +// } catch (error) { +// console.error('Error loading Swagger JSON:', error); +// swaggerDocument = {}; // Fallback: empty object or some default +// } +try { + swaggerDocument = JSON.parse(fs.readFileSync('swagger-output.json', 'utf-8')); } catch (error) { console.error('Error loading Swagger JSON:', error); - swaggerDocument = {}; // Fallback: empty object or some default } - app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); const organization = process.env.ORGANIZATION_NAME || 'defaultOrganization'; // Replace with your logic diff --git a/src/shared/connect/mongoose.ts b/src/shared/connect/mongoose.ts index 5986cd7..ead358d 100644 --- a/src/shared/connect/mongoose.ts +++ b/src/shared/connect/mongoose.ts @@ -16,7 +16,7 @@ const MainModel = ( const authOptions = { user: process.env.MONGO_USER, // Correct username environment variable pass: process.env.MONGO_PASSWORD, // Correct password environment variable - authSource: process.env.MONGO_AUTH_DB || 'admin', // Default to 'admin' if not provided + authSource: process.env.MONGO_AUTH_DB || "admin", // Default to 'admin' if not provided maxPoolSize: 50, }; @@ -24,9 +24,9 @@ const MainModel = ( if (connections[db]) { return connections[db].model(modelName, schema, collectionName); } - + try { - const db1 = mongoose.createConnection(db1_url,authOptions); + const db1 = mongoose.createConnection(db1_url, authOptions); // Cache the connection connections[db] = db1; @@ -37,7 +37,10 @@ const MainModel = ( }); db1.on("error", (err) => { - console.error(`MongoDB connection error for database ${db}:`, err.message); + console.error( + `MongoDB connection error for database ${db}:`, + err.message + ); }); return db1.model(modelName, schema, collectionName); @@ -48,4 +51,3 @@ const MainModel = ( }; export default MainModel; - diff --git a/src/shared/model/assets/flooritems-Model.ts b/src/shared/model/assets/flooritems-Model.ts index ded0185..402967c 100644 --- a/src/shared/model/assets/flooritems-Model.ts +++ b/src/shared/model/assets/flooritems-Model.ts @@ -1,5 +1,5 @@ import mongoose, { Document, Schema } from 'mongoose'; -import MainModel from '../../connect/mongoose'; +import MainModel from '../../connect/mongoose.ts'; // Interface for TypeScript with PascalCase export interface floorItenms extends Document { diff --git a/src/shared/model/assets/wallitems-Model.ts b/src/shared/model/assets/wallitems-Model.ts index 03d2535..b22c46b 100644 --- a/src/shared/model/assets/wallitems-Model.ts +++ b/src/shared/model/assets/wallitems-Model.ts @@ -1,5 +1,5 @@ import mongoose, { Document, Schema } from 'mongoose'; -import MainModel from '../../connect/mongoose'; +import MainModel from '../../connect/mongoose.ts'; // Interface for TypeScript with PascalCase export interface wallitems extends Document { modeluuid: string; diff --git a/src/shared/model/builder/assets/asset-Model.ts b/src/shared/model/builder/assets/asset-Model.ts new file mode 100644 index 0000000..868eb71 --- /dev/null +++ b/src/shared/model/builder/assets/asset-Model.ts @@ -0,0 +1,85 @@ +import mongoose, { Document, Schema } from "mongoose"; +import MainModel from "../../../connect/mongoose.ts"; + +export interface assetData extends Document { + modeluuid: string; + modelfileID: string; + modelname: string; + isLocked: boolean; + type: string; + isVisible: boolean; + // position: []; + // rotation: { + // x: number; + // y: number; + // z: number; + // }; + points: { + uuid: string; + position: []; + rotation: []; + actions: [mongoose.Types.ObjectId]; + triggers: [mongoose.Types.ObjectId]; + connections: { + source: { + pathUUID: string; + pointUUID: string; + }; + targets: [ + { + pathUUID: string; + pointUUID: string; + } + ]; + }[]; + }[]; + assetPosition: number[]; + assetRotation: number[]; + speed: number | string; +} + +// Define the Mongoose Schema +const assetDataSchema: Schema = new Schema({ + modeluuid: { type: String }, + modelfileID: { type: String }, + modelname: { type: String }, + type: { type: String }, + // assetPosition: { type: Array }, + points: [ + { + uuid: { type: String }, + position: { type: Array }, + rotation: { type: Array }, + actions: [{ type: mongoose.Schema.Types.ObjectId, ref: "Actions" }], + triggers: [{ type: mongoose.Schema.Types.ObjectId, ref: "Triggers" }], + connections: { + source: { + pathUUID: { type: String }, + pointUUID: { type: String }, + }, + targets: [ + { + pathUUID: { type: String }, + pointUUID: { type: String }, + }, + ], + }, + }, + ], + assetPosition: { type: [Number] }, + assetRotation: { type: [Number] }, + speed: { type: Schema.Types.Mixed }, + isLocked: { type: Boolean }, + isVisible: { type: Boolean }, + // rotation: { + // x: { type: Number }, + // y: { type: Number }, + // z: { type: Number }, + // }, +}); + +// export default floorItemsModel; +const assetModel = (db: string) => { + return MainModel(db, "Assets", assetDataSchema, "Assets"); +}; +export default assetModel; diff --git a/src/shared/model/builder/assets/assetPoint-Model.ts b/src/shared/model/builder/assets/assetPoint-Model.ts new file mode 100644 index 0000000..1e07f22 --- /dev/null +++ b/src/shared/model/builder/assets/assetPoint-Model.ts @@ -0,0 +1,107 @@ +import mongoose, { Schema, Document } from "mongoose"; +import MainModel from "../../../connect/mongoose.ts"; + +interface IAction { + uuid: string; + name: string; + type: string; + material: string; + delay: string; + spawnInterval: string; + isUsed: boolean; + hitCount: number; + start: string; + end: string; + buffer: number; +} + +interface ITriggers { + uuid: string; + name: string; + type: string; + isUsed: boolean; + bufferTime: number; +} + +interface IConnection { + source: { pathUUID: string; pointUUID: string }; + targets: { pathUUID: string; pointUUID: string }[]; +} + +interface IPoint { + uuid: string; + position: number[]; + rotation: number[]; + actions: IAction[]; + triggers: ITriggers[]; + connections: IConnection; +} + +interface IBaseModel extends Document { + modelfileID: string; + type: "Conveyor" | "Vehicle"; + points: IPoint[] | IPoint; +} + +// Base Schema +const PointSchema = new Schema({ + uuid: { type: String, required: true }, + position: { type: [Number] }, + rotation: { type: [Number] }, + actions: [ + { + uuid: { type: String, default: "" }, + name: { type: String }, + type: { type: String }, + material: { type: String }, + delay: { type: String }, + spawnInterval: { type: String }, + isUsed: { type: Boolean }, + hitCount: { type: String }, + start: { type: String }, + end: { type: String }, + buffer: { type: String }, + }, + ], + triggers: [ + { + uuid: { type: String, default: "" }, + name: { type: String }, + type: { type: String }, + bufferTime: { type: Number }, + isUsed: { type: Boolean }, + }, + ], + connections: { + source: { + pathUUID: { type: String }, + pointUUID: { type: String }, + }, + targets: [ + { + pathUUID: { type: String }, + pointUUID: { type: String }, + }, + ], + }, +}); + +const BaseSchema = new Schema( + { + modelfileID: { type: String }, + type: { type: String, enum: ["Conveyor", "Vehicle"] }, + points: { + type: Schema.Types.Mixed, + required: true, + }, + }, + { discriminatorKey: "type", timestamps: true } +); + +const pointModel = (db: string) => { + return MainModel(db, "Points", BaseSchema, "Points"); +}; +export default pointModel; + +// const pointModel = mongoose.model("Points", BaseSchema, "Points"); +// export default pointModel; diff --git a/src/shared/model/builder/assets/wallitems-Model.ts b/src/shared/model/builder/assets/wallitems-Model.ts new file mode 100644 index 0000000..c5a3dcc --- /dev/null +++ b/src/shared/model/builder/assets/wallitems-Model.ts @@ -0,0 +1,31 @@ +import mongoose, { Document, Schema } from "mongoose"; +import MainModel from "../../../connect/mongoose.ts"; +// Interface for TypeScript with PascalCase +export interface wallitems extends Document { + modeluuid: string; + modelname: string; + type: string; + csgposition: []; + csgscale: []; + position: []; + quaternion: []; + scale: []; +} + +// Define the Mongoose Schema +const wallItemsSchema: Schema = new Schema({ + modeluuid: { type: String, unique: true }, + modelname: { type: String }, + type: { type: String }, + csgposition: { type: Array }, + csgscale: { type: Array }, + position: { type: Array }, + quaternion: { type: Array }, + scale: { type: Array }, +}); + +// export default wallItenmModel; +const wallItenmModel = (db: string) => { + return MainModel(db, "wallitems", wallItemsSchema, "wallitems"); +}; +export default wallItenmModel; diff --git a/src/shared/model/builder/camera/camera-Model.ts b/src/shared/model/builder/camera/camera-Model.ts new file mode 100644 index 0000000..679f382 --- /dev/null +++ b/src/shared/model/builder/camera/camera-Model.ts @@ -0,0 +1,48 @@ +import mongoose, { Document, Schema } from "mongoose"; +import MainModel from "../../../connect/mongoose.ts"; + +// Interface for TypeScript with PascalCase +export interface Camera extends Document { + userId: string; + position: { + x: number; + y: number; + z: number; + }; + target: { + x: { type: Number; required: true }; + y: { type: Number; required: true }; + z: { type: Number; required: true }; + }; + rotation: { + x: { type: Number; required: true }; + y: { type: Number; required: true }; + z: { type: Number; required: true }; + }; +} + +// Define the Mongoose Schema +const cameraSchema: Schema = new Schema({ + userId: { type: String }, + position: { + x: { type: Number, required: true }, + y: { type: Number, required: true }, + z: { type: Number, required: true }, + }, + target: { + x: { type: Number, required: true }, + y: { type: Number, required: true }, + z: { type: Number, required: true }, + }, + rotation: { + x: { type: Number, required: true }, + y: { type: Number, required: true }, + z: { type: Number, required: true }, + }, +}); + +// export default cameraModel +const cameraModel = (db: string) => { + return MainModel(db, "Camera", cameraSchema, "Camera"); +}; +export default cameraModel; diff --git a/src/shared/model/builder/environments/environments-Model.ts b/src/shared/model/builder/environments/environments-Model.ts new file mode 100644 index 0000000..1ea37de --- /dev/null +++ b/src/shared/model/builder/environments/environments-Model.ts @@ -0,0 +1,24 @@ +import mongoose, { Document, Schema } from 'mongoose'; +import MainModel from '../../../connect/mongoose.ts'; +// Interface for TypeScript with PascalCase +export interface environment extends Document { + userId: string; + roofVisibility: boolean + wallVisibility: boolean +} + +// Define the Mongoose Schema +const environmentSchema: Schema = new Schema({ + userId: { type: String, unique: true }, + roofVisibility: { type: Boolean, default: false }, + wallVisibility: { type: Boolean, default: false }, + shadowVisibility: { type: Boolean, default: false }, +}); + + + +// export default environmentModel; +const environmentModel = (db: string) => { + return MainModel(db, "environments", environmentSchema, "environments") +}; +export default environmentModel; \ No newline at end of file diff --git a/src/shared/model/builder/lines/lines-Model.ts b/src/shared/model/builder/lines/lines-Model.ts new file mode 100644 index 0000000..e1c0f7f --- /dev/null +++ b/src/shared/model/builder/lines/lines-Model.ts @@ -0,0 +1,26 @@ +import mongoose, { Document, Schema } from "mongoose"; +import MainModel from "../../../connect/mongoose.ts"; +const positionSchema = new mongoose.Schema({ + x: { type: Number }, // Optional position fields + y: { type: Number }, + z: { type: Number }, +}); + +// Define a schema for the individual line +const Vector3 = new mongoose.Schema({ + position: { type: positionSchema, required: false }, // Optional position + uuid: { type: String, required: false }, // Optional uuid +}); + +// Define the main schema +const LineSchema = new mongoose.Schema({ + layer: { type: Number, required: true }, // Layer is mandatory + line: { type: [Vector3], required: true }, // Array of line objects + type: { type: String, required: false }, // Optional type +}); + +// export default lineModel; +const lineModel = (db: string) => { + return MainModel(db, "lines", LineSchema, "lines"); +}; +export default lineModel; diff --git a/src/shared/model/builder/lines/zone-Model.ts b/src/shared/model/builder/lines/zone-Model.ts new file mode 100644 index 0000000..a1e6e12 --- /dev/null +++ b/src/shared/model/builder/lines/zone-Model.ts @@ -0,0 +1,84 @@ +// import mongoose, { Schema, Document, model } from "mongoose"; +// import MainModel from "../../../connect/mongoose.ts"; + +// export interface Zone extends Document { +// zoneName: string; +// // zoneUUID: string; +// zonePoints: []; +// centerPoints: []; +// isArchive: boolean; +// createdBy: string; +// sceneID: string; +// // createdBy: mongoose.Types.ObjectId; +// // sceneID: mongoose.Types.ObjectId; +// layer: number; +// } +// const zoneSchema: Schema = new Schema( +// { +// zoneName: { type: String }, +// // zoneUUID: { type: String }, +// createdBy: { type: String }, +// sceneID: { type: String }, +// layer: { type: Number }, +// centerPoints: { type: Array }, +// zonePoints: { type: Array }, +// isArchive: { type: Boolean, default: false }, +// // createdBy: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, +// // sceneID: { type: mongoose.Schema.Types.ObjectId, ref: "Scene" }, +// }, +// { timestamps: true } +// ); + +// const dataModel = (db: any) => { +// return MainModel(db, "Zones", zoneSchema, "Zones"); +// }; +// export default dataModel; + +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../../connect/mongoose.ts"; + +export interface Zone extends Document { + zoneName: string; + zoneId: string; + zonePoints: []; + viewPortCenter: []; + viewPortposition: []; + isArchive: boolean; + createdBy: string; + sceneID: string; + panelOrder: string[]; + lockedPanel: string[]; + // createdBy: mongoose.Types.ObjectId; + // sceneID: mongoose.Types.ObjectId; + layer: number; +} +const zoneSchema: Schema = new Schema( + { + zoneName: { type: String }, + zoneId: { type: String }, + createdBy: { type: String }, + sceneID: { type: String }, + layer: { type: Number }, + points: { type: Array }, + isArchive: { type: Boolean, default: false }, + panelOrder: { + type: [String], + enum: ["left", "right", "up", "down"], + }, + viewPortCenter: { type: Array, required: true }, + viewPortposition: { type: Array, required: true }, + lockedPanel: { + type: [String], + default: [], + enum: ["left", "right", "up", "down"], + }, + // createdBy: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, + // sceneID: { type: mongoose.Schema.Types.ObjectId, ref: "Scene" }, + }, + { timestamps: true } +); + +const zoneModel = (db: any) => { + return MainModel(db, "zones", zoneSchema, "zones"); +}; +export default zoneModel; diff --git a/src/shared/model/camera/camera-Model.ts b/src/shared/model/camera/camera-Model.ts index e51b824..7c8e35b 100644 --- a/src/shared/model/camera/camera-Model.ts +++ b/src/shared/model/camera/camera-Model.ts @@ -1,5 +1,5 @@ import mongoose, { Document, Schema } from 'mongoose'; -import MainModel from '../../connect/mongoose'; +import MainModel from '../../connect/mongoose.ts'; // Interface for TypeScript with PascalCase export interface Camera extends Document { diff --git a/src/shared/model/environments/environments-Model.ts b/src/shared/model/environments/environments-Model.ts index 76679ec..4b6524b 100644 --- a/src/shared/model/environments/environments-Model.ts +++ b/src/shared/model/environments/environments-Model.ts @@ -1,18 +1,23 @@ -import mongoose, { Document, Schema } from 'mongoose'; -import MainModel from '../../connect/mongoose'; +import mongoose, { Document, Schema } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; // Interface for TypeScript with PascalCase export interface environment extends Document { userId: string; - roofVisibility:boolean - wallVisibility:boolean + roofVisibility: boolean; + wallVisibility: boolean; + renderDistance: number; + shadowVisibility: boolean; + limitDistance: boolean; } // Define the Mongoose Schema const environmentSchema: Schema = new Schema({ userId: { type: String, unique: true }, - roofVisibility: { type: Boolean ,default:false}, - wallVisibility: { type: Boolean ,default:false}, - shadowVisibility: { type: Boolean ,default:false}, + roofVisibility: { type: Boolean, default: false }, + wallVisibility: { type: Boolean, default: false }, + shadowVisibility: { type: Boolean, default: false }, + renderDistance: { type: Number, default: false }, + limitDistance: { type: Boolean, default: true }, }); // Model for MongoDB collection @@ -33,7 +38,7 @@ const environmentSchema: Schema = new Schema({ // } // export default environmentModel; -const environmentModel = (db:string) => { - return MainModel(db, "environments", environmentSchema, "environments") +const environmentModel = (db: string) => { + return MainModel(db, "environments", environmentSchema, "environments"); }; -export default environmentModel; \ No newline at end of file +export default environmentModel; diff --git a/src/shared/model/lines/lines-Model.ts b/src/shared/model/lines/lines-Model.ts index 2f10c65..c5492a6 100644 --- a/src/shared/model/lines/lines-Model.ts +++ b/src/shared/model/lines/lines-Model.ts @@ -1,5 +1,5 @@ import mongoose, { Document, Schema } from "mongoose"; -import MainModel from "../../connect/mongoose"; +import MainModel from "../../connect/mongoose.ts"; const positionSchema = new mongoose.Schema({ x: { type: Number, }, // Optional position fields y: { type: Number, }, diff --git a/src/shared/model/lines/zone-Model.ts b/src/shared/model/lines/zone-Model.ts index e539a46..e35f4ec 100644 --- a/src/shared/model/lines/zone-Model.ts +++ b/src/shared/model/lines/zone-Model.ts @@ -1,25 +1,27 @@ import mongoose, { Document, ObjectId, Schema } from "mongoose"; -import MainModel from "../../connect/mongoose"; +import MainModel from "../../connect/mongoose.ts"; export interface zoneSchema extends Document { - zoneId: string; + zoneId: string;//UUID zoneName: string createBy: mongoose.Types.ObjectId points: [] layer: Number viewPortCenter: [] viewPortposition: [] + isArchive:boolean } // Define the Mongoose Schema const zoneSchema: Schema = new Schema({ - zoneId: { type: String }, + zoneId: { type: String },//UUID zoneName: { type: String }, createBy: { type: Schema.Types.ObjectId, ref: "Users", }, points: { type: Array }, layer: { type: Number, required: true }, viewPortCenter: { type: Array, required: true }, viewPortposition: { type: Array, required: true }, + isArchive:{type:Boolean,default:false} }); diff --git a/src/shared/model/simulation/actionmodel.ts b/src/shared/model/simulation/actionmodel.ts new file mode 100644 index 0000000..f376c06 --- /dev/null +++ b/src/shared/model/simulation/actionmodel.ts @@ -0,0 +1,46 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface Action extends Document { + pointsUUID: string; + // actionUUID: string; + isArchive: string; + // sceneID: string; + // eventData: { + uuid: string; + name: string; + type: string; + material: string; + delay: string; + spawnInterval: string; + isUsed: boolean; + hitCount: number; + start: string; + end: string; + buffer: number; + // }; +} +const actionSchema: Schema = new Schema( + { + pointsUUID: { type: String }, + isArchive: { type: Boolean, default: false }, + // actionUUID: { type: String }, + uuid: { type: String, default: "" }, + name: { type: String }, + type: { type: String }, + material: { type: String }, + delay: { type: String }, + spawnInterval: { type: String }, + isUsed: { type: Boolean }, + hitCount: { type: String }, + start: { type: String }, + end: { type: String }, + buffer: { type: String }, + }, + { timestamps: true } +); + +const actionModel = (db: any) => { + return MainModel(db, "Actions", actionSchema, "Actions"); +}; +export default actionModel; diff --git a/src/shared/model/simulation/triggersmodel.ts b/src/shared/model/simulation/triggersmodel.ts new file mode 100644 index 0000000..83a0b7c --- /dev/null +++ b/src/shared/model/simulation/triggersmodel.ts @@ -0,0 +1,33 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface Trigger extends Document { + pointsUUID: string; + // triggerUUID: string; + isArchive: string; + // sceneID: string; + uuid: string; + name: string; + type: string; + isUsed: boolean; + bufferTime: number; +} +const triggerSchema: Schema = new Schema( + { + pointsUUID: { type: String }, + isArchive: { type: Boolean, default: false }, + // triggerUUID: { type: String }, + uuid: { type: String, default: "" }, + name: { type: String }, + type: { type: String }, + material: { type: String }, + delay: { type: String }, + isUsed: { type: Boolean }, + }, + { timestamps: true } +); + +const triggerModel = (db: any) => { + return MainModel(db, "Triggers", triggerSchema, "Triggers"); +}; +export default triggerModel; diff --git a/src/shared/model/user-Model.ts b/src/shared/model/user-Model.ts index 746e417..191a1a7 100644 --- a/src/shared/model/user-Model.ts +++ b/src/shared/model/user-Model.ts @@ -1,5 +1,5 @@ import mongoose, { Document, Schema } from "mongoose"; -import MainModel from "../connect/mongoose"; +import MainModel from "../connect/mongoose.ts"; export interface User extends Document { userName: String; email: String; diff --git a/src/shared/model/vizualization/3dwidget.ts b/src/shared/model/vizualization/3dwidget.ts new file mode 100644 index 0000000..fd435c8 --- /dev/null +++ b/src/shared/model/vizualization/3dwidget.ts @@ -0,0 +1,33 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface Widget3d extends Document { + widgetName: string; + widgetID: string; + position: []; + isArchive: boolean; + zoneId: string; + Data: { + measurements: {}; + duration: string; + }; +} +const Widget3dSchema: Schema = new Schema( + { + widgetName: { type: String }, + widgetID: { type: String }, + position: { type: Array }, + zoneId: { type: String }, + Data: { + measurements: { type: Object, default: {} }, + duration: { type: String, default: "1h" }, + }, + isArchive: { type: Boolean, default: false }, + }, + { timestamps: true } +); + +const widget3dModel = (db: any) => { + return MainModel(db, "3dWidget", Widget3dSchema, "3dWidget"); +}; +export default widget3dModel; diff --git a/src/shared/model/vizualization/floatWidget.ts b/src/shared/model/vizualization/floatWidget.ts new file mode 100644 index 0000000..2222d40 --- /dev/null +++ b/src/shared/model/vizualization/floatWidget.ts @@ -0,0 +1,44 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface floatingWidget extends Document { + className: string; + header: string; + floatWidgetID: string; + position: {}; + per: string; + value: string; + isArchive: boolean; + zoneId: string; + Data: { + measurements: {}; + duration: string; + }; +} +const floatingWidgetSchema: Schema = new Schema( + { + className: { type: String }, + header: { type: String }, + floatWidgetID: { type: String }, + position: { type: Object }, + per: { type: String }, + value: { type: String }, + zoneId: { type: String }, + Data: { + measurements: { type: Object, default: {} }, + duration: { type: String, default: "1h" }, + }, + isArchive: { type: Boolean, default: false }, + }, + { timestamps: true } +); + +const floatWidgetModel = (db: any) => { + return MainModel( + db, + "FloatingWidget", + floatingWidgetSchema, + "FloatingWidget" + ); +}; +export default floatWidgetModel; diff --git a/src/shared/model/vizualization/panelmodel.ts b/src/shared/model/vizualization/panelmodel.ts new file mode 100644 index 0000000..ef15939 --- /dev/null +++ b/src/shared/model/vizualization/panelmodel.ts @@ -0,0 +1,25 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface Panel extends Document { + // zoneId: mongoose.Types.ObjectId; + zoneId: string; + panelName: string; + widgets: [mongoose.Types.ObjectId]; + isArchive: boolean; +} +const panelSchema: Schema = new Schema( + { + // zoneId: { type: mongoose.Schema.Types.ObjectId, ref: "Zone" }, + zoneId: { type: String }, + panelName: { type: String }, + widgets: [{ type: mongoose.Schema.Types.ObjectId, ref: "Widget" }], + isArchive: { type: Boolean, default: false }, + }, + { timestamps: true } +); + +const panelModel = (db: any) => { + return MainModel(db, "Panel", panelSchema, "Panel"); +}; +export default panelModel; diff --git a/src/shared/model/vizualization/templatemodel.ts b/src/shared/model/vizualization/templatemodel.ts new file mode 100644 index 0000000..2499beb --- /dev/null +++ b/src/shared/model/vizualization/templatemodel.ts @@ -0,0 +1,31 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface Template extends Document { + templateName: string; + templateID: string; + snapshot: string; + panelOrder: []; + widgets: []; + floatWidgets: []; + Widgets3D: []; + isArchive: boolean; +} +const templateSchema: Schema = new Schema( + { + templateName: { type: String }, + templateID: { type: String }, + snapshot: { type: String }, + panelOrder: { type: Array }, + widgets: { type: Array }, + floatWidgets: { type: Array }, + Widgets3D: { type: Array }, + isArchive: { type: Boolean, default: false }, + }, + { timestamps: true } +); + +const templateModel = (db: any) => { + return MainModel(db, "Template", templateSchema, "Template"); +}; +export default templateModel; diff --git a/src/shared/model/vizualization/widgemodel.ts b/src/shared/model/vizualization/widgemodel.ts new file mode 100644 index 0000000..cad396e --- /dev/null +++ b/src/shared/model/vizualization/widgemodel.ts @@ -0,0 +1,45 @@ +import mongoose, { Schema, Document, model } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; + +export interface widget extends Document { + widgetName: string; + widgetside: string; + widgetID: string; + widgetOrder: string; + elementType: string; + elementColor: string; + fontFamily: string; + fontStyle: string; + fontWeight: string; + isArchive: boolean; + panelID: mongoose.Types.ObjectId; + Data: { + measurements: {}; + duration: string; + }; +} +const widgetSchema: Schema = new Schema( + { + widgetName: { type: String, default: "Widget" }, + widgetside: { type: String }, + widgetID: { type: String }, + widgetOrder: { type: String }, + elementType: { type: String }, + elementColor: { type: String }, + fontFamily: { type: String }, + fontStyle: { type: String }, + Data: { + measurements: { type: Object, default: {} }, + duration: { type: String, default: "1h" }, + }, + fontWeight: { type: String }, + isArchive: { type: Boolean, default: false }, + panelID: { type: mongoose.Schema.Types.ObjectId, ref: "Panel" }, + }, + { timestamps: true } +); + +const widgetModel = (db: any) => { + return MainModel(db, "Widget", widgetSchema, "Widget"); +}; +export default widgetModel; diff --git a/src/shared/security/Hasing.ts b/src/shared/security/Hasing.ts index f74281e..7b52ee1 100644 --- a/src/shared/security/Hasing.ts +++ b/src/shared/security/Hasing.ts @@ -1,16 +1,17 @@ -const bcrypt = require("bcryptjs"); +import bcrypt from 'bcryptjs'; + const saltRounds = 10; -const hashGenerate = async (Password:String) => { +export const hashGenerate = async (Password:string) => { try { const salt = await bcrypt.genSalt(saltRounds); const hash = await bcrypt.hash(Password, salt); - + return hash; } catch (error) { return error; } }; -const hashValidator = async (password:String, hashedPassword:String) => { +export const hashValidator = async (password:string, hashedPassword:string) => { try { const result = await bcrypt.compare(password, hashedPassword); @@ -20,5 +21,4 @@ const hashValidator = async (password:String, hashedPassword:String) => { return false; } }; -module.exports.hashGenerate = hashGenerate; -module.exports.hashValidator = hashValidator; \ No newline at end of file +; diff --git a/src/socket-server/Dockerfile b/src/socket-server/Dockerfile index 5ecee54..f7863f6 100644 --- a/src/socket-server/Dockerfile +++ b/src/socket-server/Dockerfile @@ -7,7 +7,7 @@ ENV NODE_ENV development WORKDIR /usr/src/app -RUN npm install -g npm +RUN npm install -g tsx COPY package.json /usr/src/app/package.json diff --git a/src/socket-server/index.ts b/src/socket-server/index.ts index 1df2843..044f064 100644 --- a/src/socket-server/index.ts +++ b/src/socket-server/index.ts @@ -6,7 +6,7 @@ import dotenv from "dotenv"; // Import dotenv dotenv.config(); -import { initSocketServer } from "./socket/socketManager"; +import { initSocketServer } from "./socket/socketManager.ts"; const app = express(); const PORT = process.env.SOCKET_PORT; diff --git a/src/socket-server/services/assets/flooritem-Controller.ts b/src/socket-server/services/assets/flooritem-Controller.ts index 9f14a06..4a2f604 100644 --- a/src/socket-server/services/assets/flooritem-Controller.ts +++ b/src/socket-server/services/assets/flooritem-Controller.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import floorItemsModel from "../../../shared/model/assets/flooritems-Model"; +import floorItemsModel from "../../../shared/model/assets/flooritems-Model.ts"; export const setFloorItems = async (data: any) => { try { diff --git a/src/socket-server/services/assets/wallitem-Controller.ts b/src/socket-server/services/assets/wallitem-Controller.ts index f702af7..e2ac9f9 100644 --- a/src/socket-server/services/assets/wallitem-Controller.ts +++ b/src/socket-server/services/assets/wallitem-Controller.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import wallItenmModel from "../../../shared/model/assets/wallitems-Model"; +import wallItenmModel from "../../../shared/model/assets/wallitems-Model.ts"; export const setWallItems = async (data: any) => { diff --git a/src/socket-server/services/camera/camera-Controller.ts b/src/socket-server/services/camera/camera-Controller.ts index 3d78d63..1231a0f 100644 --- a/src/socket-server/services/camera/camera-Controller.ts +++ b/src/socket-server/services/camera/camera-Controller.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express"; import { Socket } from "socket.io"; -import cameraModel from "../../../shared/model/camera/camera-Model"; +import cameraModel from "../../../shared/model/camera/camera-Model.ts"; export const createCamera = async (data: any,) => { const { userId, position, target, organization,rotation } = data diff --git a/src/socket-server/services/environments/environments-controller.ts b/src/socket-server/services/environments/environments-controller.ts index 3081061..8137bdf 100644 --- a/src/socket-server/services/environments/environments-controller.ts +++ b/src/socket-server/services/environments/environments-controller.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import environmentModel from "../../../shared/model/environments/environments-Model"; +import environmentModel from "../../../shared/model/environments/environments-Model.ts"; diff --git a/src/socket-server/services/lines/line-Controller.ts b/src/socket-server/services/lines/line-Controller.ts index c9a3193..6497bea 100644 --- a/src/socket-server/services/lines/line-Controller.ts +++ b/src/socket-server/services/lines/line-Controller.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import lineModel from "../../../shared/model/lines/lines-Model"; +import lineModel from "../../../shared/model/lines/lines-Model.ts"; export const createLineItems = async (data: any)=>{ diff --git a/src/socket-server/services/lines/zone-Services.ts b/src/socket-server/services/lines/zone-Services.ts new file mode 100644 index 0000000..938e7d1 --- /dev/null +++ b/src/socket-server/services/lines/zone-Services.ts @@ -0,0 +1,79 @@ +import zoneModel from "../../../shared/model/builder/lines/zone-Model.ts"; + +// export const setZone = async (data: any) => { +// const { organization, userId, zoneData } = data + +// try { +// console.log('data: ', data); +// const zoneId = zoneData.zoneId +// const points = zoneData.points +// const zoneName = zoneData.zoneName +// const layer = zoneData.layer +// const viewPortCenter = zoneData.viewPortCenter +// const viewPortposition = zoneData.viewPortposition +// const sceneID = zoneData.sceneID + +// const existingZone = await zoneModel(organization).findOne({ +// zoneId: zoneId, +// isArchive: false, +// }); +// if (!existingZone) { +// const newZone = await zoneModel(organization).create({ +// zoneName: zoneName, +// zoneId: zoneId, +// zonePoints: points, +// viewPortposition: viewPortposition, +// viewPortCenter: viewPortCenter, +// createdBy: userId, +// layer: layer, +// sceneID: sceneID, +// }); +// if (newZone) +// return { success: true, message: 'zone created', data: newZone, organization: organization } + +// } else { +// const replaceZone = await zoneModel(organization).findOneAndUpdate( +// { zoneId: zoneId, isArchive: false }, +// { +// zonePoints: points, +// viewPortposition: viewPortposition, +// viewPortCenter: viewPortCenter, +// }, +// { new: true } +// ); +// if (!replaceZone) +// return { success: false, message: 'Zone not updated',organization: organization } +// else +// return { success: true, message: 'zone updated', data: replaceZone, organization: organization } + +// } +// } catch (error: any) { +// return { success: false, message: 'Zone not found', error,organization: organization } +// } +// } +// export const deleteZone = async (data: any) => { +// const { organization, userId, zoneId } = data +// try { +// const existingZone = await zoneModel(organization).findOne({ +// zoneId: zoneId, +// isArchive: false, +// }); +// if (!existingZone) { +// return { success: true, message: 'Invalid zone ID', organization: organization } +// } else { +// const deleteZone = await zoneModel(organization).findOneAndUpdate( +// { zoneId: zoneId, isArchive: false }, +// { +// isArchive: true, +// }, +// { new: true } +// ); + +// if (deleteZone) { +// return { success: true, message: 'zone deleted', data: deleteZone, organization: organization } +// } +// } +// } catch (error: any) { +// return { success: false, message: 'Zone not found', error,organization: organization } +// } +// } \ No newline at end of file diff --git a/src/socket-server/services/lines/zone-controller.ts b/src/socket-server/services/lines/zone-controller.ts index a3f7dd1..1a8a8b5 100644 --- a/src/socket-server/services/lines/zone-controller.ts +++ b/src/socket-server/services/lines/zone-controller.ts @@ -1,4 +1,4 @@ -import zoneModel from "../../../shared/model/lines/zone-Model"; +import zoneModel from "../../../shared/model/lines/zone-Model.ts"; export const setZone = async (data: any) => { try { diff --git a/src/socket-server/services/users/user-controller.ts b/src/socket-server/services/users/user-controller.ts index 379c112..a7f5fdc 100644 --- a/src/socket-server/services/users/user-controller.ts +++ b/src/socket-server/services/users/user-controller.ts @@ -1,5 +1,5 @@ -import cameraModel from "../../../shared/model/camera/camera-Model" -import userModel from "../../../shared/model/user-Model" +import cameraModel from "../../../shared/model/camera/camera-Model.ts" +import userModel from "../../../shared/model/user-Model.ts" export const activeUsers = async (data: any) => { const {organization}=data diff --git a/src/socket-server/services/visualization/panel-Services.ts b/src/socket-server/services/visualization/panel-Services.ts new file mode 100644 index 0000000..4a24ad7 --- /dev/null +++ b/src/socket-server/services/visualization/panel-Services.ts @@ -0,0 +1,105 @@ +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; + +export const addPanel = async (data: any) => { +const{organization,zoneId,panelName,panelOrder}=data +console.log('data: ', data); +try { + const findZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + console.log('findZone: ', findZone); + if (!findZone) { + return { success: false, message: 'Zone not found',organization: organization} + + } + const updatezone = await zoneSchema(organization).findOneAndUpdate( + { zoneId: zoneId, isArchive: false }, + { panelOrder: panelOrder }, + { new: true } + ); + const existingPanels = await panelSchema(organization).find({ + zoneId: zoneId, + isArchive: false, + }); + + const existingPanelNames = existingPanels.map( + (panel: any) => panel.panelName + ); + + const missingPanels = panelOrder.filter( + (panelName: string) => !existingPanelNames.includes(panelName) + ); + + const createdPanels = []; + for (const panelName of missingPanels) { + const newPanel = await panelSchema(organization).create({ + zoneId: zoneId, + panelName: panelName, + widgets: [], + isArchive: false, + }); + createdPanels.push(newPanel); + } + + if (createdPanels.length === 0) { + return { success: false, message: "No new panels were created. All panels already exist",organization: organization} + } + // const IDdata = createdPanels.map((ID: any) => { + // return ID._id; + // }); + console.log("IDdata: ", createdPanels); + createdPanels + return { success: true, message: "Panels created successfully", data: createdPanels, organization: organization } +}catch (error) { + return { success: false, message: 'Panel not found', error,organization: organization } + +} + +} +export const panelDelete = async (data: any) => { + const { organization, panelName, zoneId } = data; + console.log('data: ', data); + try { + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return { success: false, message: 'Zone not found',organization: organization} + + const existingPanel = await panelSchema(organization).findOne({ + zoneId: zoneId, + panelName: panelName, + isArchive: false, + }); + if (!existingPanel) + return { success: false, message: 'Panel Already Deleted',organization: organization} + const updatePanel = await panelSchema(organization).updateOne( + { _id: existingPanel._id, isArchive: false }, + { $set: { isArchive: true } } + ); + const existingWidgets = await widgetSchema(organization).find({ + panelID:existingPanel._id, + isArchive: false, + }); + + for (const widgetData of existingWidgets) { + widgetData.isArchive = true; + await widgetData.save(); + } + + if (existingZone.panelOrder.includes(existingPanel.panelName)) { + const index1 = existingZone.panelOrder.indexOf(existingPanel.panelName); + existingZone.panelOrder.splice(index1, 1); + + const panelDeleteDatas= await existingZone.save(); + return { success: true, message: 'Panel deleted successfully',data:panelDeleteDatas,organization: organization} + } + + } catch (error) { + return { success: false, message: 'Panel not found', error,organization: organization } } + + } \ No newline at end of file diff --git a/src/socket-server/services/visualization/widget-Services.ts b/src/socket-server/services/visualization/widget-Services.ts new file mode 100644 index 0000000..697fe4b --- /dev/null +++ b/src/socket-server/services/visualization/widget-Services.ts @@ -0,0 +1,119 @@ +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; +export const addWidget = async (data: any) => { + const { organization,panel,zoneId,widget,} = data + console.log('data: ', data); + try { + const existingPanel = await panelSchema(organization).findOne({ + panelName: widget.panel, + zoneId: zoneId, + isArchive: false, + }); + if (!existingPanel) + + return { success: false, message: "panelName not found",organization: organization} + + + if (existingPanel.panelName === widget.panel) { + const existingWidget = await widgetSchema(organization).findOne({ + panelID: existingPanel._id, + widgetID: widget.id, + isArchive: false, + // widgetOrder: widget.widgetOrder, + }); + if (existingWidget) { + const updateWidget = await widgetSchema( + organization + ).findOneAndUpdate( + { + panelID: existingPanel._id, + widgetID: widget.id, + isArchive: false, + }, + { + $set: { + panelID: existingPanel._id, + widgetID: widget.id, + Data: { + measurements: widget.Data.measurements, + duration: widget.Data.duration, + }, + isArchive: false, + }, + }, + { upsert: true, new: true } // Upsert: create if not exists, new: return updated document + ); + + return { success: false, message: "Widget updated successfully",data:updateWidget,organization: organization} + + } + const newWidget = await widgetSchema(organization).create({ + widgetID: widget.id, + elementType: widget.type, + // widgetOrder: widgetOrder, + widgetName: widget.widgetName, + panelID: existingPanel._id, + widgetside: widget.panel, + // Data: { + // measurements: widget.Data.measurements || {}, + // duration: widget.Data.duration || "1hr", + // }, + }); + if (newWidget) { + existingPanel.widgets.push(newWidget._id); + await existingPanel.save(); + return { success: true, message: "Widget already exist for the widgetID",data:existingPanel,organization: organization} + } + } + return { success: false, message: "Type mismatch",organization: organization} + + } catch (error: any) { + return { success: false, message: 'widge not found', error,organization: organization } + } +} +export const Widgetdelete = async (data: any) => { + const { widgetID, organization } = data + console.log('data: ', data); + try { + const findWidget = await widgetSchema(organization).findOne({ + widgetID: widgetID, + isArchive: false, + }); + if (!findWidget) + return { success: false, message: "Widget not found",organization: organization} + const widgetData = await widgetSchema(organization).updateOne( + { _id: findWidget._id, isArchive: false }, + { $set: { isArchive: true } } + ); + + if (widgetData) { + // Find all widgets in the same panel and sort them by widgetOrder + const widgets = await widgetSchema(organization).find({ + panelID: findWidget.panelID, + isArchive: false, + }); + // .sort({ widgetOrder: 1 }); + + // Reassign widgetOrder values + // for (let i = 0; i < widgets.length; i++) { + // widgets[i].widgetOrder = (i + 1).toString(); // Convert to string + // await widgets[i].save(); + // } + const panelData = await panelSchema(organization).findOne({ + _id: findWidget.panelID, + isArchive: false, + }); + if (panelData.widgets.includes(findWidget._id)) { + const index1 = panelData.widgets.indexOf(findWidget._id); + panelData.widgets.splice(index1, 1); + } + const panelDeletedata = await panelData.save(); + console.log('Widget deleted successfully: '); + return { success: false, message: "Widget deleted successfully",data:panelDeletedata,organization: organization} + + } + + } catch (error: any) { + return { success: false, message: error?.message || "An unknown error occurred.", error ,organization: organization} + } +} \ No newline at end of file diff --git a/src/socket-server/socket/events.ts b/src/socket-server/socket/events.ts index 4558cff..86b7540 100644 --- a/src/socket-server/socket/events.ts +++ b/src/socket-server/socket/events.ts @@ -47,30 +47,4 @@ export const EVENTS = { zoneUpdateRespones:"zone:response:updates", deleteZone:"v2:zone:delete", ZoneDeleteRespones:"zone:response:delete", - - //visualization - addPanel:"v2:viz-panel:add", - panelUpdateRespones:"viz-panel:response:updates", - deletePanel:"v2:viz-panel:delete", - PanelDeleteRespones:"viz-panel:response:delete", - - //widget - addWidget:"v2:viz-widget:add", - widgetUpdateRespones:"viz-widget:response:updates", - deleteWidget:"v2:viz-widget:delete", - widgetDeleteRespones:"viz-widget:response:delete", - - //float - addFloat: "v2:viz-float:add", - floatUpdateRespones: "viz-float:response:updates", - deleteFloat: "v2:viz-float:delete", - floatDeleteRespones: "viz-float:response:delete", - - //template - addTemplate:"v2:viz-template:add", - templateUpdateRespones:"viz-template:response:updates", - - //model-asset - setAssetModel: "v2:model-asset:add", - assetUpdateRespones: "model-asset:response:updates", } \ No newline at end of file diff --git a/src/socket-server/socket/socketManager.ts b/src/socket-server/socket/socketManager.ts index 581afe0..6a03d85 100644 --- a/src/socket-server/socket/socketManager.ts +++ b/src/socket-server/socket/socketManager.ts @@ -1,12 +1,14 @@ import { Server, Socket } from 'socket.io'; -import { EVENTS } from './events'; -import { createCamera } from '../services/camera/camera-Controller'; -import { setEnvironment } from '../services/environments/environments-controller'; -import { deleteFloorItems, setFloorItems } from '../services/assets/flooritem-Controller'; -import { deleteWallItems, setWallItems } from '../services/assets/wallitem-Controller'; -import { deleteLineItems, deleteLinPoiteItems, updateLineItems ,createLineItems, deleteLayer} from '../services/lines/line-Controller'; -import { activeUserOffline, activeUsers } from '../services/users/user-controller'; -import { deleteZone, setZone } from '../services/lines/zone-controller'; +import { EVENTS } from './events.ts'; +import { createCamera } from '../services/camera/camera-Controller.ts'; +import { setEnvironment } from '../services/environments/environments-controller.ts'; +import { deleteFloorItems, setFloorItems } from '../services/assets/flooritem-Controller.ts'; +import { deleteWallItems, setWallItems } from '../services/assets/wallitem-Controller.ts'; +import { deleteLineItems, deleteLinPoiteItems, updateLineItems ,createLineItems, deleteLayer} from '../services/lines/line-Controller.ts'; +import { activeUserOffline, activeUsers } from '../services/users/user-controller.ts'; +import { deleteZone, setZone } from '../services/lines/zone-controller.ts'; +import { addPanel, panelDelete } from '../services/visualization/panel-Services.ts'; +import { addWidget, Widgetdelete } from '../services/visualization/widget-Services.ts'; @@ -449,6 +451,142 @@ switch (event) { break; } } +const panelHandleEvent=async(event: string, socket: Socket, data: any,namespace: any, notifySender: boolean = false)=>{ + if (!data?.organization) { + console.warn(`Missing organization for event: ${event}`); + return; + } + + let result; + switch (event) { + case EVENTS.addPanel:{ + result = await addPanel(data); + console.log('result: ', result); + + if (result) { + console.log('result?.success: ', result.organization); + const responseEvent = EVENTS.panelUpdateRespones + console.log('responseEvent: ', responseEvent); + const organization=result?.organization + console.log('organization: ', organization); + // const emitTarget = notifySender ? socket.in(organization) : socket.to(organization); + // console.log(`👀 Active sockets in room:`, namespace.adapter.rooms.get(organization)); + // console.log('emitTarget: ', emitTarget); + + socket.to(organization).emit(responseEvent, { + success: result.success, + message: result.message, + data: result.data, + error: result.error, + socketId: socket.id, + organization: result.organization, + }); + } + break;} + case EVENTS.deletePanel: { + const result = await panelDelete(data) + if (result) { + // console.log('result?.success: ', result.organization); + const responseEvent = EVENTS.PanelDeleteRespones + // console.log('responseEvent: ', responseEvent); + const organization = result?.organization + // console.log('organization: ', organization); + // const emitTarget = notifySender ? socket.in(organization) : socket.to(organization); + // console.log(`👀 Active sockets in room:`, namespace.adapter.rooms.get(organization)); + // console.log('emitTarget: ', emitTarget); + if (organization) { + socket.emit(responseEvent, { + success: result.success, + message: result.message, + data: result.data, + error: result.error || null, + socketId: socket.id, + organization, + }); + } else { + console.warn(`Organization missing in response for event: ${event}`); + } + } + break + } + + + default: + return; + } + + + } +const widgetHandleEvent = async (event: string, socket: Socket, data: any, namespace: any, notifySender: boolean = false) => { + // console.log('data: ', data); + if (!data?.organization) { + console.warn(`Missing organization for event: ${event}`); + return; + } + + let result; + switch (event) { + case EVENTS.addWidget: { + result = await addWidget(data); + // console.log('result: ', result); + + if (result) { + // console.log('result?.success: ', result.organization); + const responseEvent = EVENTS.widgetUpdateRespones + // console.log('responseEvent: ', responseEvent); + const organization = result?.organization + // console.log('organization: ', organization); + // const emitTarget = notifySender ? socket.in(organization) : socket.to(organization); + // console.log(`👀 Active sockets in room:`, namespace.adapter.rooms.get(organization)); + // console.log('emitTarget: ', emitTarget); + if (organization) { + socket.to(organization).emit(responseEvent, { + success: result.success, + message: result.message, + data: result.data, + error: result.error || null, + socketId: socket.id, + organization, + }); + } else { + console.warn(`Organization missing in response for event: ${event}`); + } + } + break + } + case EVENTS.deleteWidget: { + const result = await Widgetdelete(data) + if (result) { + // console.log('result?.success: ', result.organization); + const responseEvent = EVENTS.widgetDeleteRespones + // console.log('responseEvent: ', responseEvent); + const organization = result?.organization + // console.log('organization: ', organization); + // const emitTarget = notifySender ? socket.in(organization) : socket.to(organization); + // console.log(`👀 Active sockets in room:`, namespace.adapter.rooms.get(organization)); + // console.log('emitTarget: ', emitTarget); + if (organization) { + socket.emit(responseEvent, { + success: result.success, + message: result.message, + data: result.data, + error: result.error || null, + socketId: socket.id, + organization, + }); + } else { + console.warn(`Organization missing in response for event: ${event}`); + } + } + break + } + + default: + return; + } + +} + export const initSocketServer = (httpServer: any) => { const io = new Server(httpServer, { @@ -458,6 +596,7 @@ export const initSocketServer = (httpServer: any) => { }, }); + // Listen for new connections io.on(EVENTS.connection, (socket: Socket) => { // console.log(`New client connected: ${socket.id}`); @@ -483,62 +622,5 @@ userStatus(EVENTS.connection, socket, socket.handshake.auth,io); }); }); - // 🔹 Create different namespaces - const namespaces = { - camera: io.of("/camera"), - environment: io.of("/environment"), - floorItems: io.of("/floorItems"), - wallItems: io.of("/wallItems"), - line: io.of("/line"), - zone: io.of("/zone"), - Builder: io.of('/Builder'), - visualization: io.of('/visualization'), - // widget:io.of('/widget') - }; - // 🔹 Function to handle connections in a namespace - const handleNamespace = (namespaceName: string, namespace: any, ...eventHandlers: Function[]) => { - namespace.on("connection", (socket: Socket) => { - console.log(`✅ Client connected to ${namespaceName}: ${socket.id}`); - - // Extract organization from query parameters - // const organization = socket.handshake.query.organization as string; - const organization = socket.handshake.auth.organization as string; - console.log(`🔍 Received organization: ${organization}`); - - if (organization) { - socket.join(organization); - // console.log(`🔹 Socket ${socket.id} joined room: ${organization}`); - - // Debug: Check rooms - // console.log(`🛠️ Current rooms for ${socket.id}:`, socket.rooms); - } else { - console.warn(`⚠️ Warning: Socket ${socket.id} did not provide an organization`); - } - - socket.onAny((event: string, data: any) => { - // console.log(`📩 Event received: ${event}, Data: ${JSON.stringify(data)}`); - eventHandlers.forEach(handler => handler(event, socket, data, namespace)); - // eventHandler(event, socket, data, namespace); // Pass `namespace` instead of `io` - }); - - socket.on("disconnect", (reason: string) => { - console.log(`❌ Client disconnected from ${namespaceName}: ${socket.id}, Reason: ${reason}`); - }); - }); - }; - - // 🔹 Apply namespace handlers - // handleNamespace("camera", namespaces.camera, cameraHandleEvent); - // handleNamespace("environment", namespaces.environment, EnvironmentHandleEvent); - // handleNamespace("floorItems", namespaces.floorItems, floorItemsHandleEvent); - // handleNamespace("wallItems", namespaces.wallItems, wallItemsHandleEvent); - handleNamespace("line", namespaces.line, lineHandleEvent); - handleNamespace("zone", namespaces.zone, zoneHandleEvent); - // handleNamespace("visualization", namespaces.panel, panelHandleEvent); - // handleNamespace("widget", namespaces.visualization, widgetHandleEvent); - // handleNamespace("Builder", namespaces.Builder, modelAssetHandleEvent,cameraHandleEvent,EnvironmentHandleEvent,wallItemsHandleEvent,lineHandleEvent); - // handleNamespace("visualization", namespaces.visualization, panelHandleEvent, widgetHandleEvent,floatHandleEvent,templateHandleEvent); - - return io; }; diff --git a/tsconfig.json b/tsconfig.json index d7bd47c..6cc49ca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,9 +11,10 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "libReplacement": true, /* Enable lib replacement. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ @@ -25,17 +26,18 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "NodeNext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "NodeNext", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + "typeRoots": ["node_modules/@types"], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": ["node"], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ @@ -55,7 +57,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ + "noEmit": true, /* Disable emitting files from a compilation. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ // "outDir": "./", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ @@ -76,6 +78,7 @@ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */