diff --git a/package-lock.json b/package-lock.json index bc6d21c..1c85ff9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,8 @@ "nodemailer": "^7.0.3", "socket.io": "^4.8.1", "swagger-autogen": "^2.23.7", - "swagger-ui-express": "^5.0.1" + "swagger-ui-express": "^5.0.1", + "yjs": "^13.6.27" }, "devDependencies": { "@types/bcryptjs": "^3.0.0", @@ -1446,6 +1447,15 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "node_modules/isomorphic.js": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", + "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1510,6 +1520,26 @@ "node": ">=12.0.0" } }, + "node_modules/lib0": { + "version": "0.2.108", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.108.tgz", + "integrity": "sha512-+3eK/B0SqYoZiQu9fNk4VEc6EX8cb0Li96tPGKgugzoGj/OdRdREtuTLvUW+mtinoB2mFiJjSqOJBIaMkAGhxQ==", + "dependencies": { + "isomorphic.js": "^0.2.4" + }, + "bin": { + "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", + "0gentesthtml": "bin/gentesthtml.js", + "0serve": "bin/0serve.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2849,6 +2879,22 @@ "node": ">=0.4" } }, + "node_modules/yjs": { + "version": "13.6.27", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.27.tgz", + "integrity": "sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==", + "dependencies": { + "lib0": "^0.2.99" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 29bba9f..75b26d7 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "nodemailer": "^7.0.3", "socket.io": "^4.8.1", "swagger-autogen": "^2.23.7", - "swagger-ui-express": "^5.0.1" + "swagger-ui-express": "^5.0.1", + "yjs": "^13.6.27" }, "devDependencies": { "@types/bcryptjs": "^3.0.0", diff --git a/src/api-server/Dockerfile b/src/api-server/Dockerfile index 96c6e73..3b05bce 100644 --- a/src/api-server/Dockerfile +++ b/src/api-server/Dockerfile @@ -23,7 +23,7 @@ USER appuser COPY . . # Expose the port that the application listens on. -EXPOSE 4999 +EXPOSE 3503 # Run the application. diff --git a/src/api-server/V1/v1Controllers/authController/authControllers.ts b/src/api-server/V1/v1Controllers/authController/authControllers.ts index 6ffed94..e162677 100644 --- a/src/api-server/V1/v1Controllers/authController/authControllers.ts +++ b/src/api-server/V1/v1Controllers/authController/authControllers.ts @@ -1,6 +1,7 @@ import { Request, Response } from "express"; import { AuthLogin, + AuthLogins, AuthLogout, AuthSignup, forgetPassword, @@ -12,7 +13,6 @@ export const SignupController = async ( ): Promise => { try { const { userName, Email, Password } = req.body; - console.log('req.body: ', req.body); if (!userName || !Email || !Password) { res.status(400).json({ message: "All fields are required", @@ -20,7 +20,6 @@ export const SignupController = async ( return; } const result = await AuthSignup(req.body); - console.log('result: ', result); switch (result.status) { case "User already exists": @@ -78,7 +77,6 @@ export const SignInController = async ( ForceLogoutData: result.data, }); break; - case "User_Datas not found": res.status(404).json({ message: "User_Datas not found", @@ -245,3 +243,69 @@ export const ResetPasswordController = async ( return; } }; + + +// export const SignInController = async ( +// req: Request, +// res: Response +// ): Promise => { +// try { +// const { Email, Password, fingerprint } = req.body; +// if (!fingerprint || !Email || !Password) { +// res.status(400).json({ +// message: "All fields are required", +// }); +// return; +// } +// const result = await AuthLogins(req.body); + +// switch (result.status) { +// case "User Not Found!!! Kindly signup...": +// res.status(404).json({ +// message: "User Not Found!!! Kindly signup...", +// }); +// break; +// case "Email & Password is invalid...Check the credentials": +// res.status(400).json({ +// message: "Email & Password is invalid...Check the credentials", +// }); +// break; +// // case "Already LoggedIn on another browser....Please logout!!!": +// // res.status(403).json({ +// // message: "Already LoggedIn on another browser....Please logout!!!", +// // ForceLogoutData: result.data, +// // }); +// // break; +// case "Already LoggedIn on another browser....ForceLogout Implemented!!!": +// res.status(200).json({ +// message: result.data +// }); +// break; +// case "User_Datas not found": +// res.status(404).json({ +// message: "User_Datas not found", +// }); +// break; +// case "User update failed.": +// res.status(400).json({ +// message: "User update failed.", +// }); +// break; +// case "Success": +// res.status(200).json({ +// message: result.data, +// }); +// break; +// default: +// res.status(500).json({ +// message: "Internal server error", +// }); +// break; +// } +// } catch (error) { +// res.status(500).json({ +// message: "An unexpected error occurred", +// }); +// return; +// } +// }; \ No newline at end of file diff --git a/src/api-server/V1/v1Controllers/builderController/v1AisleController.ts b/src/api-server/V1/v1Controllers/builderController/v1AisleController.ts index 63d0758..7b78363 100644 --- a/src/api-server/V1/v1Controllers/builderController/v1AisleController.ts +++ b/src/api-server/V1/v1Controllers/builderController/v1AisleController.ts @@ -12,8 +12,8 @@ export const UpsertAisleController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { aisleUuid, points, type, projectId } = req.body; - if (!organization || !userId || !aisleUuid || !projectId) { + const { aisleUuid, points, type, projectId, versionId } = req.body; + if (!organization || !userId || !aisleUuid || !projectId || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -24,6 +24,7 @@ export const UpsertAisleController = async ( type, aisleUuid, projectId, + versionId, organization, userId, }; @@ -39,6 +40,11 @@ export const UpsertAisleController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Aisle Not Updated": res.status(200).json({ message: "Aisle Not Updated", @@ -83,8 +89,8 @@ export const DeleteAisleController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { aisleUuid, projectId } = req.body; - if (!organization || !userId || !aisleUuid || !projectId) { + const { aisleUuid, projectId, versionId } = req.body; + if (!organization || !userId || !aisleUuid || !projectId || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -95,6 +101,7 @@ export const DeleteAisleController = async ( projectId, organization, userId, + versionId, }; const result = await DeleteAisle(data); switch (result.status) { @@ -108,6 +115,11 @@ export const DeleteAisleController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Aisle not found": res.status(200).json({ message: "Aisle not found", @@ -136,7 +148,7 @@ export const AllAisleController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId } = req.params; + const { projectId, versionId } = req.params; if (!organization || !userId || !projectId) { res.status(400).json({ message: "All fields are required", @@ -145,6 +157,7 @@ export const AllAisleController = async ( } const data = { projectId, + versionId, organization, userId, }; @@ -160,6 +173,11 @@ export const AllAisleController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Aisle not found": res.status(200).json(result.data); break; diff --git a/src/api-server/V1/v1Controllers/builderController/v1LineController.ts b/src/api-server/V1/v1Controllers/builderController/v1LineController.ts index b5db8d6..9522c4c 100644 --- a/src/api-server/V1/v1Controllers/builderController/v1LineController.ts +++ b/src/api-server/V1/v1Controllers/builderController/v1LineController.ts @@ -15,8 +15,16 @@ export const NewLineController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { line, type, layer, projectId } = req.body; - if (!organization || !userId || !line || !type || !layer || !projectId) { + const { line, type, layer, projectId, versionId } = req.body; + if ( + !organization || + !userId || + !line || + !type || + !layer || + !projectId || + !versionId + ) { res.status(400).json({ message: "All fields are required", }); @@ -28,6 +36,7 @@ export const NewLineController = async ( layer, projectId, organization, + versionId, userId, }; const result = await CreateLineItems(data); @@ -43,6 +52,11 @@ export const NewLineController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Success": res.status(201).json(result.data); break; @@ -64,8 +78,15 @@ export const UpdateLineController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { uuid, position, projectId } = req.body; - if (!organization || !userId || !uuid || !position || projectId) { + const { uuid, position, projectId, versionId } = req.body; + if ( + !organization || + !userId || + !uuid || + !position || + projectId || + !versionId + ) { res.status(400).json({ message: "All fields are required", }); @@ -74,6 +95,7 @@ export const UpdateLineController = async ( const result = await UpdateLineItems({ organization, projectId, + versionId, uuid, position, userId, @@ -90,8 +112,13 @@ export const UpdateLineController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Success": - res.status(201).json(result.data); + res.status(200).json(result.data); break; default: res.status(500).json({ @@ -111,8 +138,8 @@ export const DeleteLineController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId, line } = req.body; - if (!organization || !userId || !projectId || !line) { + const { projectId, line, versionId } = req.body; + if (!organization || !userId || !projectId || !line || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -121,6 +148,7 @@ export const DeleteLineController = async ( const result = await DeleteLineItems({ organization, projectId, + versionId, line, userId, }); @@ -136,6 +164,11 @@ export const DeleteLineController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "line not found": res.status(404).json({ message: "data not found", @@ -162,8 +195,8 @@ export const DeleteLayerController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId, layer } = req.body; - if (!organization || !userId || !projectId || !layer) { + const { projectId, layer, versionId } = req.body; + if (!organization || !userId || !projectId || !layer || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -172,6 +205,7 @@ export const DeleteLayerController = async ( const result = await DeleteLayer({ organization, projectId, + versionId, layer, userId, }); @@ -187,6 +221,11 @@ export const DeleteLayerController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "layer not found": res.status(404).json({ message: "data not found", @@ -214,8 +253,8 @@ export const DeleteLinePointsController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId, uuid } = req.body; - if (!organization || !userId || !projectId || !uuid) { + const { projectId, uuid, versionId } = req.body; + if (!organization || !userId || !projectId || !uuid || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -223,6 +262,7 @@ export const DeleteLinePointsController = async ( } const result = await DeleteLinePoints({ organization, + versionId, projectId, uuid, userId, @@ -239,6 +279,11 @@ export const DeleteLinePointsController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Line not found": res.status(404).json({ message: "data not found", @@ -265,7 +310,7 @@ export const GetLinesController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId } = req.params; + const {versionId, projectId } = req.params; if (!organization || !userId || !projectId) { res.status(400).json({ message: "All fields are required", @@ -274,7 +319,7 @@ export const GetLinesController = async ( } const result = await GetLinesService({ organization, - projectId, + projectId,versionId, userId, }); @@ -289,6 +334,11 @@ export const GetLinesController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Line not found": res.status(200).json(result.data); break; diff --git a/src/api-server/V1/v1Controllers/builderController/v1assetController.ts b/src/api-server/V1/v1Controllers/builderController/v1assetController.ts index 5fc56db..631d46f 100644 --- a/src/api-server/V1/v1Controllers/builderController/v1assetController.ts +++ b/src/api-server/V1/v1Controllers/builderController/v1assetController.ts @@ -25,13 +25,9 @@ export const CreateAssetController = async ( isLocked, isVisible, projectId, + versionId, } = req.body; - if ( - !organization || - !userId || - !projectId || - !modelUuid - ) { + if (!organization || !userId || !projectId || !modelUuid || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -49,6 +45,7 @@ export const CreateAssetController = async ( isLocked, isVisible, projectId, + versionId, }; const result = await setAssetModel(data); @@ -63,6 +60,11 @@ export const CreateAssetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Updated successfully": res.status(200).json(result.data); break; @@ -89,8 +91,15 @@ export const DeleteAssetController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { modelUuid, modelName, projectId } = req.body; - if (!organization || !userId || !modelUuid || !projectId || !modelName) { + const { modelUuid, modelName, projectId, versionId } = req.body; + if ( + !organization || + !userId || + !modelUuid || + !projectId || + !modelName || + !versionId + ) { res.status(400).json({ message: "All fields are required", }); @@ -101,6 +110,7 @@ export const DeleteAssetController = async ( modelName, modelUuid, projectId, + versionId, userId, }); @@ -115,6 +125,11 @@ export const DeleteAssetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "model not found": res.status(404).json({ message: "Model not found", @@ -148,7 +163,7 @@ export const GetAssetController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId } = req.params; + const { projectId,versionId } = req.params; if (!organization || !userId || !projectId) { res.status(400).json({ message: "All fields are required", @@ -158,7 +173,7 @@ export const GetAssetController = async ( const result = await getFloorItems({ organization, projectId, - userId, + userId,versionId, }); switch (result.status) { @@ -172,6 +187,11 @@ export const GetAssetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "floorItems not found": res.status(200).json([]); break; @@ -196,8 +216,15 @@ export const ReplaceEventDataController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { modelUuid, eventData, projectId } = req.body; - if (!organization || !userId || !projectId || !modelUuid || !eventData) { + const { modelUuid, eventData, projectId, versionId } = req.body; + if ( + !organization || + !userId || + !projectId || + !modelUuid || + !versionId || + !eventData + ) { res.status(400).json({ message: "All fields are required", }); @@ -207,6 +234,7 @@ export const ReplaceEventDataController = async ( modelUuid, organization, eventData, + versionId, projectId, userId, }); @@ -222,6 +250,11 @@ export const ReplaceEventDataController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Model not for this UUID": res.status(404).json({ message: "Model not for this UUID", @@ -256,6 +289,7 @@ export const AssetUpdatePosRotController = async ( isLocked, isVisible, projectId, + versionId, } = req.body; if ( !organization || @@ -266,6 +300,7 @@ export const AssetUpdatePosRotController = async ( !rotation || !modelName || !projectId || + !versionId || !modelUuid ) { res.status(400).json({ @@ -283,6 +318,7 @@ export const AssetUpdatePosRotController = async ( isLocked, isVisible, projectId, + versionId, }); switch (result.status) { @@ -296,6 +332,11 @@ export const AssetUpdatePosRotController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Asset not found": res.status(404).json({ message: "Asset not found", diff --git a/src/api-server/V1/v1Controllers/builderController/v1cameraController.ts b/src/api-server/V1/v1Controllers/builderController/v1cameraController.ts index a189e03..7db2777 100644 --- a/src/api-server/V1/v1Controllers/builderController/v1cameraController.ts +++ b/src/api-server/V1/v1Controllers/builderController/v1cameraController.ts @@ -13,13 +13,14 @@ export const SetNewCamera = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { position, target, rotation, projectId } = req.body; + const { position, target, rotation, projectId,versionId } = req.body; if ( !organization || !userId || !position || !target || !rotation || + !versionId || !projectId ) { res.status(400).json({ @@ -32,7 +33,7 @@ export const SetNewCamera = async ( target, rotation, projectId, - organization, + organization,versionId, userId, }; const result = await SetCamera(data); @@ -48,7 +49,11 @@ export const SetNewCamera = async ( message: "Project not found", }); break; - + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Update Success": res.status(200).json(result.data); break; diff --git a/src/api-server/V1/v1Controllers/builderController/v1wallController.ts b/src/api-server/V1/v1Controllers/builderController/v1wallController.ts index 3b644aa..9478ae6 100644 --- a/src/api-server/V1/v1Controllers/builderController/v1wallController.ts +++ b/src/api-server/V1/v1Controllers/builderController/v1wallController.ts @@ -16,27 +16,16 @@ export const WallSetup = async ( modelUuid, modelName, position, - type, assetId, + type, csgposition, csgscale, quaternion, scale, projectId, + versionId, } = req.body; - if ( - !modelUuid || - !modelName || - !position || - !type || - !projectId || - !csgscale || - !csgposition || - !quaternion || - !scale || - !organization || - !userId - ) { + if (!modelUuid || !organization || !userId || !projectId || !versionId) { res.status(400).json({ message: "All fields are required!", }); @@ -44,17 +33,18 @@ export const WallSetup = async ( } const result = await setWallItems({ projectId, + versionId, modelUuid, modelName, position, type, - assetId, csgposition, csgscale, quaternion, scale, organization, userId, + assetId, }); switch (result.status) { case "User not found": @@ -67,10 +57,15 @@ export const WallSetup = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Updated successfully": res.status(200).json(result.data); break; - case "wall Item created successfully": + case "Success": res.status(201).json(result.data); break; default: @@ -90,7 +85,7 @@ export const WallGet = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId } = req.params; + const { versionId, projectId } = req.params; if (!organization || !userId || !projectId) { res.status(400).json({ message: "All fields are required", @@ -101,6 +96,7 @@ export const WallGet = async ( organization, userId, projectId, + versionId, }); switch (result.status) { @@ -114,6 +110,11 @@ export const WallGet = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "wallitems not found": res.status(200).json(result.data); break; @@ -138,8 +139,15 @@ export const WallDelete = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId, modelName, modelUuid } = req.body; - if (!organization || !userId || !projectId || !modelName || !modelUuid) { + const { projectId, versionId, modelName, modelUuid } = req.body; + if ( + !organization || + !userId || + !projectId || + !modelName || + !versionId || + !modelUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -149,6 +157,7 @@ export const WallDelete = async ( organization, userId, projectId, + versionId, modelName, modelUuid, }); @@ -164,6 +173,11 @@ export const WallDelete = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "model not found": res.status(404).json({ message: "model not found", diff --git a/src/api-server/V1/v1Controllers/builderController/v1zoneController.ts b/src/api-server/V1/v1Controllers/builderController/v1zoneController.ts index 41330f7..0f762c4 100644 --- a/src/api-server/V1/v1Controllers/builderController/v1zoneController.ts +++ b/src/api-server/V1/v1Controllers/builderController/v1zoneController.ts @@ -15,8 +15,8 @@ export const CreateZoneController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { zoneData, projectId } = req.body; - if (!organization || !userId || !zoneData || !projectId) { + const { zoneData, projectId, versionId } = req.body; + if (!organization || !userId || !zoneData || !projectId || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -25,6 +25,7 @@ export const CreateZoneController = async ( const data = { zoneData, projectId, + versionId, organization, userId, }; @@ -41,6 +42,11 @@ export const CreateZoneController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "zone updated": res.status(200).json({ message: "zone updated", @@ -71,8 +77,8 @@ export const DeleteZoneController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { zoneUuid, projectId } = req.body; - if (!organization || !userId || !zoneUuid || !projectId) { + const { zoneUuid, projectId, versionId } = req.body; + if (!organization || !userId || !zoneUuid || !projectId || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -82,6 +88,7 @@ export const DeleteZoneController = async ( organization, zoneUuid, projectId, + versionId, userId, }); @@ -96,6 +103,11 @@ export const DeleteZoneController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Invalid zone ID": res.status(404).json({ message: "Zone not found for the UUID", @@ -124,7 +136,7 @@ export const GetZoneController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId } = req.params; + const { projectId, versionId } = req.params; if (!organization || !userId || !projectId) { res.status(400).json({ message: "All fields are required", @@ -135,6 +147,7 @@ export const GetZoneController = async ( organization, projectId, userId, + versionId, }); switch (result.status) { @@ -148,6 +161,11 @@ export const GetZoneController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Invalid zone": res.status(404).json({ message: "Zone not found for the UUID", @@ -174,7 +192,7 @@ export const VizZoneController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId } = req.params; + const { projectId, versionId } = req.params; if (!organization || !userId || !projectId) { res.status(400).json({ message: "All fields are required", @@ -184,6 +202,7 @@ export const VizZoneController = async ( const result = await VizZoneDatas({ organization, projectId, + versionId, userId, }); @@ -198,6 +217,11 @@ export const VizZoneController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the UUID": res.status(200).json(result.data); break; @@ -223,7 +247,7 @@ export const ZoneDataController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId, zoneUuid } = req.params; + const { projectId, zoneUuid, versionId } = req.params; if (!organization || !userId || !projectId || !zoneUuid) { res.status(400).json({ message: "All fields are required", @@ -234,6 +258,7 @@ export const ZoneDataController = async ( organization, projectId, userId, + versionId, zoneUuid, }); @@ -248,6 +273,11 @@ export const ZoneDataController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -274,7 +304,7 @@ export const SingleZonePanelController = async ( ): Promise => { try { const { organization, userId } = req.user || {}; - const { projectId, zoneUuid } = req.params; + const { versionId, projectId, zoneUuid } = req.params; if (!organization || !userId || !projectId || !zoneUuid) { res.status(400).json({ message: "All fields are required", @@ -285,6 +315,7 @@ export const SingleZonePanelController = async ( organization, projectId, userId, + versionId, zoneUuid, }); @@ -299,6 +330,11 @@ export const SingleZonePanelController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the UUID": res.status(404).json({ message: "Zone not found for the UUID", diff --git a/src/api-server/V1/v1Controllers/dummycontroller.ts/productdummycontroller.ts b/src/api-server/V1/v1Controllers/dummycontroller.ts/productdummycontroller.ts new file mode 100644 index 0000000..82399bc --- /dev/null +++ b/src/api-server/V1/v1Controllers/dummycontroller.ts/productdummycontroller.ts @@ -0,0 +1,396 @@ +import { Response } from "express"; +import { AuthenticatedRequest } from "../../../../shared/utils/token.ts"; +import { + AllProductDatas, + EventDataDelete, + getProductDatas, + productAdd, + productDataDelete, + productRename, +} from "../../../../shared/services/simulation/productService.ts"; +import { productAdddummy } from "../../../../shared/services/dummyservice.ts"; + +export const AddProductControllerdumy = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { productUuid, eventDatas, projectId, productName } = req.body; + + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if ( + !productUuid || + !productName || + !projectId || + !userId || + !organization + ) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await productAdddummy({ + productName, + productUuid, + eventDatas, + projectId, + userId, + organization, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "EventData updated successfully": + res.status(200).json({ + message: "EventData updated successfully", + }); + break; + case "EventData add successfully": + res.status(200).json({ + message: "EventData add successfully", + }); + break; + case "Success": + res.status(201).json({ + message: "Product created Successfully", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + return; + } +}; +export const GetProductEventDatas = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { productUuid, projectId } = req.query as { + productUuid: string; + projectId: string; + }; + + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!productUuid || !projectId || !userId || !organization) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await getProductDatas({ + productUuid, + projectId, + userId, + organization, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Product not found": + res.status(404).json({ + message: "Product not found", + }); + break; + case "Events not found": + res.status(200).json(result.data); + break; + case "Success": + res.status(200).json(result.data); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + return; + } +}; +export const DeleteProductController = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { productUuid, projectId } = req.body; + + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!productUuid || !projectId || !userId || !organization) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await productDataDelete({ + productUuid, + projectId, + userId, + organization, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Product not found": + res.status(404).json({ + message: "Product not found", + }); + break; + case "Success": + res.status(200).json({ + message: "Product Deleted Successfully", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + return; + } +}; +export const DeleteEventsController = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { productUuid, projectId, modelUuid } = req.body; + + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!productUuid || !projectId || !userId || !organization || !modelUuid) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await EventDataDelete({ + productUuid, + modelUuid, + projectId, + userId, + organization, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Product not found": + res.status(404).json({ + message: "Product not found", + }); + break; + case "Event Delete Unsuccessful": + res.status(200).json({ + message: "Event Delete Unsuccessful", + }); + break; + case "Success": + res.status(200).json({ + message: "Events Deleted Successfully", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + return; + } +}; +export const ProjectBasedProductsController = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId } = req.params; + + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !userId || !organization) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await AllProductDatas({ + projectId, + userId, + organization, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "No products found": + res.status(200).json(result.data); + break; + case "Success": + res.status(200).json(result.data); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + return; + } +}; +export const RenameProductController = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { productName, productUuid, projectId } = req.body; + + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if ( + !projectId || + !userId || + !organization || + !productName || + !productUuid + ) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await productRename({ + projectId, + productName, + productUuid, + userId, + organization, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Product not found": + res.status(404).json({ message: "Product not found" }); + break; + case "Rename Unsuccessful": + res.status(200).json({ message: "Product Rename Not Updated" }); + break; + case "Success": + res.status(200).json({ message: "Product Rename Successfull" }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + return; + } +}; diff --git a/src/api-server/V1/v1Controllers/simulationController/v1productController.ts b/src/api-server/V1/v1Controllers/simulationController/v1productController.ts index 180ad95..4248ef0 100644 --- a/src/api-server/V1/v1Controllers/simulationController/v1productController.ts +++ b/src/api-server/V1/v1Controllers/simulationController/v1productController.ts @@ -15,7 +15,8 @@ export const AddProductController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { productUuid, eventDatas, projectId, productName } = req.body; + const { productUuid, eventDatas, projectId, versionId, productName } = + req.body; if (!req.user?.userId || !req.user?.organization) { res.status(401).json({ message: "Unauthorized" }); @@ -25,6 +26,7 @@ export const AddProductController = async ( !productUuid || !productName || !projectId || + !versionId || !userId || !organization ) { @@ -38,6 +40,7 @@ export const AddProductController = async ( productUuid, eventDatas, projectId, + versionId, userId, organization, }); @@ -88,9 +91,10 @@ export const GetProductEventDatas = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { productUuid, projectId } = req.query as { + const { productUuid, projectId, versionId } = req.query as { productUuid: string; projectId: string; + versionId: string; }; if (!req.user?.userId || !req.user?.organization) { @@ -105,6 +109,7 @@ export const GetProductEventDatas = async ( } const result = await getProductDatas({ productUuid, + versionId, projectId, userId, organization, @@ -116,6 +121,11 @@ export const GetProductEventDatas = async ( message: "User not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Project not found": res.status(404).json({ @@ -152,13 +162,13 @@ export const DeleteProductController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { productUuid, projectId } = req.body; + const { productUuid, projectId, versionId } = req.body; if (!req.user?.userId || !req.user?.organization) { res.status(401).json({ message: "Unauthorized" }); return; } - if (!productUuid || !projectId || !userId || !organization) { + if (!productUuid || !projectId || !versionId || !userId || !organization) { res.status(400).json({ message: "All fields are required", }); @@ -167,6 +177,7 @@ export const DeleteProductController = async ( const result = await productDataDelete({ productUuid, projectId, + versionId, userId, organization, }); @@ -212,13 +223,20 @@ export const DeleteEventsController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { productUuid, projectId, modelUuid } = req.body; + const { productUuid, projectId, modelUuid, versionId } = req.body; if (!req.user?.userId || !req.user?.organization) { res.status(401).json({ message: "Unauthorized" }); return; } - if (!productUuid || !projectId || !userId || !organization || !modelUuid) { + if ( + !productUuid || + !projectId || + !versionId || + !userId || + !organization || + !modelUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -228,6 +246,7 @@ export const DeleteEventsController = async ( productUuid, modelUuid, projectId, + versionId, userId, organization, }); @@ -278,7 +297,7 @@ export const ProjectBasedProductsController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { projectId } = req.params; + const { projectId, versionId } = req.params; if (!req.user?.userId || !req.user?.organization) { res.status(401).json({ message: "Unauthorized" }); @@ -293,6 +312,7 @@ export const ProjectBasedProductsController = async ( const result = await AllProductDatas({ projectId, userId, + versionId, organization, }); @@ -308,6 +328,11 @@ export const ProjectBasedProductsController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "No products found": res.status(200).json(result.data); break; @@ -333,7 +358,7 @@ export const RenameProductController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { productName, productUuid, projectId } = req.body; + const { productName, productUuid, projectId, versionId } = req.body; if (!req.user?.userId || !req.user?.organization) { res.status(401).json({ message: "Unauthorized" }); @@ -341,6 +366,7 @@ export const RenameProductController = async ( } if ( !projectId || + !versionId || !userId || !organization || !productName || @@ -353,6 +379,7 @@ export const RenameProductController = async ( } const result = await productRename({ projectId, + versionId, productName, productUuid, userId, diff --git a/src/api-server/V1/v1Controllers/threadController/threadController.ts b/src/api-server/V1/v1Controllers/threadController/threadController.ts new file mode 100644 index 0000000..0f85d73 --- /dev/null +++ b/src/api-server/V1/v1Controllers/threadController/threadController.ts @@ -0,0 +1,346 @@ +import { Response } from "express"; +import { AuthenticatedRequest } from "../../../../shared/utils/token.ts"; +import { + addComments, + createThread, + deleteComments, + deleteThread, + findThreads, + updateThreadTitle, +} from "../../../../shared/services/Thread/ThreadService.ts"; +export const threadCreate = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId } = req.body; + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await createThread({ ...req.body, userId, organization }); + + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "CurrentVersion Data not found": + res.status(404).json({ + message: "CurrentVersion Data not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(201).json({ + message: "Thread created Successfully", + threadData: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const threaddelete = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId } = req.body; + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await deleteThread({ ...req.body, userId, organization }); + + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "CurrentVersion Data not found": + res.status(404).json({ + message: "CurrentVersion Data not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(201).json({ + message: "Thread deleted Successfully", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const threadUpdateTitle = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId, threadId } = req.body; + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !threadId || !organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await updateThreadTitle({ + ...req.body, + userId, + organization, + }); + + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "CurrentVersion Data not found": + res.status(404).json({ + message: "CurrentVersion Data not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(201).json({ + message: "ThreadTitle updated Successfully", + data: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const threadComment = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId, threadId } = req.body; + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !threadId || !organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await addComments({ ...req.body, userId, organization }); + console.log("result: ", result); + + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "CurrentVersion Data not found": + res.status(404).json({ + message: "CurrentVersion Data not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "updated": + res.status(200).json({ + message: "Comment updated successfully", + data: result.data, + }); + break; + case "Success": + res.status(201).json({ + message: "Thread comments add Successfully", + data: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const threadCommentDelete = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId, threadId, commentId } = req.body; + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !commentId || !threadId || !organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await deleteComments({ ...req.body, userId, organization }); + + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "CurrentVersion Data not found": + res.status(404).json({ + message: "CurrentVersion Data not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "thread not found": + res.status(404).json({ + message: "thread not found", + }); + break; + case "unauthorized": + res.status(404).json({ + message: "You can only delete your own comment.", + }); + break; + case "Success": + res.status(201).json({ + message: "Thread comment deleted Successfully", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const getALLthreads = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { userId, organization } = req.user || {}; + const { projectId } = req.params; + if (!req.user?.userId || !req.user?.organization) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + if (!projectId || !organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await findThreads({ projectId, userId, organization }); + + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "CurrentVersion Data not found": + res.status(404).json({ + message: "CurrentVersion Data not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(201).json({ + data: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; diff --git a/src/api-server/V1/v1Controllers/versionController/versioncontroller.ts b/src/api-server/V1/v1Controllers/versionController/versioncontroller.ts index a288614..c6002c4 100644 --- a/src/api-server/V1/v1Controllers/versionController/versioncontroller.ts +++ b/src/api-server/V1/v1Controllers/versionController/versioncontroller.ts @@ -1,24 +1,224 @@ import { Request, Response } from "express"; -import versionService from "../../../../shared/services/version/versionService.ts"; +import { + CreateVersion, + GetVersionById, + RollBackversion, + VersionHistory, +} from "../../../../shared/services/version/versionService.ts"; +import { AuthenticatedRequest } from "../../../../shared/utils/token.ts"; -export const versioncontroller = async ( - req: Request, +export const versionAddcontroller = async ( + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { projectId, userId, description, db } = req.body; + const { organization, role, userId } = req.user || {}; + if (!organization || !role || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const { projectId, versionName, hierarchyVersion, description, createdBy } = + req.body; - const result = await versionService.saveCurrentStateAsVersion( - db, + const result = await CreateVersion({ + organization, + hierarchyVersion, + createdBy, + versionName, projectId, userId, - description - ); - + description, + }); + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Parent Version not found": + res.status(404).json({ + message: "Parent Version not found", + }); + break; + case "Success": + res.status(200).json(result.data); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } } catch (error) { res.status(500).json({ - message: "An unexpected error occurred", + message: "Unknown error", + }); + } +}; + +export const GetversionList = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, role, userId } = req.user || {}; + if (!organization || !role || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const { projectId, versionId } = req.params; + const result = await GetVersionById({ + organization, + projectId, + versionId, + userId, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Version not found for the project": + res.status(200).json([]); + break; + case "Success": + res.status(200).json({ + versionDatas: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const rollbackcontroller = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, role, userId } = req.user || {}; + if (!organization || !role || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const { versionId, projectId } = req.body; + + const result = await RollBackversion({ + organization, + versionId, + projectId, + userId, + }); + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Mentioned Version not found for the Rollback": + res.status(404).json({ + message: "Mentioned Version not found for the Rollback", + }); + break; + case "Success": + res.status(200).json({ + message: "Rollback successfull", + versionId: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const GetversionHistory = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, role, userId } = req.user || {}; + if (!organization || !role || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const { projectId } = req.params; + const page = parseInt(req.query.page as string) || 1; + const limit = parseInt(req.query.limit as string) || 10; + const result = await VersionHistory({ + organization, + page, + limit, + projectId, + userId, + }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Versions not found": + res.status(200).json([]); + break; + case "Success": + res.status(200).json(result.data); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", }); - return; } }; diff --git a/src/api-server/V1/v1Controllers/vizualizationController/v1floatWidgetController.ts b/src/api-server/V1/v1Controllers/vizualizationController/v1floatWidgetController.ts index 8de6f59..f259d90 100644 --- a/src/api-server/V1/v1Controllers/vizualizationController/v1floatWidgetController.ts +++ b/src/api-server/V1/v1Controllers/vizualizationController/v1floatWidgetController.ts @@ -14,13 +14,13 @@ export const FloatAddController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { widget, zoneUuid, index, projectId } = req.body; + const { widget, zoneUuid, index, projectId, versionId } = req.body; if ( !userId || !organization || !widget || !zoneUuid || - !index || + !versionId || !projectId ) { res.status(400).json({ @@ -30,6 +30,7 @@ export const FloatAddController = async ( } const result = await AddFloat({ organization, + versionId, widget, zoneUuid, index, @@ -48,6 +49,11 @@ export const FloatAddController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found for the zoneUuid", @@ -87,8 +93,15 @@ export const DeleteFloatController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { floatWidgetID, projectId, zoneUuid } = req.body; - if (!userId || !organization || !floatWidgetID || !projectId || !zoneUuid) { + const { floatWidgetID, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !floatWidgetID || + !projectId || + !versionId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -98,6 +111,7 @@ export const DeleteFloatController = async ( organization, floatWidgetID, zoneUuid, + versionId, projectId, userId, }); @@ -112,6 +126,11 @@ export const DeleteFloatController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found for the zoneUuid", @@ -151,13 +170,14 @@ export const DuplicateFloatController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { widget, projectId, zoneUuid, index } = req.body; + const { widget, projectId, zoneUuid, index, versionId } = req.body; if ( !userId || !organization || !widget || !projectId || !zoneUuid || + !versionId || !index ) { res.status(400).json({ @@ -169,6 +189,7 @@ export const DuplicateFloatController = async ( organization, widget, zoneUuid, + versionId, index, projectId, userId, @@ -184,6 +205,11 @@ export const DuplicateFloatController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found for the zoneUuid", @@ -228,7 +254,7 @@ export const GetFloatController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { projectId, zoneUuid } = req.params; + const { projectId, zoneUuid,versionId } = req.params; if (!userId || !organization || !projectId || !zoneUuid) { res.status(400).json({ message: "All fields are required", @@ -236,7 +262,7 @@ export const GetFloatController = async ( return; } const result = await GetFloatWidget({ - organization, + organization,versionId, zoneUuid, projectId, userId, @@ -252,6 +278,11 @@ export const GetFloatController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", diff --git a/src/api-server/V1/v1Controllers/vizualizationController/v1panelController.ts b/src/api-server/V1/v1Controllers/vizualizationController/v1panelController.ts index 42b94fe..d04036e 100644 --- a/src/api-server/V1/v1Controllers/vizualizationController/v1panelController.ts +++ b/src/api-server/V1/v1Controllers/vizualizationController/v1panelController.ts @@ -13,8 +13,15 @@ export const AddPanelController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { panelOrder, zoneUuid, projectId } = req.body; - if (!userId || !organization || !panelOrder || !zoneUuid || !projectId) { + const { panelOrder, zoneUuid, projectId, versionId } = req.body; + if ( + !userId || + !organization || + !panelOrder || + !versionId || + !zoneUuid || + !projectId + ) { res.status(400).json({ message: "All fields are required", }); @@ -24,6 +31,7 @@ export const AddPanelController = async ( organization, panelOrder, zoneUuid, + versionId, projectId, userId, }); @@ -39,6 +47,11 @@ export const AddPanelController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -74,8 +87,15 @@ export const DeletePanelController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { panelName, projectId, zoneUuid } = req.body; - if (!userId || !organization || !panelName || !projectId || !zoneUuid) { + const { panelName, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !panelName || + !projectId || + !versionId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -86,6 +106,7 @@ export const DeletePanelController = async ( panelName, zoneUuid, projectId, + versionId, userId, }); switch (result.status) { @@ -99,6 +120,11 @@ export const DeletePanelController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -133,8 +159,15 @@ export const ClearPanelController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { panelName, projectId, zoneUuid } = req.body; - if (!userId || !organization || !panelName || !projectId || !zoneUuid) { + const { panelName, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !panelName || + !versionId || + !projectId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -145,6 +178,7 @@ export const ClearPanelController = async ( panelName, zoneUuid, projectId, + versionId, userId, }); switch (result.status) { @@ -158,6 +192,11 @@ export const ClearPanelController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -197,8 +236,15 @@ export const LockedPanelController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { projectId, zoneUuid, lockedPanel } = req.body; - if (!userId || !organization || !projectId || !zoneUuid || !lockedPanel) { + const { projectId, zoneUuid, lockedPanel, versionId } = req.body; + if ( + !userId || + !organization || + !projectId || + !versionId || + !zoneUuid || + !lockedPanel + ) { res.status(400).json({ message: "All fields are required", }); @@ -210,6 +256,7 @@ export const LockedPanelController = async ( lockedPanel, userId, projectId, + versionId, }); switch (result.status) { case "User not found": @@ -222,6 +269,11 @@ export const LockedPanelController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", diff --git a/src/api-server/V1/v1Controllers/vizualizationController/v1templateController.ts b/src/api-server/V1/v1Controllers/vizualizationController/v1templateController.ts index 76a55d6..ad56430 100644 --- a/src/api-server/V1/v1Controllers/vizualizationController/v1templateController.ts +++ b/src/api-server/V1/v1Controllers/vizualizationController/v1templateController.ts @@ -13,8 +13,8 @@ export const AddTemplateController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { template, projectId } = req.body; - if (!userId || !organization || !template || !projectId) { + const { template, projectId, versionId } = req.body; + if (!userId || !organization || !template || !projectId || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -25,6 +25,7 @@ export const AddTemplateController = async ( template, projectId, userId, + versionId, }); switch (result.status) { @@ -38,6 +39,11 @@ export const AddTemplateController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "TemplateID alreay exists": res.status(200).json({ message: "TemplateID alreay exists", @@ -72,8 +78,15 @@ export const AddTemToZoneController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { templateID, projectId, zoneUuid } = req.body; - if (!userId || !organization || !templateID || !projectId || !zoneUuid) { + const { templateID, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !templateID || + !versionId || + !projectId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -85,6 +98,7 @@ export const AddTemToZoneController = async ( zoneUuid, projectId, userId, + versionId, }); switch (result.status) { case "User not found": @@ -97,6 +111,11 @@ export const AddTemToZoneController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -132,8 +151,8 @@ export const TemplateDeleteController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { templateID, projectId } = req.body; - if (!userId || !organization || !templateID || !projectId) { + const { templateID, projectId, versionId } = req.body; + if (!userId || !organization || !templateID || !projectId || !versionId) { res.status(400).json({ message: "All fields are required", }); @@ -144,6 +163,7 @@ export const TemplateDeleteController = async ( organization, templateID, projectId, + versionId, }); switch (result.status) { case "User not found": @@ -156,6 +176,11 @@ export const TemplateDeleteController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Template not found": res.status(404).json({ message: "Template not found", @@ -190,7 +215,7 @@ export const GetTemplateController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { projectId } = req.params; + const { projectId,versionId } = req.params; if (!userId || !organization || !projectId) { res.status(400).json({ message: "All fields are required", @@ -199,7 +224,7 @@ export const GetTemplateController = async ( } const result = await GetAllTemplates({ organization, - userId, + userId,versionId, projectId, }); switch (result.status) { @@ -213,6 +238,11 @@ export const GetTemplateController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "All Datas": res.status(404).json([]); break; diff --git a/src/api-server/V1/v1Controllers/vizualizationController/v1widgetController.ts b/src/api-server/V1/v1Controllers/vizualizationController/v1widgetController.ts index 970530c..0c38a78 100644 --- a/src/api-server/V1/v1Controllers/vizualizationController/v1widgetController.ts +++ b/src/api-server/V1/v1Controllers/vizualizationController/v1widgetController.ts @@ -13,8 +13,15 @@ export const AddWidgetController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { widget, projectId, zoneUuid } = req.body; - if (!userId || !organization || !widget || !projectId || !zoneUuid) { + const { widget, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !widget || + !projectId || + !versionId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -26,6 +33,7 @@ export const AddWidgetController = async ( projectId, userId, zoneUuid, + versionId, }); switch (result.status) { @@ -39,6 +47,11 @@ export const AddWidgetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found", @@ -88,8 +101,15 @@ export const WidgetDeleteController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { widgetID, projectId, zoneUuid } = req.body; - if (!userId || !organization || !widgetID || !projectId || !zoneUuid) { + const { widgetID, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !widgetID || + !versionId || + !projectId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -101,6 +121,7 @@ export const WidgetDeleteController = async ( zoneUuid, projectId, userId, + versionId, }); switch (result.status) { case "User not found": @@ -113,6 +134,11 @@ export const WidgetDeleteController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found for the zoneUuid", @@ -147,13 +173,14 @@ export const WidgetUpdateController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { values, projectId, zoneUuid, widgetID } = req.body; + const { values, projectId, zoneUuid, widgetID, versionId } = req.body; if ( !userId || !organization || !widgetID || !values || !projectId || + !versionId || !zoneUuid ) { res.status(400).json({ @@ -168,6 +195,7 @@ export const WidgetUpdateController = async ( widgetID, projectId, userId, + versionId, }); switch (result.status) { case "User not found": @@ -180,6 +208,12 @@ export const WidgetUpdateController = async ( message: "Project not found", }); break; + + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found for the zoneUuid", @@ -214,8 +248,9 @@ export const GetWidgetController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { projectId, zoneUuid, widgetID } = req.query as { + const { projectId, zoneUuid, widgetID, versionId } = req.query as { projectId: string; + versionId: string; zoneUuid: string; widgetID: string; }; @@ -230,6 +265,7 @@ export const GetWidgetController = async ( zoneUuid, widgetID, projectId, + versionId, userId, }); switch (result.status) { @@ -243,6 +279,12 @@ export const GetWidgetController = async ( message: "Project not found", }); break; + + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(404).json({ message: "Zone not found for the zoneUuid", diff --git a/src/api-server/V1/v1Controllers/vizualizationController/widget3Dcontroller.ts b/src/api-server/V1/v1Controllers/vizualizationController/widget3Dcontroller.ts index 62f6cce..11e6bf7 100644 --- a/src/api-server/V1/v1Controllers/vizualizationController/widget3Dcontroller.ts +++ b/src/api-server/V1/v1Controllers/vizualizationController/widget3Dcontroller.ts @@ -13,8 +13,15 @@ export const Add3dWidgetController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { widget, projectId, zoneUuid } = req.body; - if (!userId || !organization || !widget || !projectId || !zoneUuid) { + const { widget, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !widget || + !projectId || + !versionId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -26,6 +33,7 @@ export const Add3dWidgetController = async ( userId, zoneUuid, projectId, + versionId, }); switch (result.status) { @@ -39,6 +47,11 @@ export const Add3dWidgetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found for the zoneUuid": res.status(200).json({ message: "Zone not found", @@ -83,7 +96,7 @@ export const Update3DwidgetController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { id, position, rotation, projectId, zoneUuid } = req.body; + const { id, position, rotation, projectId, zoneUuid, versionId } = req.body; if ( !userId || !organization || @@ -91,6 +104,7 @@ export const Update3DwidgetController = async ( !position || !rotation || !projectId || + !versionId || !zoneUuid ) { res.status(400).json({ @@ -106,6 +120,7 @@ export const Update3DwidgetController = async ( userId, zoneUuid, projectId, + versionId, }); switch (result.status) { case "User not found": @@ -118,6 +133,11 @@ export const Update3DwidgetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -157,8 +177,15 @@ export const Delete3DwidgetController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { id, projectId, zoneUuid } = req.body; - if (!userId || !organization || !id || !projectId || !zoneUuid) { + const { id, projectId, zoneUuid, versionId } = req.body; + if ( + !userId || + !organization || + !id || + !projectId || + !versionId || + !zoneUuid + ) { res.status(400).json({ message: "All fields are required", }); @@ -170,6 +197,7 @@ export const Delete3DwidgetController = async ( userId, zoneUuid, projectId, + versionId, }); switch (result.status) { case "User not found": @@ -182,6 +210,11 @@ export const Delete3DwidgetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", @@ -221,7 +254,7 @@ export const Get3DWidgetController = async ( ): Promise => { try { const { userId, organization } = req.user || {}; - const { projectId, zoneUuid } = req.params; + const { projectId, zoneUuid, versionId } = req.params; if (!userId || !organization || !projectId) { res.status(400).json({ message: "All fields are required", @@ -232,6 +265,7 @@ export const Get3DWidgetController = async ( organization, userId, zoneUuid, + versionId, projectId, }); switch (result.status) { @@ -245,6 +279,11 @@ export const Get3DWidgetController = async ( message: "Project not found", }); break; + case "Version Data not found": + res.status(404).json({ + message: "Version Data not found", + }); + break; case "Zone not found": res.status(404).json({ message: "Zone not found", diff --git a/src/api-server/V1/v1Controllers/yjsController/auto-saveControlle.ts b/src/api-server/V1/v1Controllers/yjsController/auto-saveControlle.ts new file mode 100644 index 0000000..c4ac9d1 --- /dev/null +++ b/src/api-server/V1/v1Controllers/yjsController/auto-saveControlle.ts @@ -0,0 +1,93 @@ +import { Response } from "express"; +import { AuthenticatedRequest } from "../../../../shared/utils/token.ts"; +import { restoreSnapshotService } from "../../../../shared/services/yjs/snapshot.ts"; +import { clearSnapshotController, restoreYDocFromAutoSave } from "../../../../shared/services/yjs/auto-save.ts"; + +export const autoSaveRestore = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, versionId, projectId, } = req.body; + if (!organization || !versionId ) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await restoreYDocFromAutoSave({ organization, versionId,projectId }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Snapshot not found": + res.status(404).json({ + message: "Snapshot not found", + + }); + break; + + case "Success": + res.status(200).json({ + AutoSave: result, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const clearAutoSaveRestore = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, versionId, projectId, } = req.body; + if (!organization || !versionId ) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await clearSnapshotController({ organization, versionId,projectId }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Snapshot not found": + res.status(404).json({ + message: "Snapshot not found", + + }); + break; + + case "Success": + res.status(200).json({ + message: "Snapshot autosave deleted", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; \ No newline at end of file diff --git a/src/api-server/V1/v1Controllers/yjsController/yjsSnapController.ts b/src/api-server/V1/v1Controllers/yjsController/yjsSnapController.ts new file mode 100644 index 0000000..0f3eea9 --- /dev/null +++ b/src/api-server/V1/v1Controllers/yjsController/yjsSnapController.ts @@ -0,0 +1,92 @@ +import { Response } from "express"; +import { AuthenticatedRequest } from "../../../../shared/utils/token.ts"; +import { listSnapshotService, restoreSnapshotService } from "../../../../shared/services/yjs/snapshot.ts"; + +export const SnapshotRestore = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, snapshotId, userId,ydoc } = req.body; + if (!organization || !snapshotId ) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await restoreSnapshotService({ organization, snapshotId,ydoc }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Snapshot not found": + res.status(404).json({ + message: "Snapshot not found", + + }); + break; + + case "Success": + res.status(200).json({ + Snapshot: result, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const SnapshotList = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { projectId, versionId, organization } = req.body; + if (!organization || !versionId ) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await listSnapshotService({ projectId, versionId, organization}); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Snapshot not found": + res.status(404).json({ + message: "Snapshot not found", + + }); + break; + + case "Success": + res.status(200).json({ + Snapshot: result, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; \ No newline at end of file diff --git a/src/api-server/V1/v1Routes/BuilderRoutes/V1-AisleRoutes.ts b/src/api-server/V1/v1Routes/BuilderRoutes/V1-AisleRoutes.ts index 16bd1d0..bbf13f6 100644 --- a/src/api-server/V1/v1Routes/BuilderRoutes/V1-AisleRoutes.ts +++ b/src/api-server/V1/v1Routes/BuilderRoutes/V1-AisleRoutes.ts @@ -10,6 +10,6 @@ const V1Aisle = express.Router(); V1Aisle.post("/UpsertAisle", tokenValidator, UpsertAisleController); V1Aisle.patch("/DeleteAisle", tokenValidator, DeleteAisleController); -V1Aisle.get("/Aisles/:projectId", tokenValidator, AllAisleController); +V1Aisle.get("/Aisles/:projectId/:versionId", tokenValidator, AllAisleController); export default V1Aisle; diff --git a/src/api-server/V1/v1Routes/BuilderRoutes/v1-ZoneRoutes.ts b/src/api-server/V1/v1Routes/BuilderRoutes/v1-ZoneRoutes.ts index 1068e49..d38dbb3 100644 --- a/src/api-server/V1/v1Routes/BuilderRoutes/v1-ZoneRoutes.ts +++ b/src/api-server/V1/v1Routes/BuilderRoutes/v1-ZoneRoutes.ts @@ -15,20 +15,20 @@ V1Zone.post("/zones", tokenValidator, CreateZoneController); V1Zone.patch("/zones/delete", tokenValidator, DeleteZoneController); V1Zone.get( - "/zones/visualization/:projectId", + "/zones/visualization/:projectId/:versionId", tokenValidator, VizZoneController ); V1Zone.get( - "/zones/:projectId/:zoneUuid", + "/zones/:projectId/:zoneUuid/:versionId", tokenValidator, ZoneDataController ); V1Zone.get( - "/zones/panel/:projectId/:zoneUuid", + "/zones/panel/:projectId/:zoneUuid/:versionId", tokenValidator, SingleZonePanelController ); -V1Zone.get("/zones/:projectId", tokenValidator, GetZoneController); +V1Zone.get("/zones/:projectId/:versionId", tokenValidator, GetZoneController); export default V1Zone; diff --git a/src/api-server/V1/v1Routes/BuilderRoutes/v1-assetRoutes.ts b/src/api-server/V1/v1Routes/BuilderRoutes/v1-assetRoutes.ts index 69e5b92..8022e2a 100644 --- a/src/api-server/V1/v1Routes/BuilderRoutes/v1-assetRoutes.ts +++ b/src/api-server/V1/v1Routes/BuilderRoutes/v1-assetRoutes.ts @@ -20,7 +20,7 @@ V1Asset.patch( AssetUpdatePosRotController ); V1Asset.get( - "/floorAssets/:projectId", + "/floorAssets/:projectId/:versionId", tokenValidator, GetAssetController ); diff --git a/src/api-server/V1/v1Routes/BuilderRoutes/v1-linesRoutes.ts b/src/api-server/V1/v1Routes/BuilderRoutes/v1-linesRoutes.ts index 9b95622..cc694be 100644 --- a/src/api-server/V1/v1Routes/BuilderRoutes/v1-linesRoutes.ts +++ b/src/api-server/V1/v1Routes/BuilderRoutes/v1-linesRoutes.ts @@ -16,5 +16,5 @@ V1Line.post("/points", tokenValidator, UpdateLineController); V1Line.patch("/layers/delete", tokenValidator, DeleteLayerController); V1Line.patch("/lines/delete", tokenValidator, DeleteLineController); V1Line.patch("/points/delete", tokenValidator, DeleteLinePointsController); -V1Line.get("/lines/:projectId", tokenValidator, GetLinesController); +V1Line.get("/lines/:projectId/:versionId", tokenValidator, GetLinesController); export default V1Line; diff --git a/src/api-server/V1/v1Routes/BuilderRoutes/v1-wallRoutes.ts b/src/api-server/V1/v1Routes/BuilderRoutes/v1-wallRoutes.ts index c221150..4e9eb1d 100644 --- a/src/api-server/V1/v1Routes/BuilderRoutes/v1-wallRoutes.ts +++ b/src/api-server/V1/v1Routes/BuilderRoutes/v1-wallRoutes.ts @@ -19,7 +19,7 @@ V1Wall.patch( WallDelete ); V1Wall.get( - "/walls/:projectId", + "/walls/:projectId/:versionId", tokenValidator, WallGet ); diff --git a/src/api-server/V1/v1Routes/SimulationRoutes/v1-ProductRoutes.ts b/src/api-server/V1/v1Routes/SimulationRoutes/v1-ProductRoutes.ts index 3f577de..29dc5a6 100644 --- a/src/api-server/V1/v1Routes/SimulationRoutes/v1-ProductRoutes.ts +++ b/src/api-server/V1/v1Routes/SimulationRoutes/v1-ProductRoutes.ts @@ -16,7 +16,7 @@ V1Product.get("/EventsByProduct", tokenValidator, GetProductEventDatas); V1Product.patch("/DeleteEvent", tokenValidator, DeleteEventsController); V1Product.patch("/DeleteProduct", tokenValidator, DeleteProductController); V1Product.get( - "/ProjectProducts/:projectId", + "/ProjectProducts/:projectId/:versionId", tokenValidator, ProjectBasedProductsController ); diff --git a/src/api-server/V1/v1Routes/authRoutes.ts b/src/api-server/V1/v1Routes/authRoutes.ts index b95d384..f67a63f 100644 --- a/src/api-server/V1/v1Routes/authRoutes.ts +++ b/src/api-server/V1/v1Routes/authRoutes.ts @@ -6,7 +6,6 @@ import { SignOutController, SignupController, } from "../v1Controllers/authController/authControllers.ts"; -import { versioncontroller } from "../v1Controllers/versionController/versioncontroller.ts"; const Authrouter = express.Router(); Authrouter.post("/Auth/signup", SignupController); @@ -14,6 +13,5 @@ Authrouter.post("/Auth/login", SignInController); Authrouter.post("/Auth/logout", SignOutController); Authrouter.post("/Auth/forgetPassword", ForgetPasswordController); Authrouter.post("/Auth/reset-password/:resetToken", ResetPasswordController); -Authrouter.post("/Auth/versionData", versioncontroller); export default Authrouter; diff --git a/src/api-server/V1/v1Routes/dummyroutes.ts b/src/api-server/V1/v1Routes/dummyroutes.ts new file mode 100644 index 0000000..5c82fd1 --- /dev/null +++ b/src/api-server/V1/v1Routes/dummyroutes.ts @@ -0,0 +1,12 @@ +import express from "express"; +import { tokenValidator } from "../../../shared/utils/token.ts"; +import { AddProductControllerdumy } from "../v1Controllers/dummycontroller.ts/productdummycontroller.ts"; + +const Dummyrouter = express.Router(); +Dummyrouter.post( + "/ProductUpsertdummy", + tokenValidator, + AddProductControllerdumy +); + +export default Dummyrouter; diff --git a/src/api-server/V1/v1Routes/v1-homeRoutes.ts b/src/api-server/V1/v1Routes/v1-homeRoutes.ts index a1d7538..c308334 100644 --- a/src/api-server/V1/v1Routes/v1-homeRoutes.ts +++ b/src/api-server/V1/v1Routes/v1-homeRoutes.ts @@ -4,15 +4,11 @@ import { recentDataController, searchProjectController, searchTrashProjectController, -} from "../../V1/v1Controllers/homeController/v1homeController.ts"; +} from "../v1Controllers/homeController/v1homeController.ts"; const V1homeRoutes = express.Router(); -V1homeRoutes.get( - "/RecentlyViewed", - tokenValidator, - recentDataController -); +V1homeRoutes.get("/RecentlyViewed", tokenValidator, recentDataController); V1homeRoutes.get( "/search/searchProjects", tokenValidator, diff --git a/src/api-server/V1/v1Routes/v1-projectRoutes.ts b/src/api-server/V1/v1Routes/v1-projectRoutes.ts index e3ba3e5..92b21ae 100644 --- a/src/api-server/V1/v1Routes/v1-projectRoutes.ts +++ b/src/api-server/V1/v1Routes/v1-projectRoutes.ts @@ -6,7 +6,7 @@ import { RemoveProject, updateProjectController, ViewData, -} from "../../V1/v1Controllers/projectController/v1projectController.ts"; +} from "../v1Controllers/projectController/v1projectController.ts"; import { tokenValidator } from "../../../shared/utils/token.ts"; const V1projectRouter = express.Router(); @@ -17,11 +17,7 @@ V1projectRouter.post( tokenValidator, ProjectDuplicateController ); -V1projectRouter.get( - "/Projects", - tokenValidator, - GetProjects -); +V1projectRouter.get("/Projects", tokenValidator, GetProjects); V1projectRouter.patch( "/Projects/Archive/:projectId", tokenValidator, @@ -33,10 +29,6 @@ V1projectRouter.patch( tokenValidator, updateProjectController ); -V1projectRouter.get( - "/Project/:projectId", - tokenValidator, - ViewData -); +V1projectRouter.get("/Project/:projectId", tokenValidator, ViewData); export default V1projectRouter; diff --git a/src/api-server/V1/v1Routes/v1-threadRoutes.ts b/src/api-server/V1/v1Routes/v1-threadRoutes.ts new file mode 100644 index 0000000..2486c23 --- /dev/null +++ b/src/api-server/V1/v1Routes/v1-threadRoutes.ts @@ -0,0 +1,35 @@ +import express from "express"; +import { tokenValidator } from "../../../shared/utils/token.ts"; +import { getALLthreads, threadComment, threadCommentDelete, threadCreate, threaddelete, threadUpdateTitle } from "../v1Controllers/threadController/threadController.ts"; +const V1ThreadRoutes = express.Router(); +V1ThreadRoutes.post( + "/upsetThread/", + tokenValidator, + threadCreate +); +V1ThreadRoutes.patch( + "/Thread/delete", + tokenValidator, + threaddelete +); +V1ThreadRoutes.patch( + "/Thread/updateTitle", + tokenValidator, + threadUpdateTitle +); +V1ThreadRoutes.post( + "/Thread/addComment", + tokenValidator, + threadComment +); +V1ThreadRoutes.patch( + "/Thread/deleteComment", + tokenValidator, + threadCommentDelete +); +V1ThreadRoutes.get( + "/Threads/:projectId", + tokenValidator, + getALLthreads +); +export default V1ThreadRoutes \ No newline at end of file diff --git a/src/api-server/V1/v1Routes/v1-trashRoutes.ts b/src/api-server/V1/v1Routes/v1-trashRoutes.ts index 925ab66..08bbd42 100644 --- a/src/api-server/V1/v1Routes/v1-trashRoutes.ts +++ b/src/api-server/V1/v1Routes/v1-trashRoutes.ts @@ -4,23 +4,11 @@ import { DeleteTrashData, GetTrashList, RestoreTrash, -} from "../../V1/v1Controllers/trashController/v1trashController.ts"; +} from "../v1Controllers/trashController/v1trashController.ts"; const V1TrashRoutes = express.Router(); -V1TrashRoutes.get( - "/TrashItems", - tokenValidator, - GetTrashList -); +V1TrashRoutes.get("/TrashItems", tokenValidator, GetTrashList); -V1TrashRoutes.patch( - "/Trash/restore", - tokenValidator, - RestoreTrash -); -V1TrashRoutes.patch( - "/Trash/Delete", - tokenValidator, - DeleteTrashData -); +V1TrashRoutes.patch("/Trash/restore", tokenValidator, RestoreTrash); +V1TrashRoutes.patch("/Trash/Delete", tokenValidator, DeleteTrashData); export default V1TrashRoutes; diff --git a/src/api-server/V1/v1Routes/v1-versionRoutes.ts b/src/api-server/V1/v1Routes/v1-versionRoutes.ts new file mode 100644 index 0000000..cc278e0 --- /dev/null +++ b/src/api-server/V1/v1Routes/v1-versionRoutes.ts @@ -0,0 +1,21 @@ +import express from "express"; +import { tokenValidator } from "../../../shared/utils/token.ts"; +import { + GetversionHistory, + GetversionList, + rollbackcontroller, + versionAddcontroller, +} from "../v1Controllers/versionController/versioncontroller.ts"; + +const V1versionRoutes = express.Router(); + +V1versionRoutes.post("/generateVersion", tokenValidator, versionAddcontroller); +V1versionRoutes.get( + "/version/:versionId/:projectId", + tokenValidator, + GetversionList +); +V1versionRoutes.get("/:projectId/versions", tokenValidator, GetversionHistory); +V1versionRoutes.post("/version/rollback", tokenValidator, rollbackcontroller); + +export default V1versionRoutes; diff --git a/src/api-server/V1/v1Routes/vizRoutes.ts/v1-FloatWidgetRoutes.ts b/src/api-server/V1/v1Routes/vizRoutes.ts/v1-FloatWidgetRoutes.ts index 140afa6..4e722f1 100644 --- a/src/api-server/V1/v1Routes/vizRoutes.ts/v1-FloatWidgetRoutes.ts +++ b/src/api-server/V1/v1Routes/vizRoutes.ts/v1-FloatWidgetRoutes.ts @@ -21,7 +21,7 @@ V1FloatWidget.patch( DeleteFloatController ); V1FloatWidget.get( - "/floatWidgets/:zoneUuid/:projectId", + "/floatWidgets/:zoneUuid/:projectId/:versionId", tokenValidator, GetFloatController ); diff --git a/src/api-server/V1/v1Routes/vizRoutes.ts/v1-TemplateRoutes.ts b/src/api-server/V1/v1Routes/vizRoutes.ts/v1-TemplateRoutes.ts index 3facb5e..d382049 100644 --- a/src/api-server/V1/v1Routes/vizRoutes.ts/v1-TemplateRoutes.ts +++ b/src/api-server/V1/v1Routes/vizRoutes.ts/v1-TemplateRoutes.ts @@ -20,7 +20,7 @@ V1Template.post( AddTemToZoneController ); V1Template.get( - "/template/data/:projectId", + "/template/data/:projectId/:versionId", tokenValidator, GetTemplateController ); diff --git a/src/api-server/V1/v1Routes/vizRoutes.ts/v1-widget3dRoutes.ts b/src/api-server/V1/v1Routes/vizRoutes.ts/v1-widget3dRoutes.ts index 3a6668d..b1d37ea 100644 --- a/src/api-server/V1/v1Routes/vizRoutes.ts/v1-widget3dRoutes.ts +++ b/src/api-server/V1/v1Routes/vizRoutes.ts/v1-widget3dRoutes.ts @@ -23,7 +23,7 @@ V1Widget3d.patch( Update3DwidgetController ); V1Widget3d.get( - "/widget3d/data/:zoneUuid/:projectId", + "/widget3d/data/:zoneUuid/:projectId/:versionId", tokenValidator, Get3DWidgetController ); diff --git a/src/api-server/V1/v1Routes/yjsRoutes.ts/autosaveRoutes.ts b/src/api-server/V1/v1Routes/yjsRoutes.ts/autosaveRoutes.ts new file mode 100644 index 0000000..be13e11 --- /dev/null +++ b/src/api-server/V1/v1Routes/yjsRoutes.ts/autosaveRoutes.ts @@ -0,0 +1,17 @@ +import express from "express"; + +import { tokenValidator } from "../../../../shared/utils/token.ts"; +import { autoSaveRestore, clearAutoSaveRestore } from "../../v1Controllers/yjsController/auto-saveControlle.ts"; +const V1AutoSaveRoutes = express.Router(); +V1AutoSaveRoutes.get( + "/restoreAutoSave/", +// tokenValidator, + autoSaveRestore +); +V1AutoSaveRoutes.post( + "/clearSnapAutoSave/", +// tokenValidator, + clearAutoSaveRestore +); + +export default V1AutoSaveRoutes \ No newline at end of file diff --git a/src/api-server/V1/v1Routes/yjsRoutes.ts/snapshotRoutes.ts b/src/api-server/V1/v1Routes/yjsRoutes.ts/snapshotRoutes.ts new file mode 100644 index 0000000..a6cb924 --- /dev/null +++ b/src/api-server/V1/v1Routes/yjsRoutes.ts/snapshotRoutes.ts @@ -0,0 +1,16 @@ +import express from "express"; + +import { SnapshotList, SnapshotRestore } from "../../v1Controllers/yjsController/yjsSnapController.ts"; +import { tokenValidator } from "../../../../shared/utils/token.ts"; +const V1SnapshotRoutes = express.Router(); +V1SnapshotRoutes.get( + "/restoreSnap/", +// tokenValidator, + SnapshotRestore +); +V1SnapshotRoutes.get( + "/listSnap/", +// tokenValidator, + SnapshotList +); +export default V1SnapshotRoutes \ No newline at end of file diff --git a/src/api-server/app.ts b/src/api-server/app.ts index 927d088..95abcf8 100644 --- a/src/api-server/app.ts +++ b/src/api-server/app.ts @@ -38,6 +38,11 @@ import V1Widget from "./V1/v1Routes/vizRoutes.ts/v1-widgetRoutes.ts"; import V1Widget3d from "./V1/v1Routes/vizRoutes.ts/v1-widget3dRoutes.ts"; import V1Product from "./V1/v1Routes/SimulationRoutes/v1-ProductRoutes.ts"; import V1Aisle from "./V1/v1Routes/BuilderRoutes/V1-AisleRoutes.ts"; +import V1ThreadRoutes from "./V1/v1Routes/v1-threadRoutes.ts"; +import V1versionRoutes from "./V1/v1Routes/v1-versionRoutes.ts"; +import Dummyrouter from "./V1/v1Routes/dummyroutes.ts"; +import V1SnapshotRoutes from "./V1/v1Routes/yjsRoutes.ts/snapshotRoutes.ts"; +import V1AutoSaveRoutes from "./V1/v1Routes/yjsRoutes.ts/autosaveRoutes.ts"; redis; const app = express(); app.use(cors()); @@ -90,5 +95,10 @@ app.use("/api/V1", V1Widget); app.use("/api/V1", V1Widget3d); app.use("/api/V1", V1Product); app.use("/api/V1", V1Aisle); +app.use("/api/V1", V1ThreadRoutes); +app.use("/api/V1", V1versionRoutes); +app.use("/api/V1", Dummyrouter); +app.use("/api/V1", V1SnapshotRoutes); +app.use("/api/V1", V1AutoSaveRoutes); export default app; diff --git a/src/api-server/main.ts b/src/api-server/main.ts index 6ed5807..15ad189 100644 --- a/src/api-server/main.ts +++ b/src/api-server/main.ts @@ -5,13 +5,29 @@ import fs from "fs"; const server = http.createServer(app); let swaggerDocument = {}; +let swaggerNewVersionDocument = {}; try { swaggerDocument = JSON.parse(fs.readFileSync("swagger-output.json", "utf-8")); } catch (error) { console.error("Error loading Swagger JSON:", error); } -app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); +// app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); +app.use( + "/api-docs", + swaggerUi.serveFiles(swaggerDocument), + swaggerUi.setup(swaggerDocument) +); +// app.use( +// "/NewVersion/api-docs", +// swaggerUi.serve, +// swaggerUi.setup(swaggerNewVersionDocument) +// ); +app.use( + "/NewVersion/api-docs", + swaggerUi.serveFiles(swaggerNewVersionDocument), + swaggerUi.setup(swaggerNewVersionDocument) +); const organization = process.env.ORGANIZATION_NAME || "defaultOrganization"; if (!organization) { @@ -22,4 +38,7 @@ const PORT = process.env.API_PORT; server.listen(PORT, () => { console.log(`API-Server running on http://localhost:${PORT}`); console.log(`Swagger UI available at http://localhost:${PORT}/api-docs`); + console.log( + `Swagger UI available at http://localhost:${PORT}/NewVersion/api-docs` + ); }); diff --git a/src/shared/V1Models/Builder/AisleModel.ts b/src/shared/V1Models/Builder/AisleModel.ts index f381c37..c0d1e50 100644 --- a/src/shared/V1Models/Builder/AisleModel.ts +++ b/src/shared/V1Models/Builder/AisleModel.ts @@ -2,7 +2,7 @@ import { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; import { User } from "../Auth/userAuthModel.ts"; import { Project } from "../Project/project-model.ts"; - +import { Version } from "../Version/versionModel.ts"; type PointTypes = "Aisle"; export interface Point { @@ -116,6 +116,7 @@ export interface Aisle extends Document { aisleUuid: string; points: [Point, Point]; projectId: Project["_id"]; + versionId: Version["_id"]; createdBy: User["_id"]; type: AisleType; isArchive: boolean; @@ -126,6 +127,7 @@ const AisleSchema: Schema = new Schema( aisleUuid: { type: String, required: true }, createdBy: { type: Schema.Types.ObjectId, ref: "User" }, projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, points: { type: [ { diff --git a/src/shared/V1Models/Builder/linesModel.ts b/src/shared/V1Models/Builder/linesModel.ts index 6081a5b..62d72c7 100644 --- a/src/shared/V1Models/Builder/linesModel.ts +++ b/src/shared/V1Models/Builder/linesModel.ts @@ -1,22 +1,41 @@ import mongoose, { Schema } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; +import { User } from "../Auth/userAuthModel.ts"; const positionSchema = new mongoose.Schema({ x: { type: Number }, y: { type: Number }, z: { type: Number }, }); -const Vector3 = new mongoose.Schema({ +const vector3Schema = new mongoose.Schema({ position: { type: positionSchema, required: false }, uuid: { type: String, required: false }, }); +export interface Vector3 { + uuid: string; + position: { + x: { type: Number }; + y: { type: Number }; + z: { type: Number }; + }; +} + +export interface ILines extends Document { + userId: User["_id"]; + projectId: User["_id"]; + versionId: User["_id"]; + layer: number; + line: Vector3[]; + type: string; + isArchive: boolean; +} const LineSchema = new mongoose.Schema({ userId: { type: Schema.Types.ObjectId, ref: "User" }, projectId: { type: Schema.Types.ObjectId, ref: "Project" }, versionId: { type: Schema.Types.ObjectId, ref: "Version" }, layer: { type: Number, required: true }, - line: { type: [Vector3], required: true }, + line: { type: [vector3Schema], required: true }, type: { type: String, required: false }, isArchive: { type: Boolean, default: false }, }); diff --git a/src/shared/V1Models/Builder/wallItemsModel.ts b/src/shared/V1Models/Builder/wallItemsModel.ts index 9b9ba13..97d86b9 100644 --- a/src/shared/V1Models/Builder/wallItemsModel.ts +++ b/src/shared/V1Models/Builder/wallItemsModel.ts @@ -16,6 +16,7 @@ export interface WallItems extends Document { position: []; quaternion: []; scale: []; + isArchive: boolean; } const wallItemsSchema: Schema = new Schema({ @@ -27,6 +28,7 @@ const wallItemsSchema: Schema = new Schema({ modelName: { type: String }, type: { type: String }, csgposition: { type: Array }, + isArchive: { type: Boolean, default: false }, csgscale: { type: Array }, position: { type: Array }, quaternion: { type: Array }, diff --git a/src/shared/V1Models/Environment/environments-Model.ts b/src/shared/V1Models/Environment/environments-Model.ts index f6d8420..558006e 100644 --- a/src/shared/V1Models/Environment/environments-Model.ts +++ b/src/shared/V1Models/Environment/environments-Model.ts @@ -2,9 +2,11 @@ import { Document, Schema } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; import { User } from "../Auth/userAuthModel.ts"; import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; export interface Environment extends Document { userId: User["_id"]; projectId: Project["_id"]; + versionId: Version["_id"]; roofVisibility: boolean; wallVisibility: boolean; renderDistance: number; @@ -16,6 +18,7 @@ export interface Environment extends Document { const environmentSchema: Schema = new Schema({ userId: { type: Schema.Types.ObjectId, ref: "User" }, projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, roofVisibility: { type: Boolean, default: false }, wallVisibility: { type: Boolean, default: false }, shadowVisibility: { type: Boolean, default: false }, diff --git a/src/shared/V1Models/Project/project-model.ts b/src/shared/V1Models/Project/project-model.ts index 0f996dc..e2c5692 100644 --- a/src/shared/V1Models/Project/project-model.ts +++ b/src/shared/V1Models/Project/project-model.ts @@ -1,6 +1,7 @@ import { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; import { User } from "../Auth/userAuthModel.ts"; +import { Version } from "../Version/versionModel.ts"; export interface Project extends Document { projectUuid: string; @@ -13,7 +14,7 @@ export interface Project extends Document { DeletedAt: Date; isViewed: number; total_versions: string; - Present_version: string; + Present_version: Version["_id"]; } const projectSchema: Schema = new Schema( { @@ -27,7 +28,7 @@ const projectSchema: Schema = new Schema( isDeleted: { type: Boolean, default: false }, isViewed: { type: Number }, total_versions: { type: String }, - Present_version: { type: String }, + Present_version: { type: Schema.Types.ObjectId, ref: "Version" }, }, { timestamps: true } ); diff --git a/src/shared/V1Models/Simulation/eventsDataModel.ts b/src/shared/V1Models/Simulation/eventsDataModel.ts index 080235a..5b9f9a2 100644 --- a/src/shared/V1Models/Simulation/eventsDataModel.ts +++ b/src/shared/V1Models/Simulation/eventsDataModel.ts @@ -1,6 +1,7 @@ import { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; interface AssetEventSchema { modelUuid: string; modelName: string; @@ -124,7 +125,7 @@ interface StorageEventSchema extends AssetEventSchema { type: "storageUnit"; point: StoragePointSchema; } -interface IPointModel extends Document { +export interface IPointModel extends Document { modelUuid: string; modelName: string; position: [number]; @@ -132,6 +133,7 @@ interface IPointModel extends Document { state: string; productUuid: string; projectId: Project["_id"]; + versionId: Version["_id"]; isArchive: boolean; type: "transfer" | "vehicle" | "roboticArm" | "machine" | "storageUnit"; speed: number; @@ -167,6 +169,7 @@ const BaseEventSchema = new Schema( type: Schema.Types.Mixed, }, projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, productUuid: { type: String, required: true }, isArchive: { type: Boolean, default: false }, }, diff --git a/src/shared/V1Models/Thread/thread-Model.ts b/src/shared/V1Models/Thread/thread-Model.ts index b654b30..999d1ee 100644 --- a/src/shared/V1Models/Thread/thread-Model.ts +++ b/src/shared/V1Models/Thread/thread-Model.ts @@ -4,38 +4,45 @@ import { Project } from "../Project/project-model.ts"; import { Version } from "../Version/versionModel.ts"; import MainModel from "../../connect/mongoose.ts"; interface IComment { - userId: User["_id"]; - comment: string; - timestamp:number + userId: User["_id"]; + comment: string; + isArchive: boolean; + createdAt: number } export interface IThread extends Document { - projectId: Project["_id"]; - versionId: Version["_id"]; - state: string; - commentId: string; - createdBy: User["_id"]; - createdAt: number; - lastUpdatedAt: string; - position: [number, number, number]; - rotation: [number, number, number]; - replies: IComment[]; + projectId: Project["_id"]; + versionId: Version["_id"]; + state: string; + threadTitle: string; + createdBy: User["_id"]; + createdAt: number; + lastUpdatedAt: string; + position: [number, number, number]; + rotation: [number, number, number]; + comments: IComment[]; + isArchive: boolean; + isResolved: boolean; } -const CommentSchema = new Schema( +const CommentSchema = new Schema( { userId: { type: Schema.Types.ObjectId, ref: 'User', required: true }, - comment: { type: String,}, - timestamp:{ - type: Number, - default:Date.now()} + comment: { type: String, }, + isArchive: { type: Boolean, default: false }, + createdAt: { + type: Number, + default: Date.now() + } }, ); const threadSchema = new Schema({ projectId: { type: Schema.Types.ObjectId, ref: 'Project', required: true }, state: { type: String, enum: ['active', 'inactive'], required: true }, - commentId: { type: String, }, + threadTitle: { type: String, }, createdBy: { type: Schema.Types.ObjectId, ref: 'User', required: true }, - createdAt: { type: Number,}, + createdAt: { type: Number, }, + isArchive: { type: Boolean, default: false }, + isResolved: { type: Boolean, default: false }, lastUpdatedAt: { type: String, }, position: { type: [Number], @@ -45,7 +52,7 @@ const threadSchema = new Schema({ type: [Number], required: true, }, - replies: { type: [CommentSchema ], default: [] }, + comments: { type: [CommentSchema], default: [] }, }); const ThreadModel = (db: string) => { diff --git a/src/shared/V1Models/Version/versionModel.ts b/src/shared/V1Models/Version/versionModel.ts index 920174c..f239968 100644 --- a/src/shared/V1Models/Version/versionModel.ts +++ b/src/shared/V1Models/Version/versionModel.ts @@ -4,15 +4,23 @@ import { Project } from "../Project/project-model.ts"; import { User } from "../Auth/userAuthModel.ts"; export interface Version extends Document { versionName: string; + previous_Version: string; projectId: Project["_id"]; createdBy: User["_id"]; isArchive: boolean; version: number; + rollBackComment: string; + description: string; + parentVersionID: Version["_id"]; } const versionSchema: Schema = new Schema( { - versionName: { type: String }, + versionName: { type: String, default: "" }, + rollBackComment: { type: String }, + description: { type: String, default: "" }, version: { type: Number }, + parentVersionID: { type: Schema.Types.ObjectId, ref: "version" }, + previous_Version: { type: String }, isArchive: { type: Boolean, default: false }, projectId: { type: Schema.Types.ObjectId, ref: "project" }, createdBy: { type: Schema.Types.ObjectId, ref: "user" }, diff --git a/src/shared/V1Models/Vizualization/3dwidget.ts b/src/shared/V1Models/Vizualization/3dwidget.ts index b250c0d..5fa80e4 100644 --- a/src/shared/V1Models/Vizualization/3dwidget.ts +++ b/src/shared/V1Models/Vizualization/3dwidget.ts @@ -1,5 +1,7 @@ import { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; export interface Widget3d extends Document { type: string; widgetID: string; @@ -7,20 +9,24 @@ export interface Widget3d extends Document { position: []; rotation: []; isArchive: boolean; - zoneUuid:string + zoneUuid: string; Data: { measurements: {}; duration: string; }; + projectId: Project["_id"]; + versionId: Version["_id"]; } const Widget3dSchema: Schema = new Schema( { type: { type: String }, + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, widgetID: { type: String }, widgetName: { type: String, default: "Widget3D" }, position: { type: Array }, rotation: { type: Array }, - zoneUuid:{ type: String }, + zoneUuid: { type: String }, Data: { measurements: { type: Object, default: {} }, duration: { type: String, default: "1h" }, diff --git a/src/shared/V1Models/Vizualization/floatWidget.ts b/src/shared/V1Models/Vizualization/floatWidget.ts index 5f3a188..5a61eb0 100644 --- a/src/shared/V1Models/Vizualization/floatWidget.ts +++ b/src/shared/V1Models/Vizualization/floatWidget.ts @@ -1,5 +1,7 @@ import { Schema, Document } from "mongoose"; -import MainModel from "../../connect/mongoose.ts"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; export interface FloatingWidget extends Document { className: string; iconName: string; @@ -9,11 +11,13 @@ export interface FloatingWidget extends Document { per: string; value: string; isArchive: boolean; - zoneUuid: string + zoneUuid: string; Data: { measurements: {}; duration: string; }; + projectId: Project["_id"]; + versionId: Version["_id"]; } const floatingWidgetSchema: Schema = new Schema( { @@ -25,6 +29,8 @@ const floatingWidgetSchema: Schema = new Schema( per: { type: String }, value: { type: String }, zoneUuid: { type: String }, + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, Data: { measurements: { type: Object, default: {} }, duration: { type: String, default: "1h" }, diff --git a/src/shared/V1Models/Vizualization/panelmodel.ts b/src/shared/V1Models/Vizualization/panelmodel.ts index 0628c44..42d8a8f 100644 --- a/src/shared/V1Models/Vizualization/panelmodel.ts +++ b/src/shared/V1Models/Vizualization/panelmodel.ts @@ -1,15 +1,21 @@ import mongoose, { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; export interface Panel extends Document { - zoneUuid: string + zoneUuid: string; panelName: string; widgets: [mongoose.Types.ObjectId]; isArchive: boolean; + projectId: Project["_id"]; + versionId: Version["_id"]; } const panelSchema: Schema = new Schema( { zoneUuid: { type: String }, panelName: { type: String }, + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, widgets: [{ type: mongoose.Schema.Types.ObjectId, ref: "Widget" }], isArchive: { type: Boolean, default: false }, }, diff --git a/src/shared/V1Models/Vizualization/widgemodel.ts b/src/shared/V1Models/Vizualization/widgemodel.ts index 0a6f57e..5731b68 100644 --- a/src/shared/V1Models/Vizualization/widgemodel.ts +++ b/src/shared/V1Models/Vizualization/widgemodel.ts @@ -1,11 +1,15 @@ import mongoose, { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; export interface Widget extends Document { widgetName: string; widgetside: string; widgetID: string; widgetOrder: string; elementType: string; + projectId: Project["_id"]; + versionId: Version["_id"]; elementColor: string; fontFamily: string; fontStyle: string; @@ -16,13 +20,15 @@ export interface Widget extends Document { measurements: {}; duration: string; }; - zoneUuid: string + zoneUuid: string; } const widgetSchema: Schema = new Schema( { widgetName: { type: String, default: "Widget" }, widgetside: { type: String }, widgetID: { type: String }, + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, widgetOrder: { type: String }, elementType: { type: String }, elementColor: { type: String }, @@ -35,7 +41,7 @@ const widgetSchema: Schema = new Schema( fontWeight: { type: String }, isArchive: { type: Boolean, default: false }, panelID: { type: mongoose.Schema.Types.ObjectId, ref: "Panel" }, - zoneUuid: { type: String } + zoneUuid: { type: String }, }, { timestamps: true } ); diff --git a/src/shared/V1Models/dummy/actionDummy.ts b/src/shared/V1Models/dummy/actionDummy.ts new file mode 100644 index 0000000..2a73380 --- /dev/null +++ b/src/shared/V1Models/dummy/actionDummy.ts @@ -0,0 +1,155 @@ +import { Schema, Document } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +interface AssetEventSchema { + modelUuid: string; + modelName: string; + position: [number, number, number]; + rotation: [number, number, number]; + state: "idle" | "running" | "stopped" | "disabled" | "error"; +} + +interface TriggerSchema { + triggerUuid: string; + triggerName: string; + triggerType: "onComplete" | "onStart" | "onStop" | "delay" | "onError"; + delay: number; + triggeredAsset: { + triggeredModel: { modelName: string; modelUuid: string }; + triggeredPoint: { pointName: string; pointUuid: string }; + triggeredAction: { actionName: string; actionUuid: string }; + } | null; +} + +interface ConveyorPointActionSchema { + uuid: string; + action: { + actionUuid: string; + actionName: string; + actionType: "default" | "spawn" | "swap" | "despawn"; + material: string; + delay: number | "inherit"; + spawnInterval: number | "inherit"; + spawnCount: number | "inherit"; + triggers: TriggerSchema[]; + }; +} + +interface VehiclePointActionSchema { + uuid: string; + action: { + actionUuid: string; + actionName: string; + actionType: "travel"; + material: string | null; + unLoadDuration: number; + loadCapacity: number; + pickUpPoint: { x: number; y: number; z: number } | null; + unLoadPoint: { x: number; y: number; z: number } | null; + triggers: TriggerSchema[]; + }; +} + +interface RoboticArmPointActionSchema { + uuid: string; + actions: { + actionUuid: string; + actionName: string; + actionType: "pickAndPlace"; + process: { + startPoint: [number, number, number]; + endPoint: [number, number, number]; + }; + triggers: TriggerSchema[]; + }[]; +} + +interface MachinePointActionSchema { + uuid: string; + action: { + actionUuid: string; + actionName: string; + actionType: "process"; + processTime: number; + swapMaterial: string; + triggers: TriggerSchema[]; + }; +} + +interface StoragePointActionSchema { + uuid: string; + action: { + actionUuid: string; + actionName: string; + actionType: "storage"; + materials: { materialName: string; materialId: string }[]; + storageCapacity: number; + }; +} + +export interface ConveyorActionSchema extends AssetEventSchema { + type: "transfer"; + Action: ConveyorPointActionSchema; +} + +export interface VehicleActionSchema extends AssetEventSchema { + type: "vehicle"; + Action: VehiclePointActionSchema; +} + +export interface RoboticArmActionSchema extends AssetEventSchema { + type: "roboticArm"; + Actions: RoboticArmPointActionSchema[]; +} + +export interface MachineActionSchema extends AssetEventSchema { + type: "machine"; + Action: MachinePointActionSchema; +} + +export interface StorageActionSchema extends AssetEventSchema { + type: "storageUnit"; + Action: StoragePointActionSchema; +} +interface IActionModel extends Document { + modelUuid: string; + modelName: string; + productUuid: string; + projectId: Project["_id"]; + isArchive: boolean; + type: "transfer" | "vehicle" | "roboticArm" | "machine" | "storageUnit"; + Action: + | VehicleActionSchema + | ConveyorActionSchema + | MachineActionSchema + | StorageActionSchema; + Actions: RoboticArmActionSchema[]; +} + +const BaseEventSchema = new Schema( + { + modelUuid: { type: String, required: true }, + modelName: { type: String, required: true }, + type: { + type: String, + required: true, + enum: ["transfer", "vehicle", "roboticArm", "machine", "storageUnit"], + }, + Action: { + type: Schema.Types.Mixed, + }, + Actions: { + type: Schema.Types.Mixed, + }, + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + productUuid: { type: String, required: true }, + isArchive: { type: Boolean, default: false }, + }, + { discriminatorKey: "type", timestamps: true } +); + +const actionDummyModel = (db: string) => { + return MainModel(db, "Actions", BaseEventSchema, "Actions"); +}; + +export default actionDummyModel; diff --git a/src/shared/V1Models/dummy/eventDummy.ts b/src/shared/V1Models/dummy/eventDummy.ts new file mode 100644 index 0000000..bbc98aa --- /dev/null +++ b/src/shared/V1Models/dummy/eventDummy.ts @@ -0,0 +1,149 @@ +import { Schema, Document } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +interface AssetEventSchema { + modelUuid: string; + modelName: string; + position: [number, number, number]; + rotation: [number, number, number]; + state: "idle" | "running" | "stopped" | "disabled" | "error"; +} + +interface TriggerSchema { + triggerUuid: string; + triggerName: string; + triggerType: "onComplete" | "onStart" | "onStop" | "delay" | "onError"; + delay: number; + triggeredAsset: { + triggeredModel: { modelName: string; modelUuid: string }; + triggeredPoint: { pointName: string; pointUuid: string }; + triggeredAction: { actionName: string; actionUuid: string }; + } | null; +} + +interface ConveyorPointSchema { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + action: { + actionUuid: string; + }; +} + +interface VehiclePointSchema { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + action: { + actionUuid: string; + }; +} + +interface RoboticArmPointSchema { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + actions: { + actionUuid: string; + }[]; +} + +interface MachinePointSchema { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + action: { + actionUuid: string; + }; +} + +interface StoragePointSchema { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + action: { + actionUuid: string; + }; +} + +interface ConveyorEventSchema extends AssetEventSchema { + type: "transfer"; + speed: number; + points: ConveyorPointSchema[]; +} + +interface VehicleEventSchema extends AssetEventSchema { + type: "vehicle"; + speed: number; + point: VehiclePointSchema; +} + +interface RoboticArmEventSchema extends AssetEventSchema { + type: "roboticArm"; + speed: number; + point: RoboticArmPointSchema; +} + +interface MachineEventSchema extends AssetEventSchema { + type: "machine"; + point: MachinePointSchema; +} + +interface StorageEventSchema extends AssetEventSchema { + type: "storageUnit"; + point: StoragePointSchema; +} +interface IPointModel extends Document { + modelUuid: string; + modelName: string; + position: [number]; + rotation: [number]; + state: string; + productUuid: string; + projectId: Project["_id"]; + isArchive: boolean; + type: "transfer" | "vehicle" | "roboticArm" | "machine" | "storageUnit"; + speed: number; + point: + | VehicleEventSchema + | RoboticArmEventSchema + | MachineEventSchema + | StorageEventSchema; + points: ConveyorEventSchema[]; +} + +const BaseEventSchema = new Schema( + { + modelUuid: { type: String, required: true }, + modelName: { type: String, required: true }, + position: { type: [Number], required: true }, + rotation: { type: [Number], required: true }, + speed: { type: Number }, + state: { + type: String, + enum: ["idle", "running", "stopped", "disabled", "error"], + default: "idle", + }, + type: { + type: String, + required: true, + enum: ["transfer", "vehicle", "roboticArm", "machine", "storageUnit"], + }, + point: { + type: Schema.Types.Mixed, + }, + points: { + type: Schema.Types.Mixed, + }, + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + productUuid: { type: String, required: true }, + isArchive: { type: Boolean, default: false }, + }, + { discriminatorKey: "type", timestamps: true } +); + +const EventsDataModel = (db: string) => { + return MainModel(db, "EventDatas", BaseEventSchema, "EventDatas"); +}; + +export default EventsDataModel; diff --git a/src/shared/V1Models/dummy/productDumy.ts b/src/shared/V1Models/dummy/productDumy.ts new file mode 100644 index 0000000..5aab68b --- /dev/null +++ b/src/shared/V1Models/dummy/productDumy.ts @@ -0,0 +1,28 @@ +import { Schema, Document } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; +import { User } from "../Auth/userAuthModel.ts"; +export interface Product extends Document { + productName: string; + userId: User["_id"]; + productUuid: string; + projectId: Project["_id"]; + versionId: Version["_id"]; + isArchive: boolean; +} + +const ProductSchema = new Schema({ + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + userId: { type: Schema.Types.ObjectId, ref: "User" }, + versionId: { type: Schema.Types.ObjectId, ref: "Version" }, + productName: { type: String, required: true }, + productUuid: { type: String, required: true }, + isArchive: { type: Boolean, default: false }, +}); + +const ProductModel = (db: string) => { + return MainModel(db, "Products", ProductSchema, "Products"); +}; + +export default ProductModel; diff --git a/src/shared/V1Models/yjs/auto-saveModel.ts b/src/shared/V1Models/yjs/auto-saveModel.ts new file mode 100644 index 0000000..a794d8f --- /dev/null +++ b/src/shared/V1Models/yjs/auto-saveModel.ts @@ -0,0 +1,26 @@ +import { Schema, Document } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; +import { User } from "../Auth/userAuthModel.ts"; + +export interface autoSave extends Document { + + yjsData: Buffer; + isArchive: boolean; + createdBy: User["_id"]; + projectId: Project["_id"]; + versionId: string; +} +const YjsSchema: Schema = new Schema({ + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: String, }, + // versionId: { type: Schema.Types.ObjectId, ref: "Version" }, + yjsData: Buffer, + updatedAt: { type: Date, default: Date.now }, +}); + +const autosaveModel = (db: any) => { + return MainModel(db, "autosave", YjsSchema, "autosave"); +}; +export default autosaveModel; \ No newline at end of file diff --git a/src/shared/V1Models/yjs/snapshotModel.ts b/src/shared/V1Models/yjs/snapshotModel.ts new file mode 100644 index 0000000..b2d8716 --- /dev/null +++ b/src/shared/V1Models/yjs/snapshotModel.ts @@ -0,0 +1,30 @@ +import { Schema, Document } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../Project/project-model.ts"; +import { Version } from "../Version/versionModel.ts"; +import { User } from "../Auth/userAuthModel.ts"; + +export interface snapshot extends Document { + snapshotData: Buffer; + isArchive: boolean; + label: string; + createdBy: User["_id"]; + projectId: Project["_id"]; + versionId: string; + // versionId: Version["_id"]; +} + + +const SnapshotSchema: Schema = new Schema({ + projectId: { type: Schema.Types.ObjectId, ref: "Project" }, + versionId: { type: String, }, + // versionId: { type: Schema.Types.ObjectId, ref: "Version" }, + label: String, // e.g., "v1.2 layout change" + snapshotData: Buffer, + createdBy: String, + createdAt: { type: Date, default: Date.now }, +}); +const snapshotModel = (db: any) => { + return MainModel(db, "snapshot", SnapshotSchema, "snapshot"); +}; +export default snapshotModel; diff --git a/src/shared/middleware/rbacMiddleware.ts b/src/shared/middleware/rbacMiddleware.ts index 18ba11d..c7efa22 100644 --- a/src/shared/middleware/rbacMiddleware.ts +++ b/src/shared/middleware/rbacMiddleware.ts @@ -1,5 +1,5 @@ import { Response, NextFunction } from "express"; -import { AuthenticatedRequest } from "../../shared/utils/token.ts"; +import { AuthenticatedRequest } from "../utils/token.ts"; type Role = "Admin" | "User"; const authorizedRoles = (...allowedRoles: Role[]) => { return (req: AuthenticatedRequest, res: Response, next: NextFunction) => { diff --git a/src/shared/model/version/versionModel.ts b/src/shared/model/version/versionModel.ts index 0ab23f8..4c4ce14 100644 --- a/src/shared/model/version/versionModel.ts +++ b/src/shared/model/version/versionModel.ts @@ -5,6 +5,7 @@ import { User } from "../user-Model.ts"; export interface Version extends Document { versionName: string; projectId: Project["_id"]; + createdBy: User["_id"]; isArchive: boolean; version: number; diff --git a/src/shared/services/Thread/ThreadService.ts b/src/shared/services/Thread/ThreadService.ts index b4345b5..7d1cea5 100644 --- a/src/shared/services/Thread/ThreadService.ts +++ b/src/shared/services/Thread/ThreadService.ts @@ -1,26 +1,51 @@ import ThreadModel from "../../V1Models/Thread/thread-Model.ts"; -import { existingProjectByIdWithoutUser, existingUser } from "../helpers/v1projecthelperFns.ts"; - +import { Types } from "mongoose"; +import { + existingProjectByIdWithoutUser, + existingUser, + LivingCurrentVersion, +} from "../helpers/v1projecthelperFns.ts"; interface IThread { projectId: string; versionId: string; - state: string + state: string; commentId: string; + threadTitle: string; threadId: string; userId: string; createdAt: string; lastUpdatedAt: string; position: [number, number, number]; rotation: [number, number, number]; - comments: string + comment: string; timestamp: number; + organization: string; +} +interface IComment { + _id?: Types.ObjectId; + userId: string; + comment: string; + isArchive: boolean; + createdAt: number; +} +interface IgetThread { + projectId: string; + userId: string; organization: string; } export const createThread = async (data: IThread) => { try { - const { projectId, state, userId, position, rotation, comments, organization } = data + const { + projectId, + state, + userId, + position, + rotation, + threadTitle, + organization, + } = data; const userExisting = await existingUser(userId, organization); if (!userExisting) { return { @@ -29,35 +54,54 @@ export const createThread = async (data: IThread) => { } const projectExisting = await existingProjectByIdWithoutUser( projectId, - organization, - + organization ); if (!projectExisting) { return { status: "Project not found" }; } + const currentVersion = await LivingCurrentVersion( + organization, + projectExisting._id, + projectExisting.Present_version + ); + if (!currentVersion) return { status: "CurrentVersion Data not found" }; const newThread = await ThreadModel(organization).create({ projectId, + versionId: currentVersion._id, state, createdBy: userId, position, + threadTitle, rotation, - comments, - createdAt: Date.now() + isArchive: false, + createdAt: Date.now(), }); + const responseData = { + _id: newThread._id, + projectId: newThread.projectId, + versionId: newThread.versionId, + state: newThread.state, + createdBy: newThread.createdBy, + createdAt: newThread.createdAt, + isArchive: newThread.isArchive, + position: newThread.position, + rotation: newThread.rotation, + threadTitle: newThread.threadTitle, + }; return { status: "Success", - data: newThread, + data: responseData, }; } catch (error) { return { status: error, }; } -} +}; export const deleteThread = async (data: IThread) => { try { - const { projectId, userId, organization, threadId } = data + const { projectId, userId, organization, threadId } = data; const userExisting = await existingUser(userId, organization); if (!userExisting) { return { @@ -66,32 +110,98 @@ export const deleteThread = async (data: IThread) => { } const projectExisting = await existingProjectByIdWithoutUser( projectId, - organization, - + organization ); if (!projectExisting) { return { status: "Project not found" }; } - const findThreadId = await ThreadModel(organization).findOne({ _id: threadId, createdBy: userId }) + const currentVersion = await LivingCurrentVersion( + organization, + projectExisting._id, + projectExisting.Present_version + ); + if (!currentVersion) return { status: "CurrentVersion Data not found" }; + const findThreadId = await ThreadModel(organization).findOne({ + _id: threadId, + createdBy: userId, + }); if (!findThreadId) { return { status: "can't deleted" }; } - const deleteThread = await ThreadModel(organization).findOneAndDelete({ _id: threadId, createdBy: userId }) + const deleteThread = await ThreadModel(organization).findOneAndUpdate( + { _id: threadId, createdBy: userId }, + { isArchive: true } + ); return { status: "Success", data: deleteThread, }; } catch (error) { - console.log("error: ", error); return { status: error, }; } -} +}; +export const updateThreadTitle = async (data: IThread) => { + try { + const { + projectId, + userId, + threadTitle, + organization, + threadId, + commentId, + } = data; + + const userExisting = await existingUser(userId, organization); + if (!userExisting) { + return { + status: "user_not_found", + }; + } + const projectExisting = await existingProjectByIdWithoutUser( + projectId, + organization + ); + + if (!projectExisting) { + return { status: "Project not found" }; + } + const currentVersion = await LivingCurrentVersion( + organization, + projectExisting._id, + projectExisting.Present_version + ); + if (!currentVersion) return { status: "CurrentVersion Data not found" }; + const findThreadId = await ThreadModel(organization).findById(threadId); + if (findThreadId) { + const updateThread = await ThreadModel(organization).findOneAndUpdate( + { + _id: threadId, + createdBy: userId, + }, + { threadTitle: threadTitle }, + { + new: true, + } + ); + + return { + status: "Success", + data: updateThread, + }; + } + } catch (error) { + return { + status: error, + }; + } +}; export const addComments = async (data: IThread) => { try { - const { projectId, userId, comments, organization, threadId } = data + const { projectId, userId, comment, organization, threadId, commentId } = + data; const userExisting = await existingUser(userId, organization); if (!userExisting) { return { @@ -100,31 +210,73 @@ export const addComments = async (data: IThread) => { } const projectExisting = await existingProjectByIdWithoutUser( projectId, - organization, + organization ); if (!projectExisting) { return { status: "Project not found" }; } - const findThreadId = await ThreadModel(organization).findById(threadId) + const currentVersion = await LivingCurrentVersion( + organization, + projectExisting._id, + projectExisting.Present_version + ); + if (!currentVersion) return { status: "CurrentVersion Data not found" }; + const findThreadId = await ThreadModel(organization).findById(threadId); + if (commentId) { + const updated = await ThreadModel(organization).findOneAndUpdate( + { + _id: threadId, + "comments._id": commentId, + }, + { + $set: { + "comments.$.comment": comment, + "comments.$.createdAt": Date.now(), + }, + }, + { + new: true, + } + ); - const newComment = { userId, comment: comments, timestamp: Date.now() }; - findThreadId?.replies.push(newComment) - await findThreadId?.save() - return { - status: "Success", - data: newComment.comment, - }; + if (updated) { + const updatedComment = updated?.comments?.find( + (c: any) => c._id.toString() === commentId + ); + + return { + status: "updated", + data: updatedComment, + }; + } + } else { + const newComment = { + userId, + comment: comment, + isArchive: false, + createdAt: Date.now(), + }; + findThreadId?.comments.push(newComment); + await findThreadId?.save(); + const savedComment = findThreadId?.comments[ + findThreadId.comments.length - 1 + ] as IComment; + + return { + status: "Success", + data: savedComment, + }; + } } catch (error) { - console.log("error: ", error); return { status: error, }; } -} +}; export const deleteComments = async (data: IThread) => { try { - const { projectId, userId, commentId, organization, threadId } = data + const { projectId, userId, commentId, organization, threadId } = data; const userExisting = await existingUser(userId, organization); if (!userExisting) { return { @@ -133,40 +285,100 @@ export const deleteComments = async (data: IThread) => { } const projectExisting = await existingProjectByIdWithoutUser( projectId, - organization, + organization ); if (!projectExisting) { return { status: "Project not found" }; } - const findThreadId = await ThreadModel(organization).findOne({ _id: threadId }) + const currentVersion = await LivingCurrentVersion( + organization, + projectExisting._id, + projectExisting.Present_version + ); + if (!currentVersion) return { status: "CurrentVersion Data not found" }; + const findThreadId = await ThreadModel(organization).findOne({ + _id: threadId, + }); if (!findThreadId) { return { status: "thread not found" }; } - const deleted = await ThreadModel(organization).updateOne( - { _id: threadId }, + const deleted = await ThreadModel(organization).findOneAndUpdate( { - $pull: { - replies: { - _id: commentId, - userId: userId, - }, + _id: threadId, + "comments._id": commentId, + }, + { + $set: { + "comments.$.isArchive": true, }, + }, + { + new: true, // returns the updated document } ); - - if (deleted.modifiedCount === 0) { - return { status: "unauthorized" }; - } return { status: "Success", - data: deleted + data: deleted, }; } catch (error) { - console.log("error: ", error); return { status: error, }; } -} \ No newline at end of file +}; +export const findThreads = async (data: IgetThread) => { + try { + const { projectId, userId, organization } = data; + const userExisting = await existingUser(userId, organization); + if (!userExisting) { + return { + status: "user_not_found", + }; + } + const projectExisting = await existingProjectByIdWithoutUser( + projectId, + organization + ); + + if (!projectExisting) { + return { status: "Project not found" }; + } + const currentVersion = await LivingCurrentVersion( + organization, + projectExisting._id, + projectExisting.Present_version + ); + if (!currentVersion) return { status: "CurrentVersion Data not found" }; + const findThreads = await ThreadModel(organization) + .find({ isArchive: false, projectId, versionId: currentVersion._id }) + .lean(); + + const formattedThreads = findThreads.map((thread) => { + const filteredComments = (thread.comments || []).filter( + (comment) => comment.isArchive === false + ); + return { + state: thread.state, + threadId: thread._id.toString(), + creatorId: thread.createdBy.toString(), + createdAt: thread.createdAt, + threadTitle: thread.threadTitle, + // lastUpdatedAt: lastUpdatedAt, + position: thread.position, + rotation: thread.rotation, + comments: filteredComments, + }; + }); + + return { + status: "Success", + data: formattedThreads, + }; + } catch (error) { + return { + status: error, + }; + } +}; diff --git a/src/shared/services/auth/authServices.ts b/src/shared/services/auth/authServices.ts index 185f4a2..f50cbc9 100644 --- a/src/shared/services/auth/authServices.ts +++ b/src/shared/services/auth/authServices.ts @@ -119,9 +119,62 @@ export const AuthLogin = async ( { userId: Existing_User._id }, { refreshToken: "" } ); - return { - status: "Already LoggedIn on another browser....Please logout!!!", + const UserData = await UsersDataModel(organization).findOne({ + userId: existingMail._id, + isArchive: false, + }); + if (!UserData) + return { + status: "User_Datas not found", + }; + const tokenValidation = tokenGenerator( + existingMail.Email, + UserData.role, + existingMail._id, + organization + ); + const refreshTokenvalidation = tokenRefreshGenerator( + existingMail.Email, + UserData.role, + existingMail._id, + organization + ); + + await handleTokenCache( + existingMail._id.toString(), + existingMail.Email, + tokenValidation, + refreshTokenvalidation + ); + + const updatedUser = await AuthModel(organization) + .findByIdAndUpdate( + existingMail._id, + { visitorBrowserID: fingerprint }, + { new: true } + ) + .select("-__v -Profilepicture"); + if (!updatedUser) + return { + status: "User update failed.", + }; + await redis.setex( + `user:${existingMail.Email}`, + 3600, + JSON.stringify(updatedUser) + ); + const finalResult = { + message: "login successfull", + email: existingMail.Email, + name: existingMail.userName, + userId: existingMail._id, + isShare: UserData.isShare, + token: tokenValidation, + refreshToken: refreshTokenvalidation, }; + // return { + // status: "Already LoggedIn on another browser....Please logout!!!", + // }; } const UserData = await UsersDataModel(organization).findOne({ userId: existingMail._id, @@ -463,3 +516,136 @@ async function handleTokenCache( return error; } } + +export const AuthLogins = async ( + data: IloginUser +): Promise<{ status: string; data?: object }> => { + try { + const { Email, Password, fingerprint } = data; + const email = Email.toLowerCase(); + const organization = extractOrg(email); + + const existingUser = await findExistingUserEmail(email); + if (!existingUser) return { status: "User Not Found!!! Kindly signup..." }; + + const userFromCacheOrDb = await getUserFromCacheOrDB(email); + const passwordValid = await hashValidator( + Password, + userFromCacheOrDb.Password + ); + if (!passwordValid) + return { status: "Email & Password is invalid...Check the credentials" }; + + const userData = await UsersDataModel(organization).findOne({ + userId: userFromCacheOrDb._id, + isArchive: false, + }); + if (!userData) return { status: "User_Datas not found" }; + + const alreadyLoggedInElsewhere = + userFromCacheOrDb.visitorBrowserID && + userFromCacheOrDb.visitorBrowserID !== fingerprint; + + const generateTokensAndUpdateUser = async () => { + const token = tokenGenerator( + email, + userData.role, + userFromCacheOrDb._id, + organization + ); + const refreshToken = tokenRefreshGenerator( + email, + userData.role, + userFromCacheOrDb._id, + organization + ); + + await handleTokenCache( + userFromCacheOrDb._id.toString(), + email, + token, + refreshToken + ); + + const updatedUser = await AuthModel(organization) + .findByIdAndUpdate( + userFromCacheOrDb._id, + { visitorBrowserID: fingerprint }, + { new: true } + ) + .select("-__v -Profilepicture"); + + if (!updatedUser) return null; + + await redis.setex(`user:${email}`, 3600, JSON.stringify(updatedUser)); + + return { + message: "login successfull", + email, + name: userFromCacheOrDb.userName, + userId: userFromCacheOrDb._id, + isShare: userData.isShare, + token, + refreshToken, + }; + }; + + if (alreadyLoggedInElsewhere) { + await Promise.all([ + redis.del(`token:${email}`), + redis.del(`user:${email}`), + ]); + + await AuthModel(organization).updateOne( + { Email: email }, + { visitorBrowserID: "" } + ); + await tokenType(organization).updateOne( + { userId: existingUser._id }, + { refreshToken: "" } + ); + + const newLogin = await generateTokensAndUpdateUser(); + if (!newLogin) return { status: "User update failed." }; + + return { + status: + "Already LoggedIn on another browser....ForceLogout Implemented!!!", + data: newLogin, + }; + } + + // Check redis token + const cachedTokensRaw = await redis.get(`token:${email}`); + if (cachedTokensRaw) { + try { + const cachedTokens = JSON.parse(cachedTokensRaw); + Jwt.verify(cachedTokens.token, jwt_secret); + return { + status: "Success", + data: { + message: "login successfull", + email, + name: userFromCacheOrDb.userName, + userId: userFromCacheOrDb._id, + isShare: userData.isShare, + token: cachedTokens.token, + refreshToken: cachedTokens.refreshToken, + }, + }; + } catch { + console.log("Access token expired. Generating new..."); + } + } + + const freshLogin = await generateTokensAndUpdateUser(); + if (!freshLogin) return { status: "User update failed." }; + + return { status: "Success", data: freshLogin }; + } catch (error: unknown) { + return { + status: + error instanceof Error ? error.message : "An unexpected error occurred", + }; + } +}; diff --git a/src/shared/services/builder/AisleService.ts b/src/shared/services/builder/AisleService.ts index 3fb5f41..44a9d29 100644 --- a/src/shared/services/builder/AisleService.ts +++ b/src/shared/services/builder/AisleService.ts @@ -5,6 +5,7 @@ import AisleModel, { import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IAisleDatas { userId: string; @@ -13,23 +14,34 @@ interface IAisleDatas { type?: AisleType; organization: string; projectId: string; + versionId: string; } interface IAisleDelete { userId: string; aisleUuid: string; organization: string; projectId: string; + versionId: string; } interface IProjectAisles { userId: string; organization: string; projectId: string; + versionId: string; } export const SetAisle = async ( data: IAisleDatas ): Promise<{ status: string; data?: Object }> => { try { - const { aisleUuid, points, type, organization, projectId, userId } = data; + const { + aisleUuid, + points, + type, + organization, + projectId, + userId, + versionId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -38,14 +50,26 @@ export const SetAisle = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingAisle = await AisleModel(organization).findOne({ aisleUuid: aisleUuid, projectId: projectId, + versionId: versionId, isArchive: false, }); if (ExistingAisle) { const UpdateAisle = await AisleModel(organization).findOneAndUpdate( - { aisleUuid: aisleUuid, projectId: projectId, isArchive: false }, + { + aisleUuid: aisleUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { type: type, points: points }, { new: true, runValidators: true } ); @@ -55,6 +79,7 @@ export const SetAisle = async ( const NewAisle = await AisleModel(organization).create({ aisleUuid, projectId, + versionId: versionId, type: type, points: points, createdBy: userId, @@ -83,7 +108,7 @@ export const DeleteAisle = async ( data: IAisleDelete ): Promise<{ status: string; data?: Object }> => { try { - const { aisleUuid, organization, projectId, userId } = data; + const { aisleUuid, organization, projectId, userId, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -92,14 +117,26 @@ export const DeleteAisle = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingAisle = await AisleModel(organization).findOne({ aisleUuid: aisleUuid, projectId: projectId, + versionId: versionId, isArchive: false, }); if (ExistingAisle) { await AisleModel(organization).updateOne( - { aisleUuid: aisleUuid, projectId: projectId, isArchive: false }, + { + aisleUuid: aisleUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { isArchive: true } ); return { status: "Success" }; @@ -121,7 +158,7 @@ export const GetProjectAisles = async ( data: IProjectAisles ): Promise<{ status: string; data?: Object }> => { try { - const { organization, projectId, userId } = data; + const { organization, projectId, versionId, userId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -130,9 +167,17 @@ export const GetProjectAisles = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingAisle = await AisleModel(organization) .find({ projectId: projectId, + versionId: ExistingVersion._id, isArchive: false, }) .select("aisleUuid points type"); diff --git a/src/shared/services/builder/EnvironmentService.ts b/src/shared/services/builder/EnvironmentService.ts index cd04bad..9e57814 100644 --- a/src/shared/services/builder/EnvironmentService.ts +++ b/src/shared/services/builder/EnvironmentService.ts @@ -64,6 +64,7 @@ export const setEnvironment = async ( userId, projectId, roofVisibility, + versionId: LivingProject.Present_version, wallVisibility, shadowVisibility, }); diff --git a/src/shared/services/builder/assetService.ts b/src/shared/services/builder/assetService.ts index 022c08b..d0e1261 100644 --- a/src/shared/services/builder/assetService.ts +++ b/src/shared/services/builder/assetService.ts @@ -4,7 +4,9 @@ import EventsDataModel from "../../V1Models/Simulation/eventsDataModel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; +import versionModel from "../../V1Models/Version/versionModel.ts"; interface SetAssetInput { modelUuid: string; @@ -17,6 +19,7 @@ interface SetAssetInput { isVisible: boolean; organization: string; projectId: string; + versionId: string; userId: string; } interface AssetUpdate { @@ -28,6 +31,7 @@ interface AssetUpdate { isVisible: boolean; organization: string; projectId: string; + versionId: string; userId: string; } interface DelAssetInput { @@ -35,16 +39,19 @@ interface DelAssetInput { modelName: string; organization: string; projectId: string; + versionId: string; userId: string; } interface GetAssetInput { organization: string; projectId: string; + versionId: string; userId: string; } interface ReplaceEventInput { organization: string; projectId: string; + versionId: string; userId: string; eventData: Mixed; modelUuid: string; @@ -64,6 +71,7 @@ export const setAssetModel = async ( isVisible, organization, projectId, + versionId, userId, } = data; const UserExists = await existingUser(userId, organization); @@ -74,9 +82,16 @@ export const setAssetModel = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findvalue = await assetModel(organization).findOne({ modelUuid: modelUuid, projectId: projectId, + versionId: versionId, userId: userId, isArchive: false, }); @@ -85,6 +100,7 @@ export const setAssetModel = async ( { modelUuid: modelUuid, projectId: projectId, + versionId: versionId, userId: userId, isArchive: false, }, @@ -114,6 +130,7 @@ export const setAssetModel = async ( rotation, isLocked, isVisible, + versionId, }; if (eventData) { @@ -163,6 +180,7 @@ export const setAssetModel = async ( if (typedEventData && typedEventData.type === "Conveyor") { assetDatas = { projectId: assetDoc.projectId, + versionId: assetDoc.versionId, userId: assetDoc.userId, modelUuid: assetDoc.modelUuid, modelName: assetDoc.modelName, @@ -176,6 +194,7 @@ export const setAssetModel = async ( } else if (eventData && assetDoc.type === "Vehicle") { assetDatas = { projectId: assetDoc.projectId, + versionId: assetDoc.versionId, userId: assetDoc.userId, modelUuid: assetDoc.modelUuid, modelName: assetDoc.modelName, @@ -192,6 +211,7 @@ export const setAssetModel = async ( } else if (eventData && assetDoc.type === "ArmBot") { assetDatas = { projectId: assetDoc.projectId, + versionId: assetDoc.versionId, userId: assetDoc.userId, modelUuid: assetDoc.modelUuid, modelName: assetDoc.modelName, @@ -208,6 +228,7 @@ export const setAssetModel = async ( } else if (eventData && assetDoc.type === "StaticMachine") { assetDatas = { projectId: assetDoc.projectId, + versionId: assetDoc.versionId, userId: assetDoc.userId, modelUuid: assetDoc.modelUuid, modelName: assetDoc.modelName, @@ -224,6 +245,7 @@ export const setAssetModel = async ( } else { assetDatas = { projectId: assetDoc.projectId, + versionId: assetDoc.versionId, userId: assetDoc.userId, modelUuid: assetDoc.modelUuid, modelName: assetDoc.modelName, @@ -256,7 +278,8 @@ export const deleteAssetModel = async ( data: DelAssetInput ): Promise<{ status: string; data?: Object }> => { try { - const { modelUuid, modelName, organization, projectId, userId } = data; + const { modelUuid, modelName, organization, versionId, projectId, userId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -265,10 +288,17 @@ export const deleteAssetModel = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const asset = await assetModel(organization).findOne({ modelUuid, modelName, projectId, + versionId, isArchive: false, }); if (!asset) { @@ -277,7 +307,7 @@ export const deleteAssetModel = async ( }; } const archivedAsset = await assetModel(organization).findOneAndUpdate( - { modelUuid, modelName, projectId }, + { modelUuid, modelName, projectId, versionId }, { $set: { isArchive: true } }, { new: true } ); @@ -287,7 +317,7 @@ export const deleteAssetModel = async ( }; } await EventsDataModel(organization).updateMany( - { modelUuid, projectId: projectId }, + { modelUuid, projectId: projectId, versionId: versionId }, { $set: { isArchive: true } } ); @@ -311,7 +341,8 @@ export const replaceEventDatas = async ( data: ReplaceEventInput ): Promise<{ status: string; data?: Object }> => { try { - const { modelUuid, organization, eventData, projectId, userId } = data; + const { modelUuid, organization, eventData, versionId, projectId, userId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -320,9 +351,16 @@ export const replaceEventDatas = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingModel = await assetModel(organization).findOne({ modelUuid: modelUuid, projectId: projectId, + versionId: versionId, isArchive: false, }); if (!existingModel) { @@ -339,7 +377,12 @@ export const replaceEventDatas = async ( speed = typedEventData?.speed; } const updatedModel = await assetModel(organization).findOneAndUpdate( - { modelUuid, projectId, isArchive: false }, + { + modelUuid, + projectId, + versionId: versionId, + isArchive: false, + }, { points: typedEventData?.points, type: typedEventData?.type ?? existingModel?.type, @@ -377,6 +420,7 @@ export const updateAssetPositionRotation = async ( isVisible, organization, projectId, + versionId, userId, } = data; const UserExists = await existingUser(userId, organization); @@ -387,9 +431,16 @@ export const updateAssetPositionRotation = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const currentVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!currentVersion) return { status: "Version Data not found" }; const existingAsset = await assetModel(organization).findOne({ modelUuid: modelUuid, projectId: projectId, + versionId: versionId, isArchive: false, }); if (!existingAsset) { @@ -399,6 +450,7 @@ export const updateAssetPositionRotation = async ( { modelUuid: modelUuid, projectId: projectId, + versionId: versionId, modelName: modelName, isArchive: false, }, @@ -429,7 +481,7 @@ export const getFloorItems = async ( data: GetAssetInput ): Promise<{ status: string; data?: Object }> => { try { - const { organization, projectId, userId } = data; + const { organization, projectId, versionId, userId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -438,8 +490,20 @@ export const getFloorItems = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findValues = await assetModel(organization) - .find({ isArchive: false, projectId: projectId }) + .find({ + isArchive: false, + projectId: projectId, + versionId: ExistingVersion._id, + }) .select("-_id -isArchive"); if (!findValues || findValues.length === 0) { @@ -449,6 +513,7 @@ export const getFloorItems = async ( const response = findValues.map((item) => { const responseItem: any = { projectId: item.productId, + versionId: item.versionId, modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, diff --git a/src/shared/services/builder/cameraService.ts b/src/shared/services/builder/cameraService.ts index 1c00c95..ce446df 100644 --- a/src/shared/services/builder/cameraService.ts +++ b/src/shared/services/builder/cameraService.ts @@ -3,6 +3,7 @@ import cameraModel from "../../V1Models/Builder/cameraModel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IcameraData { userId: string; @@ -25,8 +26,14 @@ export const SetCamera = async ( data: IcameraData ): Promise<{ status: string; data?: Object }> => { try { - const { userId, position, target, rotation, organization, projectId } = - data; + const { + userId, + position, + target, + rotation, + organization, + projectId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -38,6 +45,7 @@ export const SetCamera = async ( const existingCamera = await cameraModel(organization).findOne({ userId: userId, projectId: projectId, + isArchive: false, }); if (existingCamera) { diff --git a/src/shared/services/builder/lineService.ts b/src/shared/services/builder/lineService.ts index 6d3be5d..798ceba 100644 --- a/src/shared/services/builder/lineService.ts +++ b/src/shared/services/builder/lineService.ts @@ -2,6 +2,7 @@ import lineModel from "../../V1Models/Builder/linesModel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface ILineItems { organization: string; @@ -9,11 +10,13 @@ interface ILineItems { line: []; type: string; projectId: string; + versionId: string; userId: string; } interface ILineGet { organization: string; projectId: string; + versionId: string; userId: string; } interface ILineUpdate { @@ -21,31 +24,36 @@ interface ILineUpdate { uuid: number; position: {}; projectId: string; + versionId: string; userId: string; } interface ILineDelete { organization: string; line: []; projectId: string; + versionId: string; userId: string; } interface ILinePointsDelete { organization: string; uuid: string; projectId: string; + versionId: string; userId: string; } interface ILayerDelete { organization: string; layer: number; projectId: string; + versionId: string; userId: string; } export const CreateLineItems = async ( data: ILineItems ): Promise<{ status: string; data?: Object }> => { try { - const { organization, line, type, layer, projectId, userId } = data; + const { organization, line, type, layer, projectId, versionId, userId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -54,11 +62,18 @@ export const CreateLineItems = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const newLine = await lineModel(organization).create({ layer, line, type, projectId, + versionId: versionId, }); return { status: "Success", data: newLine }; } catch (error: unknown) { @@ -77,7 +92,7 @@ export const UpdateLineItems = async ( data: ILineUpdate ): Promise<{ status: string; data?: Object }> => { try { - const { organization, projectId, uuid, position, userId } = data; + const { organization, projectId, versionId, uuid, position, userId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -86,8 +101,18 @@ export const UpdateLineItems = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const updateResult = await lineModel(organization).updateMany( - { "line.uuid": uuid, projectId: projectId }, + { + "line.uuid": uuid, + projectId: projectId, + versionId: versionId, + }, { $set: { "line.$.position": position } } ); @@ -111,7 +136,7 @@ export const DeleteLineItems = async ( data: ILineDelete ): Promise<{ status: string; data?: object }> => { try { - const { organization, projectId, line, userId } = data; + const { organization, projectId, versionId, line, userId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -120,12 +145,19 @@ export const DeleteLineItems = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const inputUuids = line.map((item: any) => { return item.uuid; }); const findValue = await lineModel(organization).findOneAndDelete({ projectId, + versionId: versionId, isArchive: false, "line.uuid": { $all: inputUuids }, }); @@ -156,7 +188,7 @@ export const DeleteLayer = async ( data: ILayerDelete ): Promise<{ status: string; data?: object }> => { try { - const { organization, projectId, layer, userId } = data; + const { organization, projectId, versionId, layer, userId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -165,9 +197,16 @@ export const DeleteLayer = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findValue = await lineModel(organization).find({ layer: layer, projectId: projectId, + versionId: versionId, isArchive: false, }); @@ -175,7 +214,12 @@ export const DeleteLayer = async ( return { status: "layer not found" }; } else { await lineModel(organization).deleteMany( - { projectId: projectId, layer: layer, isArchive: false }, + { + projectId: projectId, + versionId: versionId, + layer: layer, + isArchive: false, + }, { layer: layer } ); @@ -205,11 +249,25 @@ export const GetLinesService = async ( data: ILineGet ): Promise<{ status: string; data?: object }> => { try { - const { organization, projectId, userId } = data; + const { organization, projectId, versionId,userId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findValue = await lineModel(organization).find({ projectId: projectId, + versionId: ExistingVersion._id, isArchive: false, }); if (!findValue) { @@ -233,7 +291,7 @@ export const DeleteLinePoints = async ( data: ILinePointsDelete ): Promise<{ status: string; data?: object | string }> => { try { - const { organization, projectId, uuid, userId } = data; + const { organization, projectId, uuid, userId, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -242,8 +300,19 @@ export const DeleteLinePoints = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findValue = await lineModel(organization).deleteMany( - { projectId: projectId, isArchive: false, "line.uuid": uuid }, + { + projectId: projectId, + versionId: versionId, + isArchive: false, + "line.uuid": uuid, + }, { "line.uuid": uuid, } diff --git a/src/shared/services/builder/wallService.ts b/src/shared/services/builder/wallService.ts index 89555dc..2d29a22 100644 --- a/src/shared/services/builder/wallService.ts +++ b/src/shared/services/builder/wallService.ts @@ -1,11 +1,11 @@ -import wallItemModel from "../../../shared/model/builder/assets/wallitems-Model.ts"; +import wallItemModel from "../../V1Models/Builder/wallItemsModel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IWallSetupData { modelUuid: string; - assetId: string; modelName: string; type: string; csgposition: []; @@ -15,12 +15,15 @@ interface IWallSetupData { scale: []; organization: string; projectId: string; + versionId: string; userId: string; + assetId: string; } interface IWallGet { userId: string; organization: string; projectId: string; + versionId: string; } interface IWallDelete { userId: string; @@ -28,6 +31,7 @@ interface IWallDelete { modelName: string; organization: string; projectId: string; + versionId: string; } interface IWallItemResult { data?: Object; @@ -41,16 +45,18 @@ export const setWallItems = async ( userId, modelUuid, modelName, + assetId, position, type, csgposition, csgscale, quaternion, - assetId, scale, projectId, + versionId, organization, } = data; + const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -59,13 +65,27 @@ export const setWallItems = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findvalue = await wallItemModel(organization).findOne({ - modelUuid: modelUuid,isArchive:false + modelUuid: modelUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, }); if (findvalue) { const updatevalue = await wallItemModel(organization).findOneAndUpdate( - { modelUuid: modelUuid, projectId: projectId,isArchive:false }, + { + modelUuid: modelUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { modelName, position, @@ -87,14 +107,15 @@ export const setWallItems = async ( modelName, position, type, - projectId, + versionId: versionId, + projectId: projectId, csgposition, csgscale, quaternion, scale, + userId, assetId, }); - console.log("newValue: ", newValue); return { // status: "wall Item created successfully", status: "Success", @@ -115,7 +136,7 @@ export const setWallItems = async ( }; export const getWallItems = async (data: IWallGet) => { try { - const { organization, userId, projectId } = data; + const { organization, userId, projectId, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -124,8 +145,17 @@ export const getWallItems = async (data: IWallGet) => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findValue = await wallItemModel(organization).find({ - projectId: projectId,isArchive:false + projectId: projectId, + versionId: ExistingVersion._id, + isArchive: false, }); if (!findValue) { return { @@ -154,7 +184,8 @@ export const deleteWallItems = async ( data: IWallDelete ): Promise => { try { - const { modelUuid, modelName, organization, userId, projectId } = data; + const { modelUuid, modelName, organization, userId, versionId, projectId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -163,10 +194,18 @@ export const deleteWallItems = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findValue = await wallItemModel(organization).findOneAndDelete({ modelUuid: modelUuid, modelName: modelName, - projectId: projectId,isArchive:false + projectId: projectId, + versionId: versionId, + isArchive: false, }); if (!findValue) { return { diff --git a/src/shared/services/builder/zoneService.ts b/src/shared/services/builder/zoneService.ts index 740c984..1224513 100644 --- a/src/shared/services/builder/zoneService.ts +++ b/src/shared/services/builder/zoneService.ts @@ -7,10 +7,12 @@ import widgetModel from "../../V1Models/Vizualization/widgemodel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface ISetZone { organization: string; projectId: string; + versionId: string; zoneData: { zoneUuid: string; points: []; @@ -24,12 +26,21 @@ interface ISetZone { interface IZone { organization: string; projectId: string; + versionId: string; + zoneUuid: string; + userId: string; +} +interface IZoneDel { + organization: string; + projectId: string; + versionId: string; zoneUuid: string; userId: string; } interface IVizZone { organization: string; projectId: string; + versionId: string; userId: string; } interface IResult { @@ -39,12 +50,13 @@ interface IResult { interface IGetZones { organization: string; projectId: string; + versionId: string; userId: string; } export const SetZone = async (data: ISetZone): Promise => { try { - const { organization, projectId, zoneData, userId } = data; + const { organization, projectId, versionId, zoneData, userId } = data; const zoneUuid = zoneData.zoneUuid; const points = zoneData.points; const zoneName = zoneData.zoneName; @@ -59,22 +71,35 @@ export const SetZone = async (data: ISetZone): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findZoneId = await zoneModel(organization).findOne({ projectId: projectId, + versionId: versionId, zoneUuid: zoneUuid, }); if (findZoneId) { const updateZone = await zoneModel(organization) - .findOneAndUpdate( - { zoneUuid: zoneUuid, projectId: projectId, isArchive: false }, - { - points: points, - viewPortposition: viewPortposition, - viewPortCenter: viewPortCenter, - }, - { new: true } - ) - .select("-_id -__v"); + .findOneAndUpdate( + { + zoneUuid: zoneUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, + { + zoneName: zoneName, + points: points, + viewPortposition: viewPortposition, + viewPortCenter: viewPortCenter, + }, + { new: true } + ) + .select("-_id -__v"); return { status: "zone updated", data: updateZone }; } else { const zoneCreate = await zoneModel(organization).create({ @@ -84,11 +109,12 @@ export const SetZone = async (data: ISetZone): Promise => { zoneName: zoneName, points, layer, + versionId: versionId, viewPortCenter, viewPortposition, }); const createdZone = await zoneModel(organization) - .findById(zoneCreate._id) + .findById({ _id: zoneCreate._id, isArchive: false }) .select("-_id -__v"); return { status: "Success", data: createdZone }; } @@ -104,9 +130,9 @@ export const SetZone = async (data: ISetZone): Promise => { } } }; -export const DelZone = async (data: IZone): Promise => { +export const DelZone = async (data: IZoneDel): Promise => { try { - const { organization, userId, zoneUuid, projectId } = data; + const { organization, userId, zoneUuid, versionId, projectId } = data; const findZoneId = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, projectId: projectId, @@ -120,12 +146,19 @@ export const DelZone = async (data: IZone): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; if (findZoneId) { const deleteZone = await zoneModel(organization) .findOneAndUpdate( { zoneUuid: zoneUuid, createdBy: userId, + versionId: versionId, projectId: projectId, isArchive: false, }, @@ -136,6 +169,8 @@ export const DelZone = async (data: IZone): Promise => { if (deleteZone) { const panels = await panelModel(organization).find({ zoneUuid, + projectId: projectId, + versionId: versionId, isArchive: false, }); @@ -149,21 +184,41 @@ export const DelZone = async (data: IZone): Promise => { ); await panelModel(organization).updateMany( - { zoneUuid, isArchive: false }, + { + zoneUuid, + versionId: versionId, + projectId: projectId, + isArchive: false, + }, { $set: { isArchive: true } } ); await Promise.all([ widget3dModel(organization).updateMany( - { zoneUuid, isArchive: false }, + { + zoneUuid, + versionId: versionId, + projectId: projectId, + isArchive: false, + }, { $set: { isArchive: true } } ), templateModel(organization).updateMany( - { zoneUuid, isArchive: false }, + { + zoneUuid, + versionId: versionId, + projectId: projectId, + isArchive: false, + }, { $set: { isArchive: true } } ), floatWidgetModel(organization).updateMany( - { zoneUuid, isArchive: false }, + { + zoneUuid, + versionId: versionId, + projectId: projectId, + isArchive: false, + }, { $set: { isArchive: true } } ), ]); @@ -192,11 +247,28 @@ export const DelZone = async (data: IZone): Promise => { }; export const GetZones = async (data: IGetZones): Promise => { try { - const { organization, userId, projectId } = data; + const { organization, userId, projectId, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findZoneId = await zoneModel(organization) - .find({ projectId: projectId, isArchive: false }) + .find({ + projectId: projectId, + versionId: ExistingVersion._id, + isArchive: false, + }) .select( "zoneUuid zoneName layer points viewPortCenter viewPortposition -_id" ); @@ -219,7 +291,7 @@ export const GetZones = async (data: IGetZones): Promise => { }; export const ZoneData = async (data: IZone): Promise => { try { - const { organization, userId, projectId, zoneUuid } = data; + const { organization, userId, projectId, zoneUuid, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -228,9 +300,17 @@ export const ZoneData = async (data: IZone): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const findZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, projectId: projectId, + versionId: ExistingVersion._id, isArchive: false, }); if (findZone) @@ -255,7 +335,7 @@ export const ZoneData = async (data: IZone): Promise => { }; export const SingleZonePanelData = async (data: IZone): Promise => { try { - const { organization, userId, projectId, zoneUuid } = data; + const { organization, userId, projectId, versionId, zoneUuid } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -264,10 +344,18 @@ export const SingleZonePanelData = async (data: IZone): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization) .findOne({ projectId: projectId, zoneUuid: zoneUuid, + versionId: ExistingVersion._id, isArchive: false, }) .select( @@ -278,6 +366,8 @@ export const SingleZonePanelData = async (data: IZone): Promise => { } else { const panelData = await panelModel(organization).find({ zoneUuid: zoneUuid, + versionId: ExistingVersion._id, + projectId: projectId, isArchive: false, }); const zoneName = existingZone.zoneName as string; @@ -286,6 +376,8 @@ export const SingleZonePanelData = async (data: IZone): Promise => { panelData.map(async (data) => { const widgetDataArray = await widgetModel(organization).find({ panelID: data._id, + versionId: ExistingVersion._id, + projectId: projectId, isArchive: false, }); @@ -329,7 +421,7 @@ export const SingleZonePanelData = async (data: IZone): Promise => { }; export const VizZoneDatas = async (data: IVizZone): Promise => { try { - const { organization, userId, projectId } = data; + const { organization, userId, projectId, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -338,9 +430,17 @@ export const VizZoneDatas = async (data: IVizZone): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZones = await zoneModel(organization) .find({ projectId: projectId, + versionId: ExistingVersion._id, isArchive: false, }) .select( @@ -353,6 +453,8 @@ export const VizZoneDatas = async (data: IVizZone): Promise => { existingZones.map(async (zone) => { const panelData = await panelModel(organization).find({ zoneUuid: zone._id, + versionId: ExistingVersion._id, + projectId: projectId, isArchive: false, }); @@ -360,6 +462,8 @@ export const VizZoneDatas = async (data: IVizZone): Promise => { panelData.map(async (panel) => { const widgetDataArray = await widgetModel(organization).find({ panelID: panel._id, + versionId: ExistingVersion._id, + projectId: projectId, isArchive: false, }); diff --git a/src/shared/services/collaborative/lineService-collab.ts b/src/shared/services/collaborative/lineService-collab.ts new file mode 100644 index 0000000..cdf305b --- /dev/null +++ b/src/shared/services/collaborative/lineService-collab.ts @@ -0,0 +1,231 @@ +import * as Y from "yjs"; + +import lineModel from "../../V1Models/Builder/linesModel.ts"; +import { existingUser,existingProjectById } from "../helpers/v1projecthelperFns.ts"; +// import { lineMap } from "../yjs/yjsStore.ts"; +import { getYDoc } from "../../../socket-server/utils/yjs/yjsRoomjoin.ts"; +import { saveSnapshotService } from "../yjs/snapshot.ts"; + +interface ILinePoint { + position: { + x: number; + y: number; + z: number; + }; + uuid: string; +} +interface ILineItems { + organization: string; + layer: number; + line:ILinePoint[]; + type: string; + projectId: string; + versionId: string; + userId: string; +} +interface ILineGet { + organization: string; + projectId: string; + userId: string; +} +interface IPosition { + x: number; + y: number; + z: number; +} +interface ILineUpdate { + organization: string; + uuid: number; + position: IPosition; + projectId: string; + versionId: string; + userId: string; +} +interface ILineDelete { + organization: string; + line: []; + projectId: string; + versionId: string; + userId: string; +} +interface ILinePointsDelete { + organization: string; + uuid: string; + projectId: string; + userId: string; +} +interface ILayerDelete { + organization: string; + layer: number; + projectId: string; + userId: string; +} +// const ydoc = new Y.Doc(); +// const lineMap = ydoc.getMap("lines"); + +export const createLineService = async ( + data: ILineItems +): Promise<{ status: string; data?: Object }> => { + const { organization, line, type, layer, projectId,versionId, userId } = data; + console.log('data: ', data); + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const newLine = await lineModel(organization).create({ + layer, + line, + type, + versionId: versionId, + projectId, + }); +const ydoc = await getYDoc(projectId?.toString(), versionId?.toString(),organization?.toString()); +console.log('ydoc: ', ydoc); + const lineMap = ydoc.getMap("lines"); + console.log('lineMap: ', lineMap); + + const yLine = new Y.Map(); + yLine.set("layer", layer); + yLine.set("type", type); + yLine.set("projectId", projectId?.toString()); + yLine.set("userId", userId?.toString()); + yLine.set("versionId", LivingProject?.Present_version?.toString()); + + const yLineArray = new Y.Array(); + console.log('yLineArray: ', yLineArray); + for (const point of line) { + const yPoint = new Y.Map(); + if (point?.position) { + yPoint.set("position", new Y.Map([ + ["x", point.position.x], + ["y", point.position.y], + ["z", point.position.z] + ])); + } + yPoint.set("uuid", point.uuid); + yLineArray.push([yPoint]); + } + yLine.set("line", yLineArray); + + lineMap.set(`${newLine._id.toString()}`, yLine); + console.log("Line added to map:", lineMap.get(`${newLine._id.toString()}`)); + + await saveSnapshotService({ + organization, + projectId, + versionId: versionId , + createdBy: userId, + label: `Auto-snapshot after create line`, // ✅ Label + ydoc + }); + + return { status: "Success", data: newLine }; + +}; +export const updateLineService = async ( + data: ILineUpdate +): Promise<{ status: string; data?: Object }> => { + const { uuid, position,projectId,versionId, userId,organization } = data; + console.log('data: ', data); + + const updated = await lineModel(organization).findOneAndUpdate( + { "line.uuid": uuid }, + { $set: { "line.$.position": position } }, + { new: true } + ); + + console.log('updated: ', updated); +if (updated) { + const ydoc =await getYDoc(projectId, versionId,organization); + const yLine = ydoc.getMap("lines").get(`${updated._id}`); + console.log('yLine: ', yLine); + + if (yLine && yLine instanceof Y.Map) { + const yLineArray = yLine.get("line"); + console.log('yLineArray: ', yLineArray); + if (yLineArray && yLineArray instanceof Y.Array) { + for (let i = 0; i < yLineArray.length; i++) { + const yPoint = yLineArray.get(i); + if (yPoint?.get("uuid") === uuid) { + const yPos = new Y.Map(); + yPos.set("x", position.x); + yPos.set("y", position.y); + yPos.set("z", position.z); + yPoint.set("position", yPos); + console.log(`✅ Updated Yjs lineMap for uuid: ${uuid}`); + break; + } + } + } + } + await saveSnapshotService({ + organization, + projectId, + versionId: versionId , + createdBy: userId, + label: `Auto-snapshot after update line`, // ✅ Label + ydoc + }); + return { status: "Success", data: updated }; + } + + return { status: "Update failed" }; +}; + +export const DeleteLineItems = async ( + data: ILineDelete +): Promise<{ status: string; data?: object }> => { + try { + const { organization, projectId, versionId, line, userId } = data; + console.log('data: ', data); + + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + + const LivingProject = await existingProjectById(projectId, organization, userId); + if (!LivingProject) return { status: "Project not found" }; + + const inputUuids = line.map((item: any) => item.uuid); + + // 🧩 Delete in MongoDB + const findValue = await lineModel(organization).findOneAndDelete({ + projectId, + isArchive: false, + "line.uuid": { $all: inputUuids }, + }); + + if (!findValue) { + return { status: "line not found" }; + } + + // 🧠 Delete from Y.Doc + const ydoc =await getYDoc(projectId, versionId ,organization); + const lineMap = ydoc.getMap("lines"); + + lineMap.delete(`${findValue._id}`); // same _id used while storing in Yjs map + + console.log(`🧼 Yjs: line ${findValue._id} deleted`); + await saveSnapshotService({ + organization, + projectId, + versionId: versionId , + createdBy: userId, + label: `Auto-snapshot after update line`, // ✅ Label + ydoc + }); + return { + status: "Success", + data: findValue, + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { status: error.message }; + } else { + return { status: "An unexpected error occurred" }; + } + } +} \ No newline at end of file diff --git a/src/shared/services/dummyservice.ts b/src/shared/services/dummyservice.ts new file mode 100644 index 0000000..a28b055 --- /dev/null +++ b/src/shared/services/dummyservice.ts @@ -0,0 +1,499 @@ +import EventsDummyModel from "../V1Models/dummy/eventDummy.ts"; +import ProductDummyModel from "../V1Models/dummy/productDumy.ts"; +import { + existingProjectById, + existingUser, +} from "./helpers/v1projecthelperFns.ts"; +import actionDummyModel, { + ConveyorActionSchema, + MachineActionSchema, + RoboticArmActionSchema, + StorageActionSchema, + VehicleActionSchema, +} from "../V1Models/dummy/actionDummy.ts"; +interface IEventDatainterface { + modelUuid: string; + modelName: string; + position: [number]; + rotation: [number]; + type: string; + speed: string; + point: { + uuid: string; + position: [number]; + rotation: [number]; + action: IActioninterface; + actions: IActionsinterface; + }; + points: { + uuid: string; + position: [number]; + rotation: [number]; + action: IActioninterface; + }[]; +} +interface IActionsinterface { + modelUuid: string; + modelName: string; + productUuid: string; + type: string; + actions: RoboticArmActionSchema[]; +} +interface IActioninterface { + modelUuid: string; + modelName: string; + productUuid: string; + type: string; + Action: + | VehicleActionSchema + | ConveyorActionSchema + | MachineActionSchema + | StorageActionSchema; + Actions: RoboticArmActionSchema[]; +} +interface Iproduct { + productName: string; + productUuid: string; + eventDatas: IEventDatainterface; + userId: string; + organization: string; + projectId: string; +} +interface IProductEvent { + productUuid: string; + userId: string; + organization: string; + projectId: string; +} +interface IDelEvent { + productUuid: string; + modelUuid: string; + userId: string; + organization: string; + projectId: string; +} +interface IProjectProducts { + userId: string; + organization: string; + projectId: string; +} +interface IProductRename { + userId: string; + organization: string; + projectId: string; + productUuid: string; + productName: string; +} +interface IResult { + status: string; + data?: object; +} + +export const productAdddummy = async (data: Iproduct): Promise => { + try { + const { + productName, + productUuid, + eventDatas, + projectId, + userId, + organization, + } = data; + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const existingProduct = await ProductAFind( + productUuid, + projectId, + organization + ); + if (existingProduct) { + const existingEventData = await EventsDummyModel(organization).findOne({ + productUuid: productUuid, + projectId: projectId, + modelUuid: eventDatas.modelUuid, + isArchive: false, + }); + if (existingEventData) { + await EventUpdateFunction( + organization, + eventDatas, + productUuid, + projectId + ); + return { + status: "EventData updated successfully", + }; + } else { + await EventCreateFunction( + organization, + eventDatas, + productUuid, + projectId + ); + return { + status: "EventData add successfully", + }; + } + } else { + const newProduct = await ProductDummyModel(organization).create({ + productUuid: productUuid, + projectId: projectId, + productName: productName, + }); + if (newProduct) { + if (eventDatas) { + await EventCreateFunction( + organization, + eventDatas, + productUuid, + projectId + ); + } + } + return { + status: "Success", + }; + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; + +async function EventCreateFunction( + organization: string, + eventDatas: IEventDatainterface, + productUuid: string, + projectId: string +) { + await EventsDummyModel(organization).create({ + projectId: projectId, + productUuid: productUuid, + modelUuid: eventDatas?.modelUuid as string, + modelName: eventDatas?.modelName, + position: eventDatas?.position, + rotation: eventDatas?.rotation, + type: eventDatas?.type, + speed: eventDatas?.speed, + point: { + uuid: eventDatas.point?.uuid, + }, + points: eventDatas.points?.map((point) => ({ + uuid: point.uuid, + })), + }); + eventDatas.points; + await actionDummyModel(organization).create({ + projectId: projectId, + productUuid: productUuid, + modelUuid: eventDatas?.modelUuid as string, + modelName: eventDatas?.modelName, + type: eventDatas?.type, + // Action: { + // uuid: eventDatas.point?.uuid, + // Action: eventDatas.point?.action || eventDatas.points?.action, + // }, + // Actions: eventDatas.point?.actions.map((action) => ({ + // uuid: action.uuid, + // Action: action.action, + // })), + }); +} +async function EventUpdateFunction( + organization: string, + eventDatas: IEventDatainterface, + productUuid: string, + projectId: string +) { + await EventsDummyModel(organization).findOneAndUpdate( + { + projectId: projectId, + modelUuid: eventDatas.modelUuid, + productUuid: productUuid, + isArchive: false, + }, + { + modelUuid: eventDatas?.modelUuid, + modelName: eventDatas?.modelName, + position: eventDatas?.position, + rotation: eventDatas?.rotation, + type: eventDatas?.type, + speed: eventDatas?.speed, + point: eventDatas?.point, + points: eventDatas?.points, + } + ); +} +async function ProductAFind( + productUuid: string, + projectId: string, + organization: string +) { + const existingProduct = await ProductDummyModel(organization).findOne({ + productUuid: productUuid, + projectId: projectId, + isArchive: false, + }); + + return existingProduct; +} +export const getProductDatas = async ( + data: IProductEvent +): Promise => { + try { + const { productUuid, projectId, userId, organization } = data; + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const ExistingProduct = await ProductAFind( + productUuid, + projectId, + organization + ); + if (!ExistingProduct) return { status: "Product not found" }; + + const existingEventDatas = await EventsDummyModel(organization) + .find({ + productUuid: productUuid, + projectId: projectId, + isArchive: false, + }) + .select("-productUuid"); + if (!existingEventDatas) { + return { status: "Events not found", data: [] }; + } + return { status: "Success", data: existingEventDatas }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; +export const productDataDelete = async ( + data: IProductEvent +): Promise => { + try { + const { productUuid, projectId, userId, organization } = data; + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const ExistingProduct = await ProductAFind( + productUuid, + projectId, + organization + ); + if (!ExistingProduct) return { status: "Product not found" }; + + await ProductDummyModel(organization).findOneAndUpdate( + { productUuid: productUuid, projectId: projectId, isArchive: false }, + { + isArchive: true, + }, + { new: true } + ); + const existingEventDatas = await EventsDummyModel(organization).find({ + productUuid: productUuid, + projectId: projectId, + isArchive: false, + }); + if (existingEventDatas) { + await EventsDummyModel(organization).updateMany( + { productUuid, projectId, isArchive: false }, + { $set: { isArchive: true } } + ); + } + return { + status: "Success", + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; +export const EventDataDelete = async (data: IDelEvent): Promise => { + try { + const { modelUuid, productUuid, projectId, userId, organization } = data; + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const ExistingProduct = await ProductAFind( + productUuid, + projectId, + organization + ); + if (!ExistingProduct) return { status: "Product not found" }; + const EventDel = await EventsDummyModel(organization).findOneAndUpdate( + { + productUuid: productUuid, + projectId: projectId, + isArchive: false, + modelUuid: modelUuid, + }, + { + isArchive: true, + }, + { new: true } + ); + if (!EventDel) + return { + status: "Event Delete Unsuccessful", + }; + return { + status: "Success", + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; +export const AllProductDatas = async ( + data: IProjectProducts +): Promise => { + try { + const { projectId, userId, organization } = data; + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const existingProduct = await ProductDummyModel(organization).find({ + isArchive: false, + projectId: projectId, + }); + if (!existingProduct) { + return { + status: "No products found", + data: [], + }; + } + const result = []; + + for (const product of existingProduct) { + const eventDatas = await EventsDummyModel(organization) + .find({ + projectId: product.projectId, + productUuid: product.productUuid, + isArchive: false, + }) + .select("-productUuid -isArchive -createdAt -updatedAt -__v -_id"); + + result.push({ + projectId: product.projectId, + productName: product.productName, + productUuid: product.productUuid, + eventDatas, + }); + } + + return { + status: "Success", + data: result, + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; +export const productRename = async (data: IProductRename): Promise => { + try { + const { productName, productUuid, projectId, userId, organization } = data; + const UserExists = await existingUser(userId, organization); + if (!UserExists) return { status: "User not found" }; + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const ExistingProduct = await ProductAFind( + productUuid, + projectId, + organization + ); + if (!ExistingProduct) return { status: "Product not found" }; + + const UpdateName = await ProductDummyModel(organization).findOneAndUpdate( + { productUuid: productUuid, projectId: projectId, isArchive: false }, + { + productName: productName, + }, + { new: true } + ); + if (!UpdateName) { + return { + status: "Rename Unsuccessful", + }; + } + return { + status: "Success", + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; diff --git a/src/shared/services/helpers/v1projecthelperFns.ts b/src/shared/services/helpers/v1projecthelperFns.ts index abcebab..02006c4 100644 --- a/src/shared/services/helpers/v1projecthelperFns.ts +++ b/src/shared/services/helpers/v1projecthelperFns.ts @@ -26,7 +26,18 @@ export const existingUser = async (userId: string, organization: string) => { }); return userData; }; - +export async function LivingCurrentVersion( + organization: string, + projectId: string, + versionId: string +) { + const livingCurentVersion = await versionModel(organization).findOne({ + _id: versionId, + projectId: projectId, + isArchive: false, + }); + return livingCurentVersion; +} export const archiveProject = async ( projectId: string, organization: string diff --git a/src/shared/services/simulation/productService.ts b/src/shared/services/simulation/productService.ts index a9b36a0..0897e19 100644 --- a/src/shared/services/simulation/productService.ts +++ b/src/shared/services/simulation/productService.ts @@ -4,7 +4,9 @@ import ProductModel from "../../V1Models/Simulation/productModel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; +import versionModel from "../../V1Models/Version/versionModel.ts"; interface IEventDatainterface { modelUuid: string; modelName: string; @@ -31,12 +33,21 @@ interface Iproduct { userId: string; organization: string; projectId: string; + versionId: string; } interface IProductEvent { productUuid: string; userId: string; organization: string; projectId: string; + versionId: string; +} +interface IProductEventDel { + productUuid: string; + userId: string; + organization: string; + projectId: string; + versionId: string; } interface IDelEvent { productUuid: string; @@ -44,16 +55,19 @@ interface IDelEvent { userId: string; organization: string; projectId: string; + versionId: string; } interface IProjectProducts { userId: string; organization: string; projectId: string; + versionId: string; } interface IProductRename { userId: string; organization: string; projectId: string; + versionId: string; productUuid: string; productName: string; } @@ -69,6 +83,7 @@ export const productAdd = async (data: Iproduct): Promise => { productUuid, eventDatas, projectId, + versionId, userId, organization, } = data; @@ -80,15 +95,23 @@ export const productAdd = async (data: Iproduct): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingProduct = await ProductAFind( productUuid, projectId, + versionId, organization ); if (existingProduct) { const existingEventData = await EventsDataModel(organization).findOne({ productUuid: productUuid, projectId: projectId, + versionId: versionId, modelUuid: eventDatas.modelUuid, isArchive: false, }); @@ -97,7 +120,8 @@ export const productAdd = async (data: Iproduct): Promise => { organization, eventDatas, productUuid, - projectId + projectId, + versionId ); return { status: "EventData updated successfully", @@ -107,7 +131,8 @@ export const productAdd = async (data: Iproduct): Promise => { organization, eventDatas, productUuid, - projectId + projectId, + versionId ); return { status: "EventData add successfully", @@ -118,6 +143,7 @@ export const productAdd = async (data: Iproduct): Promise => { productUuid: productUuid, projectId: projectId, productName: productName, + versionId: versionId, }); if (newProduct) { if (eventDatas) { @@ -125,7 +151,8 @@ export const productAdd = async (data: Iproduct): Promise => { organization, eventDatas, productUuid, - projectId + projectId, + versionId ); } } @@ -150,9 +177,11 @@ async function EventCreateFunction( organization: string, eventDatas: IEventDatainterface, productUuid: string, - projectId: string + projectId: string, + versionId: string ) { await EventsDataModel(organization).create({ + versionId: versionId, projectId: projectId, productUuid: productUuid, modelUuid: eventDatas?.modelUuid as string, @@ -169,11 +198,13 @@ async function EventUpdateFunction( organization: string, eventDatas: IEventDatainterface, productUuid: string, - projectId: string + projectId: string, + versionId: string ) { await EventsDataModel(organization).findOneAndUpdate( { projectId: projectId, + versionId: versionId, modelUuid: eventDatas.modelUuid, productUuid: productUuid, isArchive: false, @@ -193,11 +224,13 @@ async function EventUpdateFunction( async function ProductAFind( productUuid: string, projectId: string, + versionId: string, organization: string ) { const existingProduct = await ProductModel(organization).findOne({ productUuid: productUuid, projectId: projectId, + versionId: versionId, isArchive: false, }); @@ -207,7 +240,7 @@ export const getProductDatas = async ( data: IProductEvent ): Promise => { try { - const { productUuid, projectId, userId, organization } = data; + const { productUuid, projectId,versionId, userId, organization } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -216,9 +249,17 @@ export const getProductDatas = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingProduct = await ProductAFind( productUuid, projectId, + ExistingVersion._id, organization ); if (!ExistingProduct) return { status: "Product not found" }; @@ -227,6 +268,7 @@ export const getProductDatas = async ( .find({ productUuid: productUuid, projectId: projectId, + versionId: ExistingVersion._id, isArchive: false, }) .select("-productUuid"); @@ -247,10 +289,10 @@ export const getProductDatas = async ( } }; export const productDataDelete = async ( - data: IProductEvent + data: IProductEventDel ): Promise => { try { - const { productUuid, projectId, userId, organization } = data; + const { productUuid, projectId, versionId, userId, organization } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -259,15 +301,27 @@ export const productDataDelete = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingProduct = await ProductAFind( productUuid, projectId, + versionId, organization ); if (!ExistingProduct) return { status: "Product not found" }; await ProductModel(organization).findOneAndUpdate( - { productUuid: productUuid, projectId: projectId, isArchive: false }, + { + productUuid: productUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { isArchive: true, }, @@ -276,11 +330,17 @@ export const productDataDelete = async ( const existingEventDatas = await EventsDataModel(organization).find({ productUuid: productUuid, projectId: projectId, + versionId: versionId, isArchive: false, }); if (existingEventDatas) { await EventsDataModel(organization).updateMany( - { productUuid, projectId, isArchive: false }, + { + productUuid, + projectId, + versionId: versionId, + isArchive: false, + }, { $set: { isArchive: true } } ); } @@ -301,7 +361,14 @@ export const productDataDelete = async ( }; export const EventDataDelete = async (data: IDelEvent): Promise => { try { - const { modelUuid, productUuid, projectId, userId, organization } = data; + const { + modelUuid, + productUuid, + projectId, + versionId, + userId, + organization, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -310,9 +377,16 @@ export const EventDataDelete = async (data: IDelEvent): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingProduct = await ProductAFind( productUuid, projectId, + versionId, organization ); if (!ExistingProduct) return { status: "Product not found" }; @@ -320,6 +394,7 @@ export const EventDataDelete = async (data: IDelEvent): Promise => { { productUuid: productUuid, projectId: projectId, + versionId: versionId, isArchive: false, modelUuid: modelUuid, }, @@ -351,7 +426,7 @@ export const AllProductDatas = async ( data: IProjectProducts ): Promise => { try { - const { projectId, userId, organization } = data; + const { projectId, versionId ,userId, organization } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -360,8 +435,16 @@ export const AllProductDatas = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingProduct = await ProductModel(organization).find({ isArchive: false, + versionId: ExistingVersion._id, projectId: projectId, }); if (!existingProduct) { @@ -375,6 +458,7 @@ export const AllProductDatas = async ( for (const product of existingProduct) { const eventDatas = await EventsDataModel(organization) .find({ + versionId: ExistingVersion._id, projectId: product.projectId, productUuid: product.productUuid, isArchive: false, @@ -383,6 +467,7 @@ export const AllProductDatas = async ( result.push({ projectId: product.projectId, + versionId: product.versionId, productName: product.productName, productUuid: product.productUuid, eventDatas, @@ -407,7 +492,14 @@ export const AllProductDatas = async ( }; export const productRename = async (data: IProductRename): Promise => { try { - const { productName, productUuid, projectId, userId, organization } = data; + const { + productName, + productUuid, + projectId, + versionId, + userId, + organization, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -416,15 +508,27 @@ export const productRename = async (data: IProductRename): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const ExistingProduct = await ProductAFind( productUuid, projectId, + versionId, organization ); if (!ExistingProduct) return { status: "Product not found" }; const UpdateName = await ProductModel(organization).findOneAndUpdate( - { productUuid: productUuid, projectId: projectId, isArchive: false }, + { + productUuid: productUuid, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { productName: productName, }, diff --git a/src/shared/services/trash/trashService.ts b/src/shared/services/trash/trashService.ts index f2d78dc..7035e72 100644 --- a/src/shared/services/trash/trashService.ts +++ b/src/shared/services/trash/trashService.ts @@ -21,7 +21,6 @@ export const TrashDatas = async (data: IOrg) => { Trash.DeletedAt.getTime() + 15 * 24 * 60 * 60 * 1000 ); if (now > deletedPlus15) { - console.log("now > deletedPlus15: ", now > deletedPlus15); await projectModel(organization).updateOne( { _id: Trash._id }, { $set: { isDeleted: true } } diff --git a/src/shared/services/v1Project/v1projectservice.ts b/src/shared/services/v1Project/v1projectservice.ts index caf26ce..be409f5 100644 --- a/src/shared/services/v1Project/v1projectservice.ts +++ b/src/shared/services/v1Project/v1projectservice.ts @@ -5,8 +5,20 @@ import { existingUser, previousVersion, generateUntitledProjectName, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; import UsersDataModel from "../../V1Models/Auth/user.ts"; +import assetModel from "../../V1Models/Builder/assetModel.ts"; +import AisleModel from "../../V1Models/Builder/AisleModel.ts"; +import cameraModel from "../../V1Models/Builder/cameraModel.ts"; +import lineModel from "../../V1Models/Builder/linesModel.ts"; +import wallItemModel from "../../V1Models/Builder/wallItemsModel.ts"; +import zoneModel from "../../V1Models/Builder/zoneModel.ts"; +import ProductModel from "../../V1Models/Simulation/productModel.ts"; +import EventsDataModel from "../../V1Models/Simulation/eventsDataModel.ts"; +import widget3dModel from "../../V1Models/Vizualization/3dwidget.ts"; +import floatWidgetModel from "../../V1Models/Vizualization/floatWidget.ts"; +import templateModel from "../../V1Models/Vizualization/templatemodel.ts"; interface CreateProjectInput { projectName: string; projectUuid: string; @@ -86,15 +98,28 @@ export const createProject = async (data: CreateProjectInput) => { isArchive: false, }); const versionData = await previousVersion(project._id, organization); + + const versionNameDesc = new Date().toLocaleString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + hour: "numeric", + minute: "2-digit", + }); if (!versionData || versionData.length === 0) { const newVersion = await versionModel(organization).create({ projectId: project._id, createdBy: userId, - version: 0.0, + version: 0.1, + versionName: versionNameDesc, + description: versionNameDesc, }); await projectModel(organization).findByIdAndUpdate( { _id: project._id, isArchive: false }, - { total_versions: `v-${newVersion.version.toFixed(2)}` } + { + total_versions: `v-${newVersion.version.toFixed(1)}`, + Present_version: newVersion._id, + } ); } return { @@ -102,7 +127,6 @@ export const createProject = async (data: CreateProjectInput) => { project: project, }; } catch (error) { - console.log("error: ", error); return { status: error, }; @@ -140,6 +164,7 @@ export const DeleteProject = async (data: ProjectDelInterface) => { { isArchive: true, DeletedAt: new Date() }, { new: true } ); + console.log("updateProject: ", updateProject); if (updateProject) return { status: "Success", project: updateProject }; } catch (error: unknown) { return { status: error }; @@ -150,15 +175,23 @@ export const updateProject = async (data: UpdateProjectInput) => { const { projectId, organization, userId, projectName, thumbnail } = data; const ExistingUser = await existingUser(userId, organization); if (!ExistingUser) return { status: "User not found" }; - let filter = { _id: projectId, isArchive: false } as RoleFilter; - - const existingProject = await projectModel(organization).findOne(filter); + const existingProject = await projectModel(organization).findOne({ + _id: projectId, + isArchive: false, + }); if (!existingProject) return { status: "Project not found" }; + // const currentVersion = await LivingCurrentVersion( + // organization, + // existingProject._id, + // existingProject.Present_version + // ); + // if (!currentVersion) return { status: "CurrentVersion Data not found" }; if (projectName !== undefined) existingProject.projectName = projectName; if (thumbnail !== undefined) existingProject.thumbnail = thumbnail; const updateProject = await projectModel(organization) .findOneAndUpdate( - filter, + // { _id: projectId, isArchive: false,versionId:currentVersion._id }, + { _id: projectId, isArchive: false }, { projectName: projectName, thumbnail: thumbnail }, { new: true } ) @@ -190,19 +223,27 @@ export const DuplicateProject = async (data: IProjectDuplicate) => { organization, userId ); - if (projectExisting) { return { status: "project_exists", project: projectExisting, }; } + const OldprojectData = await projectModel(organization).findOne({ + _id: projectUuid, + createdBy: userId, + isArchive: false, + }); + const oldprojectPresentVersion = await versionModel(organization).findOne({ + _id: OldprojectData.Present_version, + isArchive: false, + }); const uniqeName = await generateUniqueProjectName( projectName, organization, userId ); - const project = await projectModel(organization).create({ + const newProject = await projectModel(organization).create({ projectName: uniqeName, projectUuid: projectUuid, createdBy: userId, @@ -210,20 +251,21 @@ export const DuplicateProject = async (data: IProjectDuplicate) => { sharedUsers: sharedUsers || [], isArchive: false, }); + await AllCloneForduplicate(projectUuid, newProject._id, organization); const RecentUserDoc = await UsersDataModel(organization).findOne({ userId: userId, isArchive: false, }); const newArr = RecentUserDoc?.recentlyViewed || []; if (RecentUserDoc?.recentlyViewed.length === 0) { - newArr.push(project._id); + newArr.push(newProject._id); await RecentUserDoc.save(); } else { - const index = newArr.indexOf(project._id); + const index = newArr.indexOf(newProject._id); if (index !== -1) { newArr.splice(index, 1); } - newArr.unshift(project._id); + newArr.unshift(newProject._id); if (newArr.length > maxLength) { newArr.pop(); @@ -234,21 +276,35 @@ export const DuplicateProject = async (data: IProjectDuplicate) => { { recentlyViewed: newArr }, { new: true } ); - const versionData = await previousVersion(project._id, organization); - if (!versionData || versionData.length === 0) { - const newVersion = await versionModel(organization).create({ - projectId: project._id, - createdBy: userId, - version: 0.0, - }); - await projectModel(organization).findByIdAndUpdate( - { _id: project._id, isArchive: false }, - { total_versions: `v-${newVersion.version.toFixed(2)}` } - ); - } + const oldVersions = await versionModel(organization).find({ + projectId: projectUuid, + isArchive: false, + }); + const clonedVersions = oldVersions.map((doc) => { + const { _id, __v, ...rest } = doc.toObject(); + return { + ...rest, + projectId: newProject._id, + }; + }); + + const createdversions = await versionModel(organization).create( + clonedVersions + ); + const newPresentVersion = createdversions.find( + (v) => v.version === oldprojectPresentVersion?.version + ); + + await projectModel(organization).findByIdAndUpdate( + { _id: newProject._id, isArchive: false }, + { + total_versions: OldprojectData.total_versions, + Present_version: newPresentVersion._id, + } + ); return { status: "Success", - project: project, + project: newProject, }; } catch (error: unknown) { return { status: error }; @@ -295,6 +351,12 @@ export const viewProject = async (data: ProjectInterface) => { const existingProject = await projectModel(organization).findOne(filter); if (!existingProject) return { status: "Project not found" }; + // const currentVersion = await LivingCurrentVersion( + // organization, + // existingProject._id, + // existingProject.Present_version + // ); + // if (!currentVersion) return { status: "CurrentVersion Data not found" }; const newArr = RecentUserDoc?.recentlyViewed || []; if (RecentUserDoc?.recentlyViewed.length === 0) { newArr.push(projectId); @@ -317,9 +379,47 @@ export const viewProject = async (data: ProjectInterface) => { ); const projectData = await projectModel(organization) .findOneAndUpdate(filter, { isViewed: Date.now() }, { new: true }) - .select("_id projectName createdBy thumbnail createdAt"); + .select("_id projectName createdBy thumbnail createdAt isViewed"); return { status: "Success", data: projectData }; } catch (error: unknown) { return { status: error }; } }; + +export const AllCloneForduplicate = async ( + beforeCloneProjectId: string, + NewprojectId: string, + organization: string +) => { + async function cloneDocuments(model: any, label: string) { + const records = await model(organization).find({ + projectId: beforeCloneProjectId, + isArchive: false, + }); + + if (!records.length) { + return; + } + + const cloned = records.map((doc: any) => { + const { _id, __v, ...rest } = doc.toObject(); + return { + ...rest, + projectId: NewprojectId, + }; + }); + + const created = await model(organization).create(cloned); + } + await cloneDocuments(assetModel, "Asset"); + await cloneDocuments(AisleModel, "Aisle"); + await cloneDocuments(cameraModel, "Camera"); + await cloneDocuments(lineModel, "Line"); + await cloneDocuments(wallItemModel, "WallItem"); + await cloneDocuments(zoneModel, "Zone"); + await cloneDocuments(ProductModel, "Product"); + await cloneDocuments(EventsDataModel, "Events"); + await cloneDocuments(widget3dModel, "3DWidget"); + await cloneDocuments(floatWidgetModel, "FloatWidget"); + await cloneDocuments(templateModel, "Template"); +}; diff --git a/src/shared/services/version/README.md b/src/shared/services/version/README.md new file mode 100644 index 0000000..e4ee5a4 --- /dev/null +++ b/src/shared/services/version/README.md @@ -0,0 +1,172 @@ +DWINZO-BETA-BACKEND + +Repository Structure: +DWINZO_BACKEND/ +│ +├── .gitignore +├── package.json +├── .env +│ +└── src/ +│ +├── api-server/ +│ │ +│ └── controller/ +│ ├─── Routes/ +│ ├── V1 +│ │ └── v1Controllers/ +│ │ ├── v1Routes/ +│ ├─── app.ts +│ ├─── main.ts +│ +├── shared +│ │ +│ └── connect/ +│ ├─── middleware/ +│ ├─── model/ +│ ├─── redis/ +│ ├─── services/ +│ ├─── swagger/ +│ ├─── utils/ +│ ├─── V1Models/ +│ +├── socket-server +│ │ +│ └── controllers/ +│ ├─── manager/ +│ ├─── services/ +│ ├─── socket/ +│ ├─── utils/ +│ ├─── index.ts + +VERSION CONTROL MODULE: +The Version Control Module is a backend system component designed to track, store, and manage multiple versions of data entities (such as scenes, assets, layouts, or entire projects). It enables developers and users to: + +- View the historical state of an entity. + +- Restore previous versions. + +- Audit changes over time. + +- Enable branching workflows like clone and rollback. + +TECH STACK: +Language: Typescript +Framework: Express.js +Database: Mongodb + +Architecture FOR API: + +Entry Point: + +- src/api-server/main.js starts the server and runs the main application. +- src/api-server/app.js sets up the Express app, middleware, and routes. + +Components: + +- src/api-server/V1/ (controllers, routes). +- src/shared/services/ (Service logics). + +Utils: + +- src/shared/utils/ contains Express middleware functions (e.g., hashing,tokenDatas). + +Database: + +- src/shared/connect/ handles database configuration and connection logic. + +Models: + +- src/shared/V1Models/ handles mongo schema structure and datatype. + + +Routing for Version: + + +________________________________________________________________________________________________ +|Method | Routing | Description | +|__________|___________________________________|________________________________________________| +|POST | /generateVersion | Create New version | +|__________|___________________________________|________________________________________________| +|POST | /version/rollback | Version Rollback for the previous version | +|__________|___________________________________|________________________________________________| +|GET | /:projectId/versions | Project based Version histories | +|__________|___________________________________|________________________________________________| +|GET | /version/:versionId/:projectId | Get a Version Datas | +|__________|___________________________________|________________________________________________| + + +NEW VERSION instructions: + +Request Datas: + - userId, organization from the User authenticationtoken. + - hierarchyVersion(parentVersion),description,projectId,createdBy(userId) from the body data. + +LOGIC: + - checking for the valid userId,projectId and parentVersion. + - checking for the PreviousVersion based on the project. + - NewVersion Creation based on th PreviousVersion and parentVersion. + - Cloning for the previousVersion Datas(Scenes,asset,etc.) for the newVersion. + - Update the project data based on the latestVersion. + +Response Datas: + - Http response with status code of 404 for User not found, Project not found and Parent Version not found. + - Http response with status code of 200 with Newversion unique Id(mongo _id). + - Http response with status code of 500 for Internal server error and Unknown error. + + +ROLL BACK instructions: + +Request Datas: + - userId, organization from the User authenticationtoken. + - projectId,versionId from the body data. + +LOGIC: + - checking for the valid userId,projectId and versionId(rollback versionId). + - checking for the PreviousVersion based on the project. + - NewVersion Creation based on th PreviousVersion and parentVersion(rollback versionId). + - Cloning for the parentVersion(rollback versionId) Datas(Scenes,asset,etc.) for the newVersion. + - Update the project data based on the latestVersion. + +Response Datas: + - Http response with status code of 404 for User not found, Project not found and Mentioned Version not found for the Rollback. + - Http response with status code of 200 with Newversion unique Id(mongo _id) and message:"Rollback successfull". + - Http response with status code of 500 for Internal server error and Unknown error. + + +VERSION HISTORY instructions: + +Request Datas: + - userId, organization from the User authenticationtoken. + - projectId params data. + - page,limit query data. + +LOGIC: + - checking for the valid userId,projectId. + - fetching the allversions based on projectId for the Total count. + - filtering total project versions based on the sorting,limit and page. + - After filtering finalResponse with metaDatas like total count,page,limit and hasNextPage is provided + +Response Datas: + - Http response with status code of 404 for User not found, Project not found and Mentioned Version not found for the Rollback. + - Http response with status code of 200 for Version History Datas. + - Http response with status code of 200 for Versions not found with empty Array[]. + - Http response with status code of 500 for Internal server error and Unknown error. + + +PARTICULAR VERSION DATA instructions: + +Request Datas: + - userId, organization from the User authenticationtoken. + - projectId,versionId params data. + +LOGIC: + - checking for the valid userId,projectId. + - checking for the versionId based on the project. + - For existingVersion Fetching all the Builder, Simulation, RTViz datas based on the projectId and versionId + +Response Datas: + - Http response with status code of 404 for User not found, Project not found and Mentioned Version not found for the Rollback. + - Http response with status code of 200 for Version based Datas. + - Http response with status code of 200 for Versions not found with empty Array[]. + - Http response with status code of 500 for Internal server error and Unknown error. \ No newline at end of file diff --git a/src/shared/services/version/versionService.ts b/src/shared/services/version/versionService.ts index ab316bf..68c2c45 100644 --- a/src/shared/services/version/versionService.ts +++ b/src/shared/services/version/versionService.ts @@ -1,124 +1,635 @@ -import projectModel from "../../model/project/project-model.ts"; -import assetModel from "../../V1Models/Builder/assetModel.ts"; -import versionModel from "../../model/version/versionModel.ts"; - -class VersionService { - async getCurrentVersion(db: string, projectId: string) { - const project = await projectModel(db).findById(projectId); - if (!project) throw new Error("Project not found"); - - return { - versionNumber: parseFloat(project.Present_version || "0.0"), - versionString: project.Present_version || "0.0", - }; - } - - async createNewVersion( - db: string, - projectId: string, - userId: string, - description?: string - ) { - const project = await projectModel(db).findById(projectId); - if (!project) throw new Error("Project not found"); - - const { versionNumber } = await this.getCurrentVersion(db, projectId); - const newVersion = parseFloat((versionNumber + 0.1).toFixed(1)); - const versionName = `Version ${newVersion.toFixed(1)}`; - - const version = await versionModel(db).create({ - versionName, - version: newVersion, - projectId: project._id, - createdBy: userId, - description, - }); - - await projectModel(db).findByIdAndUpdate(projectId, { - Present_version: newVersion.toFixed(1), - total_versions: newVersion.toFixed(1), - }); - - return version; - } - - async saveCurrentStateAsVersion( - db: string, - projectId: string, - userId: string, - description?: string - ) { - const newVersion = await this.createNewVersion( - db, - projectId, - userId, - description - ); - - const previousVersion = parseFloat((newVersion.version - 0.1).toFixed(1)); - const previousVersionDoc = await versionModel(db).findOne({ - projectId, - version: previousVersion, - }); - console.log("previousVersionDoc: ", previousVersionDoc); - - let previousAssets = []; - if (previousVersionDoc) { - previousAssets = await assetModel(db).find({ - projectId, - versionId: previousVersionDoc._id, - isArchive: false, - }); - } - - const newAssets = await Promise.all( - previousAssets.map(async (asset) => { - console.log("previousAssets: ", previousAssets); - const newAsset = { ...asset.toObject(), versionId: newVersion._id }; - delete newAsset._id; - return await assetModel(db).create(newAsset); - }) - ); - - return { - version: newVersion, - assets: newAssets, - }; - } - - async getVersionHistory(db: string, projectId: string) { - const versions = await versionModel(db) - .find({ projectId, isArchive: false }) - .sort({ version: 1 }) - .populate("createdBy", "name email"); - - const versionHistory = await Promise.all( - versions.map(async (version) => { - const assets = await assetModel(db).find({ - projectId, - versionId: version._id, - isArchive: false, - }); - - const assetCounts = assets.reduce((acc, asset) => { - acc[asset.type] = (acc[asset.type] || 0) + 1; - return acc; - }, {}); - - return { - version: version.version.toFixed(1), - versionName: version.versionName, - createdAt: version.createdAt, - createdBy: version.createdBy, - description: version.description, - assets: assetCounts, - totalAssets: assets.length, - }; - }) - ); - - return versionHistory; - } +import AisleModel, { Aisle } from "../../V1Models/Builder/AisleModel.ts"; +import assetModel, { AssetData } from "../../V1Models/Builder/assetModel.ts"; +import cameraModel, { Camera } from "../../V1Models/Builder/cameraModel.ts"; +import lineModel, { ILines } from "../../V1Models/Builder/linesModel.ts"; +import wallItemModel, { + WallItems, +} from "../../V1Models/Builder/wallItemsModel.ts"; +import zoneModel, { Zone } from "../../V1Models/Builder/zoneModel.ts"; +import environmentModel from "../../V1Models/Environment/environments-Model.ts"; +import versionModel from "../../V1Models/Version/versionModel.ts"; +import widget3dModel, { + Widget3d, +} from "../../V1Models/Vizualization/3dwidget.ts"; +import panelModel, { Panel } from "../../V1Models/Vizualization/panelmodel.ts"; +import widgetModel, { + Widget, +} from "../../V1Models/Vizualization/widgemodel.ts"; +import { + existingProjectById, + existingUser, +} from "../helpers/v1projecthelperFns.ts"; +import floatWidgetModel, { + FloatingWidget, +} from "../../V1Models/Vizualization/floatWidget.ts"; +import templateModel, { + Template, +} from "../../V1Models/Vizualization/templatemodel.ts"; +import ProductModel, { + Product, +} from "../../V1Models/Simulation/productModel.ts"; +import EventsDataModel, { + IPointModel, +} from "../../V1Models/Simulation/eventsDataModel.ts"; +import AuthModel from "../../V1Models/Auth/userAuthModel.ts"; +type VersionData = { + Builder: { + cameras: Camera[]; + wallItems: WallItems[]; + lines: ILines[]; + zones: Zone[]; + aisles: Aisle[]; + assets: AssetData[]; + }; + Simulation: { + products: Product[]; + events: IPointModel[]; + }; + RTViz: { + panels: Panel[]; + widgets: Widget[]; + widget3ds: Widget3d[]; + floatWidgets: FloatingWidget[]; + templates: Template[]; + }; +}; +interface IVersionSave { + organization: string; + hierarchyVersion: string; + versionName: string; + projectId: string; + userId: string; + createdBy: string; + description?: string; +} +interface IVersionRollback { + organization: string; + versionId: string; + projectId: string; + userId: string; + description?: string; } -export default new VersionService(); +interface IVersionHistory { + organization: string; + projectId: string; + userId: string; + page: number; + limit: number; + sortBy?: string; + sortOrder?: string; +} +interface IVersionUpdate { + organization: string; + projectId: string; + userId: string; + page: number; + versionId: string; + versionName?: string; + description?: string; +} +interface IVersionById { + organization: string; + projectId: string; + versionId: string; + userId: string; +} +interface IResult { + status: string; + data?: object; +} +export const CreateVersion = async (data: IVersionSave): Promise => { + try { + const { + hierarchyVersion, + projectId, + versionName, + description, + userId, + organization, + createdBy, + } = data; + const userExisting = await existingUser(userId, organization); + if (!userExisting) { + return { + status: "User not found", + }; + } + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const versionData = await versionModel(organization).findOne({ + _id: hierarchyVersion, + projectId: projectId, + isArchive: false, + }); + if (!versionData) return { status: "Parent Version not found" }; + const versionDataprevious = await versionModel(organization) + .findOne({ + projectId: projectId, + isArchive: false, + }) + .sort({ version: -1 }); + const currentVersion = versionDataprevious?.version ?? 0; + const newVersion = parseFloat((currentVersion + 0.1).toFixed(2)); + const saveVersion = await versionModel(organization).create({ + versionName: versionName, + parentVersionID: versionData._id, + projectId: projectId, + description: description, + createdBy: createdBy, + previous_Version: currentVersion, + version: newVersion, + createdAt: new Date(), + }); + const find_User = await AuthModel(organization).findById({ + _id: saveVersion.createdBy, + isArchive: false, + }); + const responseVersionData = { + versionId: saveVersion._id, + version: saveVersion.version, + description: saveVersion.description, + versionName: saveVersion.versionName, + createdAt: saveVersion.createdAt, + createdBy: { + userId: find_User._id, + userName: find_User.userName, + }, + }; + await LivingProject.updateOne({ + Present_version: saveVersion._id, + total_versions: `v-${saveVersion.version.toFixed(1)}`, + }); + + await AllCloneFornewVersions( + projectId, + organization, + saveVersion._id, + hierarchyVersion + ); + return { status: "Success", data: responseVersionData }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; + +export const GetVersionById = async (data: IVersionById): Promise => { + try { + const { projectId, userId, organization, versionId } = data; + const userExisting = await existingUser(userId, organization); + if (!userExisting) { + return { + status: "User not found", + }; + } + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const existingVersion = await versionModel(organization) + .findOne({ + _id: versionId, + projectId: projectId, + isArchive: false, + }) + .select("version previous_Version"); + if (!existingVersion) { + return { status: "Version not found for the project" }; + } + + const [cameras, wallItems, lines, zones, aisles, assets] = + await Promise.all([ + cameraModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + wallItemModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + lineModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + zoneModel(organization) + .find({ versionId, projectId, isArchive: false }) + .select( + "-_id zoneName layer panelOrder viewPortCenter lockedPanel points createdBy zoneUuid panelOrder" + ), + AisleModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + assetModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + ]); + + // Simulation part + const [products, events] = await Promise.all([ + ProductModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + EventsDataModel(organization).find({ + versionId, + projectId, + isArchive: false, + }), + ]); + + // RTViz part + const templates = await templateModel(organization).find({ + versionId, + projectId, + isArchive: false, + }); + + //RTVIZ zone based + let panels: Panel[] = []; + let widgets: Widget[] = []; + let widget3ds: Widget3d[] = []; + let floatWidgets: FloatingWidget[] = []; + + for (const zone of zones) { + const zonePanels = await panelModel(organization) + .find({ + zoneUuid: zone.zoneUuid, + versionId, + projectId, + isArchive: false, + }) + .select("panelName -_id"); + panels.push(...zonePanels); + + for (const panel of zonePanels) { + const panelWidgets = await widgetModel(organization) + .find({ + panelID: panel._id, + zoneUuid: zone.zoneUuid, + versionId, + projectId, + isArchive: false, + }) + .select("widgetName widgetside widgetID elementType Data -_id"); + widgets.push(...panelWidgets); + } + + const zoneWidget3Ds = await widget3dModel(organization).find({ + zoneUuid: zone.zoneUuid, + versionId, + projectId, + isArchive: false, + }); + widget3ds.push(...zoneWidget3Ds); + + const zoneFloatWidgets = await floatWidgetModel(organization).find({ + zoneUuid: zone.zoneUuid, + versionId, + projectId, + isArchive: false, + }); + floatWidgets.push(...zoneFloatWidgets); + } + + const versionData: VersionData = { + Builder: { + cameras, + wallItems, + lines, + zones, + aisles, + assets, + }, + Simulation: { + products, + events, + }, + RTViz: { + panels, + widgets, + widget3ds, + floatWidgets, + templates, + }, + }; + + return { + status: "Success", + data: { + version: existingVersion, + entities: versionData, + }, + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; + +export const RollBackversion = async ( + data: IVersionRollback +): Promise => { + try { + const { versionId, projectId, userId, organization } = data; + const userExisting = await existingUser(userId, organization); + if (!userExisting) { + return { + status: "User not found", + }; + } + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const rollbackversion = await versionModel(organization).findOne({ + _id: versionId, + projectId: projectId, + isArchive: false, + }); + if (!rollbackversion) + return { status: "Mentioned Version not found for the Rollback" }; + const versionDataprevious = await versionModel(organization) + .findOne({ + projectId: projectId, + isArchive: false, + }) + .sort({ version: -1 }); + const currentVersion = versionDataprevious?.version ?? 0; + const newVersion = parseFloat((currentVersion + 0.01).toFixed(2)); + const saveVersion = await versionModel(organization).create({ + parentVersionID: rollbackversion._id, + projectId: projectId, + createdBy: userId, + previous_Version: currentVersion, + version: newVersion, + createdAt: new Date(), + rollBackComment: `RollBack from the version ${rollbackversion.version}`, + }); + LivingProject.Present_version = saveVersion._id; + LivingProject.total_versions = `v-${saveVersion.version.toFixed(2)}`; + await LivingProject.save(); + + await AllCloneFornewVersions( + projectId, + organization, + saveVersion._id, + rollbackversion._id + ); + return { status: "Success", data: saveVersion._id }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; + +export const VersionHistory = async ( + data: IVersionHistory +): Promise => { + try { + const { organization, userId, projectId, page, limit, sortOrder } = data; + + const userExisting = await existingUser(userId, organization); + if (!userExisting) return { status: "User not found" }; + + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + + const filter: object = { projectId, isArchive: false }; + const total = await versionModel(organization).countDocuments(filter); + const versiondatas = await versionModel(organization) + .find(filter) + .sort({ ["version"]: sortOrder === "asc" ? 1 : -1 }) + .skip((page - 1) * limit) + .limit(limit) + .select("version createdBy createdAt description versionName") + .populate({ + path: "createdBy", + model: AuthModel(organization), + select: "userName", + }); + // .populate({ + // path: "createdBy", + // model: UsersDataModel(organization), + // select: "profilePicture", + // }); + // console.log('versiondatas: ', versiondatas); + if (!versiondatas) + return { + status: "Versions not found", + }; + const versions = versiondatas.map((version) => { + return { + versionId: version._id, + version: version.version, + createdAt: version.createdAt, + description: version.description, + versionName: version.versionName, + createdBy: { + userId: version.createdBy._id, + userName: version.createdBy.userName, + }, + }; + }); + return { + status: "Success", + data: { + versions, + Metadatas: { + total, + page, + limit, + hasNextPage: page * limit < total, + }, + }, + }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; +export const updateVersion = async (data: IVersionUpdate): Promise => { + try { + const { + organization, + userId, + projectId, + versionId, + versionName, + description, + } = data; + + const userExisting = await existingUser(userId, organization); + if (!userExisting) return { status: "User not found" }; + + const LivingProject = await existingProjectById( + projectId, + organization, + userId + ); + if (!LivingProject) return { status: "Project not found" }; + const existingVersionId = await versionModel(organization).findOne({ + _id: versionId, + isArchive: false, + projectId: projectId, + }); + if (!existingVersionId) { + return { status: "VersionId not match" }; + } else { + existingVersionId.versionName = versionName; + existingVersionId.description = description; + await existingVersionId.save(); + return { status: "Version Updated successfully" }; + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; + +export const AllCloneFornewVersions = async ( + projectId: string, + organization: string, + versionId: string, + oldeVersionId: string +) => { + const cloneDocuments = async (model: any, modelName: string) => { + const docs = await model(organization).find({ + projectId, + isArchive: false, + versionId: oldeVersionId, + }); + + if (!docs.length) return; + + const clonedDocs = docs.map((doc: any) => { + const { _id, __v, ...rest } = doc.toObject(); + return { ...rest, versionId }; + }); + + const created = await model(organization).create(clonedDocs); + console.log(`Cloned ${modelName}:`, created.length); + }; + + await Promise.all([ + cloneDocuments(assetModel, "Asset"), + cloneDocuments(AisleModel, "Aisle"), + cloneDocuments(cameraModel, "Camera"), + cloneDocuments(lineModel, "Line"), + cloneDocuments(wallItemModel, "WallItem"), + cloneDocuments(ProductModel, "Product"), + cloneDocuments(EventsDataModel, "Event"), + cloneDocuments(widget3dModel, "3D Widget"), + cloneDocuments(floatWidgetModel, "Float Widget"), + cloneDocuments(templateModel, "Template"), + cloneDocuments(environmentModel, "Environment"), + ]); + + const zones = await zoneModel(organization).find({ + projectId, + isArchive: false, + versionId: oldeVersionId, + }); + + for (const zone of zones) { + const { _id: oldZoneId, __v, ...zoneData } = zone.toObject(); + const newZone = await zoneModel(organization).create({ + ...zoneData, + versionId, + }); + + const panels = await panelModel(organization).find({ + zoneUuid: zone.zoneUuid, + projectId: projectId, + isArchive: false, + versionId: oldeVersionId, + }); + + for (const panel of panels) { + const { _id: oldPanelId, widgets, __v, ...panelData } = panel.toObject(); + const newPanel = await panelModel(organization).create({ + ...panelData, + versionId, + projectId: projectId, + zoneUuid: newZone.zoneUuid, + }); + + const widgetsData = await widgetModel(organization).find({ + panelID: oldPanelId, + projectId, + isArchive: false, + versionId: oldeVersionId, + }); + + for (const widget of widgetsData) { + const { _id, __v, ...widgetData } = widget.toObject(); + const newWidget = await widgetModel(organization).create({ + ...widgetData, + projectId: projectId, + panelID: newPanel._id, + versionId, + zoneUuid: newZone.zoneUuid, + }); + + newPanel.widgets.push(newWidget._id); + } + + await newPanel.save(); + } + } +}; diff --git a/src/shared/services/visualization/floatWidgetService.ts b/src/shared/services/visualization/floatWidgetService.ts index 60204f4..8015dce 100644 --- a/src/shared/services/visualization/floatWidgetService.ts +++ b/src/shared/services/visualization/floatWidgetService.ts @@ -3,6 +3,7 @@ import zoneModel from "../../V1Models/Builder/zoneModel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IResult { @@ -31,6 +32,7 @@ interface IAddFloatData { zoneUuid: string; index: number; projectId: string; + versionId: string; } interface IDelFloat { userId: string; @@ -38,6 +40,7 @@ interface IDelFloat { zoneUuid: string; floatWidgetID: string; projectId: string; + versionId: string; } interface ISingleFloat { userId: string; @@ -49,6 +52,7 @@ interface IGetZoneFloat { organization: string; zoneUuid: string; projectId: string; + versionId: string; } interface IDuplicateFloatData { userId: string; @@ -72,10 +76,19 @@ interface IDuplicateFloatData { zoneUuid: string; index: number; projectId: string; + versionId: string; } export const AddFloat = async (data: IAddFloatData): Promise => { try { - const { organization, widget, zoneUuid, index, projectId, userId } = data; + const { + organization, + widget, + zoneUuid, + index, + projectId, + versionId, + userId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -84,10 +97,17 @@ export const AddFloat = async (data: IAddFloatData): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, projectId: projectId, + versionId: versionId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; @@ -95,12 +115,17 @@ export const AddFloat = async (data: IAddFloatData): Promise => { floatWidgetID: widget.id, isArchive: false, zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, }); if (existingFloatWidget) { const updateFloatWidget = await floatWidgetModel( organization ).findOneAndUpdate( { + zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, floatWidgetID: widget.id, isArchive: false, }, @@ -132,6 +157,8 @@ export const AddFloat = async (data: IAddFloatData): Promise => { iconName: widget.iconName, header: widget.header, floatWidgetID: widget.id, + versionId: versionId, + projectId: projectId, position: widget.position, per: widget.per, value: widget.value, @@ -169,7 +196,14 @@ export const AddFloat = async (data: IAddFloatData): Promise => { export const DelFloat = async (data: IDelFloat): Promise => { try { - const { organization, floatWidgetID, zoneUuid, projectId, userId } = data; + const { + organization, + floatWidgetID, + versionId, + zoneUuid, + projectId, + userId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) { return { status: "User not found" }; @@ -182,20 +216,34 @@ export const DelFloat = async (data: IDelFloat): Promise => { if (!LivingProject) { return { status: "Project not found" }; } + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, projectId: projectId, + versionId: versionId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; const findfloatWidget = await floatWidgetModel(organization).findOne({ floatWidgetID: floatWidgetID, + projectId: projectId, + versionId: versionId, isArchive: false, }); if (!findfloatWidget) return { status: "FloatWidget not found for the Id" }; const widgetData = await floatWidgetModel(organization).findByIdAndUpdate( - { _id: findfloatWidget._id, isArchive: false }, + { + _id: findfloatWidget._id, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { isArchive: true }, { new: true } ); @@ -226,7 +274,15 @@ export const DuplicateFloat = async ( data: IDuplicateFloatData ): Promise => { try { - const { organization, widget, zoneUuid, index, projectId, userId } = data; + const { + organization, + widget, + zoneUuid, + index, + versionId, + projectId, + userId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) { return { status: "User not found" }; @@ -239,10 +295,17 @@ export const DuplicateFloat = async ( if (!LivingProject) { return { status: "Project not found" }; } + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, projectId: projectId, + versionId: versionId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; @@ -250,12 +313,16 @@ export const DuplicateFloat = async ( floatWidgetID: widget.id, isArchive: false, zoneUuid: zoneUuid, + projectId: projectId, + versionId: versionId, }); if (existingFloatWidget) { const updateFloatWidget = await floatWidgetModel( organization ).findOneAndUpdate( { + projectId: projectId, + versionId: versionId, floatWidgetID: widget.id, isArchive: false, }, @@ -292,6 +359,8 @@ export const DuplicateFloat = async ( className: widget.className, header: widget.header, floatWidgetID: widget.id, + projectId: projectId, + versionId: versionId, position: widget.position, per: widget.per, value: widget.value, @@ -338,7 +407,7 @@ export const DuplicateFloat = async ( export const GetFloatWidget = async (data: IGetZoneFloat): Promise => { try { - const { organization, zoneUuid, projectId, userId } = data; + const { organization, zoneUuid, projectId, userId,versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) { return { status: "User not found" }; @@ -351,15 +420,25 @@ export const GetFloatWidget = async (data: IGetZoneFloat): Promise => { if (!LivingProject) { return { status: "Project not found" }; } + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, projectId: projectId, + versionId: ExistingVersion._id, }); if (!existingZone) return { status: "Zone not found" }; const widgetData = await floatWidgetModel(organization) .find({ zoneUuid: zoneUuid, + projectId: projectId, + versionId: ExistingVersion._id, isArchive: false, }) .select("-_id -zoneUuid -createdAt -updatedAt -__v"); @@ -393,6 +472,8 @@ export const GetFloatWidget = async (data: IGetZoneFloat): Promise => { } } }; + +//project and version based not changed export const SingleFloatWidget = async ( data: ISingleFloat ): Promise => { diff --git a/src/shared/services/visualization/panelService.ts b/src/shared/services/visualization/panelService.ts index 92906dc..ffe0c77 100644 --- a/src/shared/services/visualization/panelService.ts +++ b/src/shared/services/visualization/panelService.ts @@ -4,6 +4,7 @@ import widgetModel from "../../V1Models/Vizualization/widgemodel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IResult { status: string; @@ -15,13 +16,16 @@ interface IAddPanel { panelOrder: string[]; userId: string; projectId: string; + versionId: string; } + interface IPanel { organization: string; zoneUuid: string; panelName: string; userId: string; projectId: string; + versionId: string; } interface ILockedPanel { organization: string; @@ -29,10 +33,12 @@ interface ILockedPanel { lockedPanel: string[]; userId: string; projectId: string; + versionId: string; } export const AddPanel = async (data: IAddPanel): Promise => { try { - const { organization, zoneUuid, panelOrder, userId, projectId } = data; + const { organization, zoneUuid, panelOrder, userId, versionId, projectId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -41,19 +47,33 @@ export const AddPanel = async (data: IAddPanel): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, projectId: projectId, + versionId: versionId, }); if (!existingZone) return { status: "Zone not found" }; await zoneModel(organization).findOneAndUpdate( - { zoneUuid: zoneUuid, isArchive: false }, + { + zoneUuid: zoneUuid, + isArchive: false, + projectId: projectId, + versionId: versionId, + }, { panelOrder: panelOrder }, { new: true } ); const existingPanels = await panelModel(organization).find({ zoneUuid: zoneUuid, + projectId: projectId, + versionId: versionId, isArchive: false, }); @@ -70,6 +90,8 @@ export const AddPanel = async (data: IAddPanel): Promise => { const newPanel = await panelModel(organization).create({ zoneUuid: zoneUuid, panelName: panelName, + projectId: projectId, + versionId: versionId, widgets: [], isArchive: false, }); @@ -83,7 +105,8 @@ export const AddPanel = async (data: IAddPanel): Promise => { const zoneAndPanelData = await getZoneAndPanelData( organization, zoneUuid, - projectId + projectId, + versionId ); if (!zoneAndPanelData) { return zoneAndPanelData; @@ -103,7 +126,8 @@ export const AddPanel = async (data: IAddPanel): Promise => { }; export const DelPanel = async (data: IPanel): Promise => { try { - const { organization, zoneUuid, panelName, userId, projectId } = data; + const { organization, zoneUuid, versionId, panelName, userId, projectId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -112,25 +136,41 @@ export const DelPanel = async (data: IPanel): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, + versionId: versionId, isArchive: false, projectId: projectId, }); if (!existingZone) return { status: "Zone not found" }; const existingPanel = await panelModel(organization).findOne({ zoneUuid: zoneUuid, + projectId: projectId, + versionId: versionId, panelName: panelName, isArchive: false, }); if (!existingPanel) return { status: "Panel Already Deleted" }; await panelModel(organization).updateOne( - { _id: existingPanel._id, isArchive: false }, + { + _id: existingPanel._id, + projectId: projectId, + versionId: versionId, + isArchive: false, + }, { $set: { isArchive: true } } ); const existingWidgets = await widgetModel(organization).find({ panelID: existingPanel._id, + projectId: projectId, + versionId: versionId, isArchive: false, }); @@ -141,14 +181,19 @@ export const DelPanel = async (data: IPanel): Promise => { if (existingZone.panelOrder.includes(existingPanel.panelName)) { await zoneModel(organization).updateOne( - { _id: existingZone._id }, + { + _id: existingZone._id, + projectId: projectId, + versionId: versionId, + }, { $pull: { panelOrder: existingPanel.panelName } } ); } const zoneAndPanelData = await getZoneAndPanelData( organization, zoneUuid, - projectId + projectId, + versionId ); if (!zoneAndPanelData) { return zoneAndPanelData; @@ -168,7 +213,8 @@ export const DelPanel = async (data: IPanel): Promise => { }; export const ClearPanel = async (data: IPanel): Promise => { try { - const { organization, zoneUuid, panelName, userId, projectId } = data; + const { organization, zoneUuid, panelName, versionId, userId, projectId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -177,8 +223,15 @@ export const ClearPanel = async (data: IPanel): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, + versionId: versionId, isArchive: false, projectId: projectId, }); @@ -186,18 +239,27 @@ export const ClearPanel = async (data: IPanel): Promise => { const existingPanel = await panelModel(organization).findOne({ zoneUuid: zoneUuid, panelName: panelName, + versionId: versionId, + projectId: projectId, isArchive: false, }); if (!existingPanel) return { status: "Requested Panel not found" }; const existingWidgets = await widgetModel(organization).find({ panelID: existingPanel._id, + versionId: versionId, + projectId: projectId, isArchive: false, }); if (existingWidgets.length === 0) return { status: "No widgets to clear" }; const clearWidgetsofPanel = await widgetModel(organization).updateMany( - { panelID: existingPanel._id, isArchive: false }, + { + panelID: existingPanel._id, + isArchive: false, + versionId: versionId, + projectId: projectId, + }, { isArchive: true } ); const removeWidgetsInPanel = await panelModel( @@ -213,7 +275,8 @@ export const ClearPanel = async (data: IPanel): Promise => { const zoneAndPanelData = await getZoneAndPanelData( organization, zoneUuid, - projectId + projectId, + versionId ); if (!zoneAndPanelData) { return zoneAndPanelData; @@ -237,7 +300,14 @@ export const ClearPanel = async (data: IPanel): Promise => { }; export const LockedPanel = async (data: ILockedPanel): Promise => { try { - const { organization, zoneUuid, lockedPanel, userId, projectId } = data; + const { + organization, + zoneUuid, + lockedPanel, + versionId, + userId, + projectId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -246,15 +316,27 @@ export const LockedPanel = async (data: ILockedPanel): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) return { status: "Zone not found" }; else { const updateLockedPanel = await zoneModel(organization).findOneAndUpdate( - { zoneUuid: zoneUuid, isArchive: false }, + { + zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, + isArchive: false, + }, { lockedPanel: lockedPanel, }, @@ -263,7 +345,8 @@ export const LockedPanel = async (data: ILockedPanel): Promise => { const zoneAndPanelData = await getZoneAndPanelData( organization, zoneUuid, - projectId + projectId, + versionId ); if (!zoneAndPanelData) { return zoneAndPanelData; @@ -291,16 +374,16 @@ export const LockedPanel = async (data: ILockedPanel): Promise => { const getZoneAndPanelData = async ( organization: string, zoneUuid: string, - projectId: string + projectId: string, + versionId: string ) => { try { - - const existingZone = await zoneModel(organization) .findOne({ zoneUuid: zoneUuid, isArchive: false, projectId: projectId, + versionId: versionId, }) .select( "panelOrder zoneName zonePoints lockedPanel zoneUuid viewPortCenter viewPortposition" @@ -311,6 +394,8 @@ const getZoneAndPanelData = async ( const panelData = await panelModel(organization).find({ zoneUuid: zoneUuid, isArchive: false, + projectId: projectId, + versionId: versionId, }); const zoneName = existingZone.zoneName as string; @@ -318,6 +403,8 @@ const getZoneAndPanelData = async ( panelData.map(async (data) => { const widgetDataArray = await widgetModel(organization).find({ panelID: data._id, + projectId: projectId, + versionId: versionId, isArchive: false, }); diff --git a/src/shared/services/visualization/templateService.ts b/src/shared/services/visualization/templateService.ts index f3980eb..152a941 100644 --- a/src/shared/services/visualization/templateService.ts +++ b/src/shared/services/visualization/templateService.ts @@ -6,6 +6,7 @@ import floatWidgetModel from "../../V1Models/Vizualization/floatWidget.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IResult { status: string; @@ -23,12 +24,14 @@ interface IAddTemplate { Widgets3D: []; }; projectId: string; + versionId: string; userId: string; } interface ITemplateToZone { organization: string; templateID: string; projectId: string; + versionId: string; zoneUuid: string; userId: string; } @@ -36,32 +39,47 @@ interface ITemplate { organization: string; templateID: string; projectId: string; + versionId: string; userId: string; } interface IGetTemplate { organization: string; projectId: string; + versionId: string; userId: string; } export const AddTemplate = async (data: IAddTemplate): Promise => { try { - const { organization, template, projectId, userId } = data; + const { organization, template, projectId, versionId, userId } = data; const UserExists = await existingUser(userId, organization); - if (!UserExists) {return { status: "User not found" }}; + if (!UserExists) { + return { status: "User not found" }; + } const LivingProject = await existingProjectById( projectId, organization, userId ); - if (!LivingProject) {return { status: "Project not found" }}; + if (!LivingProject) { + return { status: "Project not found" }; + } + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingTemplate = await templateModel(organization).findOne({ templateID: template.id, isArchive: false, + versionId: versionId, projectId: projectId, }); if (existingTemplate) return { status: "TemplateID alreay exists" }; const newTemplate = await templateModel(organization).create({ templateID: template.id, + versionId: versionId, + projectId: projectId, templateName: template.name, panelOrder: template.panelOrder, widgets: template.widgets, @@ -71,7 +89,11 @@ export const AddTemplate = async (data: IAddTemplate): Promise => { }); if (newTemplate) { const allTemplateDatas = await templateModel(organization) - .find({ isArchive: false }) + .find({ + isArchive: false, + versionId: versionId, + projectId: projectId, + }) .select("-_id -__v -isArchive -createdAt -updatedAt"); const formattedTemplates = allTemplateDatas.map(async (data) => ({ @@ -102,7 +124,8 @@ export const AddTemplateToZone = async ( data: ITemplateToZone ): Promise => { try { - const { organization, templateID, projectId, zoneUuid, userId } = data; + const { organization, templateID, versionId, projectId, zoneUuid, userId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -111,9 +134,16 @@ export const AddTemplateToZone = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) @@ -124,6 +154,7 @@ export const AddTemplateToZone = async ( const existingTemplate = await templateModel(organization).findOne({ templateID: templateID, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingTemplate) @@ -136,20 +167,28 @@ export const AddTemplateToZone = async ( await existingZone.save(); const archivePanelDatas = await panelModel(organization).find({ zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); for (const panelData of archivePanelDatas) { await widgetModel(organization).deleteMany({ panelID: panelData._id, + versionId: versionId, + projectId: projectId, isArchive: false, }); } await panelModel(organization).deleteMany({ zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); await floatWidgetModel(organization).deleteMany({ zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); } @@ -157,6 +196,8 @@ export const AddTemplateToZone = async ( await existingZone.save(); const existingPanels = await panelModel(organization).find({ zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); const existingPanelNames = existingPanels.map( @@ -170,6 +211,8 @@ export const AddTemplateToZone = async ( missingPanels.map((panelName: any) => panelModel(organization).create({ zoneUuid, + versionId: versionId, + projectId: projectId, panelName, widgets: [], isArchive: false, @@ -180,6 +223,8 @@ export const AddTemplateToZone = async ( for (const widgetData of existingTemplate.widgets) { const addedExistingPanel = await panelModel(organization).findOne({ panelName: widgetData.panel, + versionId: versionId, + projectId: projectId, zoneUuid, isArchive: false, }); @@ -187,6 +232,8 @@ export const AddTemplateToZone = async ( const existingWidget = await widgetModel(organization).findOne({ panelID: addedExistingPanel._id, + versionId: versionId, + projectId: projectId, widgetID: widgetData.id, isArchive: false, }); @@ -194,6 +241,8 @@ export const AddTemplateToZone = async ( const newWidget = await widgetModel(organization).create({ widgetID: widgetData.id, + versionId: versionId, + projectId: projectId, elementType: widgetData.type, zoneUuid: zoneUuid, widgetName: widgetData.widgetName || "Widget", @@ -207,6 +256,8 @@ export const AddTemplateToZone = async ( for (const floatData of existingTemplate.floatWidgets) { const existingFloatWidget = await floatWidgetModel(organization).findOne({ floatWidgetID: floatData.id, + versionId: versionId, + projectId: projectId, isArchive: false, zoneUuid, }); @@ -214,6 +265,8 @@ export const AddTemplateToZone = async ( await floatWidgetModel(organization).create({ className: floatData.className, + versionId: versionId, + projectId: projectId, header: floatData.header, floatWidgetID: floatData.id, position: floatData.position, @@ -250,7 +303,7 @@ export const AddTemplateToZone = async ( }; export const TemplateDelete = async (data: ITemplate): Promise => { try { - const { templateID, projectId, userId, organization } = data; + const { templateID, projectId, userId, organization, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -259,14 +312,26 @@ export const TemplateDelete = async (data: ITemplate): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingTemplate = await templateModel(organization).findOne({ templateID: templateID, isArchive: false, + versionId: versionId, projectId: projectId, }); if (existingTemplate) { const newTemplate = await templateModel(organization).updateOne( - { templateID: templateID, isArchive: false, projectId: projectId }, + { + templateID: templateID, + isArchive: false, + versionId: versionId, + projectId: projectId, + }, { $set: { isArchive: true } } ); if (newTemplate) { @@ -293,7 +358,7 @@ export const TemplateDelete = async (data: ITemplate): Promise => { }; export const GetAllTemplates = async (data: IGetTemplate): Promise => { try { - const { organization, userId, projectId } = data; + const { organization, userId, projectId,versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -302,8 +367,19 @@ export const GetAllTemplates = async (data: IGetTemplate): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const templateDatas = await templateModel(organization) - .find({ projectId: projectId, isArchive: false }) + .find({ + versionId: ExistingVersion._id, + projectId: projectId, + isArchive: false, + }) .select("-_id -__v -isArchive -createdAt -updatedAt"); if (!templateDatas) return { status: "All Datas" }; diff --git a/src/shared/services/visualization/widget3dService.ts b/src/shared/services/visualization/widget3dService.ts index 7095849..ac0b277 100644 --- a/src/shared/services/visualization/widget3dService.ts +++ b/src/shared/services/visualization/widget3dService.ts @@ -3,6 +3,7 @@ import widget3dModel from "../../V1Models/Vizualization/3dwidget.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IResult { status: string; @@ -20,6 +21,7 @@ interface IWidget3DAdd { }; }; projectId: string; + versionId: string; zoneUuid: string; userId: string; } @@ -27,6 +29,7 @@ interface IWidget3dUpdate { organization: string; id: string; projectId: string; + versionId: string; zoneUuid: string; userId: string; } @@ -36,18 +39,21 @@ interface IWidgetUpdate { position: []; rotation: []; projectId: string; + versionId: string; zoneUuid: string; userId: string; } interface I3dWidgetGet { organization: string; projectId: string; + versionId: string; zoneUuid: string; userId: string; } export const Add3DWidget = async (data: IWidget3DAdd): Promise => { try { - const { organization, widget, userId, zoneUuid, projectId } = data; + const { organization, widget, userId, zoneUuid, projectId, versionId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -56,15 +62,24 @@ export const Add3DWidget = async (data: IWidget3DAdd): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; const existing3Dwidget = await widget3dModel(organization).findOne({ widgetID: widget.id, + versionId: versionId, + projectId: projectId, isArchive: false, }); if (existing3Dwidget) { @@ -72,6 +87,8 @@ export const Add3DWidget = async (data: IWidget3DAdd): Promise => { { widgetID: widget.id, zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }, { position: widget.position }, @@ -87,6 +104,8 @@ export const Add3DWidget = async (data: IWidget3DAdd): Promise => { type: widget.type, widgetID: widget.id, position: widget.position, + versionId: versionId, + projectId: projectId, zoneUuid, Data: { measurements: widget?.Data?.measurements || {}, @@ -125,8 +144,16 @@ export const Add3DWidget = async (data: IWidget3DAdd): Promise => { }; export const Update3Dwidget = async (data: IWidgetUpdate): Promise => { try { - const { organization, id, position, rotation, userId, zoneUuid, projectId } = - data; + const { + organization, + id, + position, + rotation, + userId, + zoneUuid, + projectId, + versionId, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; @@ -136,9 +163,16 @@ export const Update3Dwidget = async (data: IWidgetUpdate): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) @@ -148,6 +182,8 @@ export const Update3Dwidget = async (data: IWidgetUpdate): Promise => { const existing3Dwidget = await widget3dModel(organization).findOne({ widgetID: id, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, isArchive: false, }); @@ -155,6 +191,8 @@ export const Update3Dwidget = async (data: IWidgetUpdate): Promise => { const update3dwidget = await widget3dModel(organization).findOneAndUpdate( { widgetID: id, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, isArchive: false, }, @@ -196,7 +234,7 @@ export const Delete3Dwidget = async ( data: IWidget3dUpdate ): Promise => { try { - const { organization, id, userId, zoneUuid, projectId } = data; + const { organization, id, userId, zoneUuid, projectId, versionId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -205,9 +243,16 @@ export const Delete3Dwidget = async ( userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) @@ -218,6 +263,8 @@ export const Delete3Dwidget = async ( const existing3Dwidget = await widget3dModel(organization).findOne({ widgetID: id, isArchive: false, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, }); if (!existing3Dwidget) { @@ -226,6 +273,8 @@ export const Delete3Dwidget = async ( const updateWidget = await widget3dModel(organization).findOneAndUpdate( { widgetID: id, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, isArchive: false, }, @@ -257,7 +306,7 @@ export const Delete3Dwidget = async ( }; export const Get3Dwidget = async (data: I3dWidgetGet): Promise => { try { - const { organization, userId, zoneUuid, projectId } = data; + const { organization, userId, zoneUuid, versionId, projectId } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -266,9 +315,17 @@ export const Get3Dwidget = async (data: I3dWidgetGet): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: ExistingVersion._id, projectId: projectId, }); if (!existingZone) @@ -277,6 +334,8 @@ export const Get3Dwidget = async (data: I3dWidgetGet): Promise => { }; const widgetData = await widget3dModel(organization).find({ zoneUuid: zoneUuid, + versionId: ExistingVersion._id, + projectId: projectId, isArchive: false, }); if (!widgetData || widgetData.length === 0) { diff --git a/src/shared/services/visualization/widgetService.ts b/src/shared/services/visualization/widgetService.ts index 9ff65e8..4329990 100644 --- a/src/shared/services/visualization/widgetService.ts +++ b/src/shared/services/visualization/widgetService.ts @@ -4,6 +4,7 @@ import panelModel from "../../V1Models/Vizualization/panelmodel.ts"; import { existingProjectById, existingUser, + LivingCurrentVersion, } from "../helpers/v1projecthelperFns.ts"; interface IResult { status: string; @@ -14,7 +15,9 @@ interface IWidgetCreate { userId: string; zoneUuid: string; projectId: string; + versionId: string; widget: { + widgetName: string; type: string; title: string; panel: string; @@ -30,6 +33,7 @@ interface IWidgetDelete { userId: string; zoneUuid: string; projectId: string; + versionId: string; widgetID: string; } interface IWidgetUpdate { @@ -37,6 +41,7 @@ interface IWidgetUpdate { userId: string; zoneUuid: string; projectId: string; + versionId: string; widgetID: string; values: { widgetName: string; @@ -57,11 +62,13 @@ interface IGetWidget { userId: string; zoneUuid: string; projectId: string; + versionId: string; widgetID: string; } export const AddWidget = async (data: IWidgetCreate): Promise => { try { - const { organization, widget, userId, zoneUuid, projectId } = data; + const { organization, widget, userId, zoneUuid, projectId, versionId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -70,15 +77,24 @@ export const AddWidget = async (data: IWidgetCreate): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; const existingPanel = await panelModel(organization).findOne({ panelName: widget.panel, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, isArchive: false, }); @@ -87,6 +103,8 @@ export const AddWidget = async (data: IWidgetCreate): Promise => { if (existingPanel.panelName === widget.panel) { const existingWidget = await widgetModel(organization).findOne({ panelID: existingPanel._id, + versionId: versionId, + projectId: projectId, widgetID: widget.id, isArchive: false, }); @@ -94,11 +112,14 @@ export const AddWidget = async (data: IWidgetCreate): Promise => { const updateWidget = await widgetModel(organization).findOneAndUpdate( { panelID: existingPanel._id, + versionId: versionId, + projectId: projectId, widgetID: widget.id, isArchive: false, }, { $set: { + widgetName: widget.widgetName || widget.title, panelID: existingPanel._id, widgetID: widget.id, Data: { @@ -118,9 +139,11 @@ export const AddWidget = async (data: IWidgetCreate): Promise => { const newWidget = await widgetModel(organization).create({ widgetID: widget.id, elementType: widget.type, - widgetName: widget.title, + widgetName: widget.title || widget.widgetName, panelID: existingPanel._id, widgetside: widget.panel, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, Data: { measurements: widget?.Data?.measurements || {}, @@ -164,7 +187,8 @@ export const AddWidget = async (data: IWidgetCreate): Promise => { }; export const WidgetDelete = async (data: IWidgetDelete): Promise => { try { - const { organization, widgetID, userId, zoneUuid, projectId } = data; + const { organization, widgetID, userId, versionId, zoneUuid, projectId } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -173,9 +197,16 @@ export const WidgetDelete = async (data: IWidgetDelete): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; @@ -183,12 +214,20 @@ export const WidgetDelete = async (data: IWidgetDelete): Promise => { const findWidget = await widgetModel(organization).findOne({ widgetID: widgetID, zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); if (!findWidget) return { status: "Widget not found" }; const widgetData = await widgetModel(organization).updateOne( - { _id: findWidget._id, isArchive: false, zoneUuid: zoneUuid }, + { + _id: findWidget._id, + versionId: versionId, + projectId: projectId, + isArchive: false, + zoneUuid: zoneUuid, + }, { $set: { isArchive: true } } ); @@ -196,11 +235,15 @@ export const WidgetDelete = async (data: IWidgetDelete): Promise => { await widgetModel(organization).find({ panelID: findWidget.panelID, zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); const panelData = await panelModel(organization).findOne({ _id: findWidget.panelID, + versionId: versionId, + projectId: projectId, isArchive: false, zoneUuid: zoneUuid, }); @@ -212,6 +255,8 @@ export const WidgetDelete = async (data: IWidgetDelete): Promise => { const activeWidgets = await widgetModel(organization).find({ zoneUuid: zoneUuid, + versionId: versionId, + projectId: projectId, isArchive: false, }); @@ -247,7 +292,15 @@ export const WidgetDelete = async (data: IWidgetDelete): Promise => { }; export const UpdateWidget = async (data: IWidgetUpdate): Promise => { try { - const { organization, widgetID, userId, projectId, zoneUuid, values } = data; + const { + organization, + widgetID, + userId, + projectId, + versionId, + zoneUuid, + values, + } = data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -256,15 +309,24 @@ export const UpdateWidget = async (data: IWidgetUpdate): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + versionId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: versionId, projectId: projectId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; const findWidget = await widgetModel(organization).findOne({ widgetID: widgetID, + versionId: versionId, + projectId: projectId, zoneUuid: zoneUuid, isArchive: false, }); @@ -285,7 +347,12 @@ export const UpdateWidget = async (data: IWidgetUpdate): Promise => { }; await widgetModel(organization).findOneAndUpdate( - { widgetID: widgetID, isArchive: false }, + { + widgetID: widgetID, + versionId: versionId, + projectId: projectId, + isArchive: false, + }, updateData, { new: true, @@ -311,7 +378,8 @@ export const UpdateWidget = async (data: IWidgetUpdate): Promise => { }; export const GetWidget = async (data: IGetWidget): Promise => { try { - const { organization, widgetID, userId, projectId, zoneUuid } = data; + const { organization, widgetID, userId, projectId, versionId, zoneUuid } = + data; const UserExists = await existingUser(userId, organization); if (!UserExists) return { status: "User not found" }; const LivingProject = await existingProjectById( @@ -320,9 +388,17 @@ export const GetWidget = async (data: IGetWidget): Promise => { userId ); if (!LivingProject) return { status: "Project not found" }; + const VersionGetId = versionId ? versionId : LivingProject.Present_version; + const ExistingVersion = await LivingCurrentVersion( + organization, + LivingProject._id, + VersionGetId + ); + if (!ExistingVersion) return { status: "Version Data not found" }; const existingZone = await zoneModel(organization).findOne({ zoneUuid: zoneUuid, isArchive: false, + versionId: ExistingVersion._id, projectId: projectId, }); if (!existingZone) return { status: "Zone not found for the zoneUuid" }; @@ -331,6 +407,8 @@ export const GetWidget = async (data: IGetWidget): Promise => { .findOne({ widgetID: widgetID, zoneUuid: zoneUuid, + versionId: ExistingVersion._id, + projectId: projectId, isArchive: false, }) .select("Data widgetName -_id"); diff --git a/src/shared/services/wall/wallItemservice.ts b/src/shared/services/wall/wallItemservice.ts index fcf812d..098707d 100644 --- a/src/shared/services/wall/wallItemservice.ts +++ b/src/shared/services/wall/wallItemservice.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import wallItemModel from "../../../shared/model/builder/assets/wallitems-Model.ts"; +import wallItemModel from "../../model/builder/assets/wallitems-Model.ts"; interface IWallSetupData { modelUuid: string; modelName: string; @@ -45,7 +45,7 @@ export class WallItems { quaternion, scale, }, - { new: true } + { new: true } ); return { state: "Updated successfully", @@ -67,11 +67,13 @@ export class WallItems { data: newValue, }; } - - } catch (error:unknown) { + } catch (error: unknown) { const err = error as Error; console.error("Error creating wallitems:", error); - return { state: "Failed to create wallitems", data: { message: err.message } }; + return { + state: "Failed to create wallitems", + data: { message: err.message }, + }; } } static async getWallItems(req: Request, res: Response) { diff --git a/src/shared/services/yjs/auto-save.ts b/src/shared/services/yjs/auto-save.ts new file mode 100644 index 0000000..3fd1215 --- /dev/null +++ b/src/shared/services/yjs/auto-save.ts @@ -0,0 +1,92 @@ +import * as Y from "yjs"; +import autoSaveModel from "../../V1Models/yjs/auto-saveModel.ts"; +import { Request, Response } from "express"; + +import { + yDocStore, + observerAttached, +} from "../../../socket-server/utils/yjs/yjsRoomjoin.ts"; + +interface RestoreAutoSaveInput { + organization: string; + projectId: string; + versionId: string; +} +interface clearAutoSaveInput { + organization: string; + projectId: string; + versionId: string; +} + +const serializeYMap = (map: Y.Map): Record => { + const result: Record = {}; + for (const [key, value] of map.entries()) { + if (value instanceof Y.Map) { + result[key] = serializeYMap(value); + } else if (value instanceof Y.Array) { + result[key] = value + .toArray() + .map((item) => (item instanceof Y.Map ? serializeYMap(item) : item)); + } else { + result[key] = value; + } + } + return result; +}; + +export const restoreYDocFromAutoSave = async ( + data: RestoreAutoSaveInput +): Promise<{ status: string; data?: object }> => { + const { projectId, versionId, organization } = data; + const Model = autoSaveModel(organization); + const doc = await Model.findOne({ projectId, versionId }); + + if (!doc?.yjsData) { + return { status: "No auto-saved data found" }; + } + + const ydoc = new Y.Doc(); + try { + const binary = Buffer.from(doc.yjsData, "base64"); + Y.applyUpdateV2(ydoc, new Uint8Array(binary)); + console.log(" Y.Doc restored from auto-saved data"); + } catch (err: any) { + console.error(" Failed to apply Yjs update:", err.message); + return { status: "Corrupted Y.Doc data" }; + } + + const lineMap = ydoc.getMap("lines"); + + const jsonData: Record = {}; + for (const [key, value] of lineMap.entries()) { + const yLine = value as Y.Map; + jsonData[key] = serializeYMap(yLine); + } + + return { status: "Success", data: jsonData }; +}; + +export const clearSnapshotController = async ( + data: clearAutoSaveInput +): Promise<{ status: string; data?: object }> => { + try { + const { projectId, versionId, organization } = data; + const key = `${projectId}-${versionId}`; + + const Model = autoSaveModel(organization); + + // 🗑️ Delete from MongoDB + await Model.deleteMany({ projectId, versionId }); + + // 🧠 Clear from in-memory Y.Doc store + yDocStore.delete(key); + observerAttached.delete(key); + + console.log(`🧹 Cleared snapshot and Y.Doc from memory for: ${key}`); + + return { status: "Success" }; + } catch (err: any) { + console.error("❌ Error clearing snapshot:", err.message); + return { status: "Error", data: { message: err.message } }; + } +}; diff --git a/src/shared/services/yjs/clrearSnapshot.ts b/src/shared/services/yjs/clrearSnapshot.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/shared/services/yjs/clrearSnapshot.ts @@ -0,0 +1 @@ + diff --git a/src/shared/services/yjs/snapshot.ts b/src/shared/services/yjs/snapshot.ts new file mode 100644 index 0000000..5c49c3f --- /dev/null +++ b/src/shared/services/yjs/snapshot.ts @@ -0,0 +1,128 @@ +import * as Y from "yjs"; +import pako from "pako"; +import { getYDoc } from "../../../socket-server/utils/yjs/yjsRoomjoin.ts"; +import snapshotModel from "../../V1Models/yjs/snapshotModel.ts"; +import autosaveModel from "../../V1Models/yjs/auto-saveModel.ts"; +interface SnapshotInput { + organization: string; + projectId: string; + versionId: string; + createdBy: string; + label: string; + ydoc: Y.Doc; +} +interface listSnapshotInput { + organization: string; + projectId: string; + versionId: string; + +} +interface RestoreSnapshotInput { + organization: string; + snapshotId: string; // MongoDB document _id + ydoc: Y.Doc; +} +export const saveSnapshotService = async ({ + organization, + projectId, + versionId, + createdBy, + label, + ydoc, +}: SnapshotInput): Promise<{ status: string; data?: object }> => { + try { + const snapshot = Y.encodeStateAsUpdate(ydoc); // 🧠 Convert Y.Doc to binary + + const snapshotEntry = await snapshotModel(organization).create({ + projectId, + versionId, + createdBy, + label, + snapshotData: Buffer.from(snapshot), + }); + + return { + status: "Success", + data: snapshotEntry, + }; + } catch (error: any) { + return { + status: "Failed to save snapshot", + data: error.message, + }; + } +}; +export const restoreSnapshotService = async ({ + organization, + snapshotId, + ydoc, +}: RestoreSnapshotInput): Promise<{ status: string; data?: object }> => { + try { + const snapshot = await snapshotModel(organization).findById(snapshotId); + console.log('snapshotEntry: ', snapshot); + + if (!snapshot) { + return { status: "Snapshot not found" }; + } + + // ✅ Create new Y.Doc and apply update + const ydoc = new Y.Doc(); + Y.applyUpdate(ydoc, new Uint8Array(snapshot.snapshotData)); + + // ✅ Convert to JSON manually + const lineMap = ydoc.getMap('lines'); + const jsonResult: any = {}; + for (const [key, val] of lineMap.entries()) { + if (val instanceof Y.Map) { + const obj: any = {}; + val.forEach((v, k) => { + if (v instanceof Y.Array) { + obj[k] = v.map((item: any) => + item instanceof Y.Map + ? Object.fromEntries(item.entries()) + : item + ); + } else if (v instanceof Y.Map) { + obj[k] = Object.fromEntries(v.entries()); + } else { + obj[k] = v; + } + }); + jsonResult[key] = obj; + } + } + return { + status: "Success", + data: { + snapshotId, + label: snapshot.label, + datas:jsonResult, + restoredAt: new Date(), + }, + }; + } catch (error: any) { + return { + status: "Failed to restore snapshot", + data: error.message, + }; + } +}; +export const listSnapshotService = async ( +data:listSnapshotInput +): Promise<{ status: string; data?: object }> => { + try { + + const { projectId, versionId, organization } = data; + const SnapModel = snapshotModel(organization); + const snapshots = await SnapModel.find({ projectId, versionId }) + .sort({ createdAt: -1 }) // latest first + .select("label createdAt _id"); + + return { status: "Success", data: snapshots }; + } catch (error: any) { + return { + status: "Failed to save snapshot", + data: error.message, + }; + } +}; \ No newline at end of file diff --git a/src/socket-server/Dockerfile b/src/socket-server/Dockerfile index 5d2cce8..95ca2d4 100644 --- a/src/socket-server/Dockerfile +++ b/src/socket-server/Dockerfile @@ -26,7 +26,7 @@ USER root COPY . . # Expose the port that the application listens on. -EXPOSE 7999 +EXPOSE 1059 # Run the application. diff --git a/src/socket-server/controllers/builderController/aisle-Controller.ts b/src/socket-server/controllers/builderController/aisle-Controller.ts index 4df0750..9107534 100644 --- a/src/socket-server/controllers/builderController/aisle-Controller.ts +++ b/src/socket-server/controllers/builderController/aisle-Controller.ts @@ -20,7 +20,13 @@ export const SetAisleHandleEvent = async ( } ) => { if (event !== EVENTS.setAisleModel_v1 || !data?.organization) return; - const requiredFields = ["aisleUuid", "projectId", "userId", "organization"]; + const requiredFields = [ + "aisleUuid", + "projectId", + "versionId", + "userId", + "organization", + ]; const missingFields = validateFields(data, requiredFields); if (missingFields.length > 0) { @@ -41,6 +47,9 @@ export const SetAisleHandleEvent = async ( Success: { message: "Aisle Created Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Aisle Not Updated": { message: "Aisle Not Updated" }, "Aisle Not Created": { message: "Aisle Not Created" }, "Aisle Updated Successfully": { message: "Aisle Updated Successfully" }, @@ -76,7 +85,13 @@ export const DeleteAisleHandleEvent = async ( } ) => { if (event !== EVENTS.delete_v1AisleModel || !data?.organization) return; - const requiredFields = ["aisleUuid", "projectId", "userId", "organization"]; + const requiredFields = [ + "aisleUuid", + "projectId", + "versionId", + "userId", + "organization", + ]; const missingFields = validateFields(data, requiredFields); if (missingFields.length > 0) { @@ -97,6 +112,9 @@ export const DeleteAisleHandleEvent = async ( Success: { message: "Aisle Deleted Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Aisle not found": { message: "Aisle not found" }, }; diff --git a/src/socket-server/controllers/builderController/asset-Controller.ts b/src/socket-server/controllers/builderController/asset-Controller.ts index 7c0e360..e23b307 100644 --- a/src/socket-server/controllers/builderController/asset-Controller.ts +++ b/src/socket-server/controllers/builderController/asset-Controller.ts @@ -31,6 +31,7 @@ export const setAssetHandleEvent = async ( "isLocked", "isVisible", "projectId", + "versionId", "userId", "organization", ]; @@ -54,6 +55,9 @@ export const setAssetHandleEvent = async ( Success: { message: "Model created successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Updated successfully": { message: "Updated successfully" }, }; @@ -87,10 +91,10 @@ export const deleteAssetHandleEvent = async ( } ) => { if (event !== EVENTS.delete_v1AssetModel || !data?.organization) return; - console.log('event: ', event); const requiredFields = [ "modelUuid", "modelName", + "versionId", "projectId", "userId", "organization", @@ -115,6 +119,9 @@ export const deleteAssetHandleEvent = async ( Success: { message: "Model deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "model not found": { message: "model not found" }, "Failed to archive asset": { message: "Failed to archive asset" }, }; @@ -152,6 +159,7 @@ export const replaceEventDatasHandleEvent = async ( "modelUuid", "eventData", "projectId", + "versionId", "userId", "organization", ]; @@ -174,6 +182,9 @@ export const replaceEventDatasHandleEvent = async ( Success: { message: "Data updated successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Model not for this UUID": { message: "Model not for this UUID" }, "Failed to archive asset": { message: "Failed to archive asset" }, }; diff --git a/src/socket-server/controllers/builderController/camera-Controller.ts b/src/socket-server/controllers/builderController/camera-Controller.ts index 664316f..b9d3cf1 100644 --- a/src/socket-server/controllers/builderController/camera-Controller.ts +++ b/src/socket-server/controllers/builderController/camera-Controller.ts @@ -2,54 +2,70 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; import { SetCamera } from "../../../shared/services/builder/cameraService.ts"; -import { ErrorResponse, FinalResponse, validateFields } from "../../utils/socketfunctionHelpers.ts"; +import { + ErrorResponse, + FinalResponse, + validateFields, +} from "../../utils/socketfunctionHelpers.ts"; export const SetCameraHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.setCamera_v1 || !data?.organization) return; - console.log('event: ', event); - const requiredFields = [ - "position", - "target", - "rotation", - "projectId", - "userId", - "organization", - ]; + if (event !== EVENTS.setCamera_v1 || !data?.organization) return; + const requiredFields = [ + "position", + "target", + "rotation", + "projectId", + "userId", + "organization", + ]; const missingFields = validateFields(data, requiredFields); - - if (missingFields.length > 0) { - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.camera_v1CreateResponse, - ErrorResponse(missingFields, socket, data.organization), connectedUsersByOrg); - return; - } - const result = await SetCamera(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - const messages: Record = { - Success: { message: "Camera created successfully" }, - "User not found": { message: "User not found" }, - "Project not found": { message: "Project not found" }, - "Update Success": { message: "Update Success" }, + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.camera_v1CreateResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + console.log("event: camera", event); + const result = await SetCamera(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; + const messages: Record = { + Success: { message: "Camera created successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + "Update Success": { message: "Update Success" }, + }; - }; + const msg = messages[status] || { message: "Internal server error" }; + const Camera_Datas = status === "Success" && result?.data ? {} : undefined; - const msg = messages[status] || { message: "Internal server error" }; - const Camera_Datas = - status === "Success" && result?.data + const response = FinalResponse( + status, + socket, + data.organization, + messages, + Camera_Datas + ); - ? { - - } - : undefined; - - const response = FinalResponse(status, socket, data.organization, messages, Camera_Datas); - - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.camera_v1CreateResponse, response, connectedUsersByOrg) -} \ No newline at end of file + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.camera_v1CreateResponse, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/builderController/environment-Controller.ts b/src/socket-server/controllers/builderController/environment-Controller.ts index 097b15c..735a9ab 100644 --- a/src/socket-server/controllers/builderController/environment-Controller.ts +++ b/src/socket-server/controllers/builderController/environment-Controller.ts @@ -2,51 +2,73 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; import { setEnvironment } from "../../../shared/services/builder/EnvironmentService.ts"; -import { ErrorResponse, FinalResponse, validateFields } from "../../utils/socketfunctionHelpers.ts"; +import { + ErrorResponse, + FinalResponse, + validateFields, +} from "../../utils/socketfunctionHelpers.ts"; export const setEnvironmentHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.setenvironment_v1 || !data?.organization) return; - const requiredFields = [ - "roofVisibility", "wallVisibility", "shadowVisibility", - "projectId", - "userId", - "organization", - ]; + if (event !== EVENTS.setenvironment_v1 || !data?.organization) return; + const requiredFields = [ + "roofVisibility", + "wallVisibility", + "shadowVisibility", + "projectId", + "userId", + "organization", + ]; const missingFields = validateFields(data, requiredFields); - - if (missingFields.length > 0) { - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.Environment_v1UpdateResponse, - ErrorResponse(missingFields, socket, data.organization), connectedUsersByOrg); - return; - } - const result = await setEnvironment(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - const messages: Record = { - Success: { message: "evironment created successfully" }, - "User not found": { message: "User not found" }, - "Project not found": { message: "Project not found" }, - 'evironments updated': { message: 'evironments updated' }, + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.Environment_v1UpdateResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + const result = await setEnvironment(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; + const messages: Record = { + Success: { message: "evironment created successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, + "evironments updated": { message: "evironments updated" }, + }; - }; + const msg = messages[status] || { message: "Internal server error" }; + const environment_Datas = + status === "Success" && result?.data ? {} : undefined; + const response = FinalResponse( + status, + socket, + data.organization, + messages, + environment_Datas + ); - const msg = messages[status] || { message: "Internal server error" }; - const environment_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; - const response = FinalResponse(status, socket, data.organization, messages, environment_Datas); - - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.Environment_v1UpdateResponse, response, connectedUsersByOrg) -} \ No newline at end of file + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.Environment_v1UpdateResponse, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/builderController/line-Controller.ts b/src/socket-server/controllers/builderController/line-Controller.ts index 39b4901..608d9dc 100644 --- a/src/socket-server/controllers/builderController/line-Controller.ts +++ b/src/socket-server/controllers/builderController/line-Controller.ts @@ -27,7 +27,7 @@ export const CreateLineHandleEvent = async ( "line", "type", "layer", - "projectId", + "projectId","versionId", "userId", "organization", ]; @@ -50,6 +50,9 @@ export const CreateLineHandleEvent = async ( Success: { message: "line created successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Update Success": { message: "Update Success" }, }; @@ -86,7 +89,7 @@ export const UpdateLineHandleEvent = async ( const requiredFields = [ "uuid", "position", - "projectId", + "projectId","versionId", "userId", "organization", ]; @@ -110,6 +113,9 @@ export const UpdateLineHandleEvent = async ( Success: { message: "line updated successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, }; const msg = messages[status] || { message: "Internal server error" }; @@ -142,8 +148,7 @@ export const DeleteLineHandleEvent = async ( } ) => { if (event !== EVENTS.deleteLine_v1 || !data?.organization) return; - console.log("event: ", event); - const requiredFields = ["line", "projectId", "userId", "organization"]; + const requiredFields = ["line", "projectId","versionId", "userId", "organization"]; const missingFields = validateFields(data, requiredFields); @@ -165,6 +170,9 @@ export const DeleteLineHandleEvent = async ( Success: { message: "line deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "line not found": { message: "line not found" }, }; @@ -198,8 +206,7 @@ export const DeleteLayerHandleEvent = async ( } ) => { if (event !== EVENTS.deleteLineLayer_v1 || !data?.organization) return; - console.log("event:-layer ", event); - const requiredFields = ["layer", "projectId", "userId", "organization"]; + const requiredFields = ["layer", "projectId","versionId", "userId", "organization"]; const missingFields = validateFields(data, requiredFields); if (missingFields.length > 0) { @@ -220,6 +227,9 @@ export const DeleteLayerHandleEvent = async ( Success: { message: "layer deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "layer not found": { message: "layer not found" }, }; @@ -253,8 +263,7 @@ export const DeleteLinePointsHandleEvent = async ( } ) => { if (event !== EVENTS.deletePoint_v1 || !data?.organization) return; - console.log("event:point ", event); - const requiredFields = ["uuid", "projectId", "userId", "organization"]; + const requiredFields = ["uuid", "projectId","versionId", "userId", "organization"]; const missingFields = validateFields(data, requiredFields); @@ -276,6 +285,9 @@ export const DeleteLinePointsHandleEvent = async ( Success: { message: "point deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Line not found": { message: "Line not found" }, }; diff --git a/src/socket-server/controllers/builderController/wall-Controller.ts b/src/socket-server/controllers/builderController/wall-Controller.ts index e79fec9..e706d83 100644 --- a/src/socket-server/controllers/builderController/wall-Controller.ts +++ b/src/socket-server/controllers/builderController/wall-Controller.ts @@ -28,8 +28,8 @@ export const setWallItemsHandleEvent = async ( "type", "csgposition", "csgscale", - "quaternion", "assetId", + "quaternion","versionId", "scale", "projectId", "userId", @@ -56,9 +56,11 @@ export const setWallItemsHandleEvent = async ( Success: { message: "wall Item created successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Updated successfully": { message: "Updated successfully" }, }; - const msg = messages[status] || { message: "Internal server error" }; const wall_Datas = status === "Success" && result?.data ? {} : undefined; @@ -92,7 +94,7 @@ export const deleteWallItemsHandleEvent = async ( const requiredFields = [ "modelUuid", "modelName", - "projectId", + "projectId","versionId", "userId", "organization", ]; @@ -116,6 +118,9 @@ export const deleteWallItemsHandleEvent = async ( Success: { message: "wall Item deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "model not found": { message: "model not found" }, }; diff --git a/src/socket-server/controllers/builderController/zone-Controller.ts b/src/socket-server/controllers/builderController/zone-Controller.ts index 4e14096..4c7326a 100644 --- a/src/socket-server/controllers/builderController/zone-Controller.ts +++ b/src/socket-server/controllers/builderController/zone-Controller.ts @@ -1,101 +1,138 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; -import { DelZone, SetZone } from "../../../shared/services/builder/zoneService.ts"; -import { ErrorResponse, FinalResponse, validateFields } from "../../utils/socketfunctionHelpers.ts"; - +import { + DelZone, + SetZone, +} from "../../../shared/services/builder/zoneService.ts"; +import { + ErrorResponse, + FinalResponse, + validateFields, +} from "../../utils/socketfunctionHelpers.ts"; export const SetZoneHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.setZone_v1 || !data?.organization) return; - const requiredFields = [ - "zoneData", - "projectId", - "userId", - "organization", - ]; - const missingFields = validateFields(data, requiredFields); + if (event !== EVENTS.setZone_v1 || !data?.organization) return; + const requiredFields = [ + "zoneData", + "projectId", + "versionId", + "userId", + "organization", + ]; + const missingFields = validateFields(data, requiredFields); - if (missingFields.length > 0) { - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.zone_v1UpdateResponse, - ErrorResponse(missingFields, socket, data.organization), connectedUsersByOrg); - return; - } - const result = await SetZone(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.zone_v1UpdateResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + const result = await SetZone(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - const messages: Record = { - Success: { message: "zone created successfully" }, - "User not found": { message: "User not found" }, - "Project not found": { message: "Project not found" }, - "zone updated": { message: "zone updated" }, + const messages: Record = { + Success: { message: "zone created successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, + "zone updated": { message: "zone updated" }, + }; + const msg = messages[status] || { message: "Internal server error" }; + const zone_Datas = status === "Success" && result?.data ? {} : undefined; - }; + const response = FinalResponse( + status, + socket, + data.organization, + messages, + zone_Datas + ); - const msg = messages[status] || { message: "Internal server error" }; - const zone_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; - - const response = FinalResponse(status, socket, data.organization, messages, zone_Datas); - - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.zone_v1UpdateResponse, response, connectedUsersByOrg) -} + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.zone_v1UpdateResponse, + response, + connectedUsersByOrg + ); +}; export const DeleteZoneHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.deleteZone_v1 || !data?.organization) return; - const requiredFields = [ - "zoneUuid", - "projectId", - "userId", - "organization", - ]; + if (event !== EVENTS.deleteZone_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "projectId", + "versionId", + "userId", + "organization", + ]; - const missingFields = validateFields(data, requiredFields); + const missingFields = validateFields(data, requiredFields); - if (missingFields.length > 0) { - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.Zone_v1DeleteResponse, - ErrorResponse(missingFields, socket, data.organization), connectedUsersByOrg); - return; - } - const result = await DelZone(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.Zone_v1DeleteResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + const result = await DelZone(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - const messages: Record = { - Success: { message: "zone deleted created successfully" }, - "User not found": { message: "User not found" }, - "Project not found": { message: "Project not found" }, + const messages: Record = { + Success: { message: "zone deleted created successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, + }; + const zone_Datas = status === "Success" && result?.data ? {} : undefined; + const response = FinalResponse( + status, + socket, + data.organization, + messages, + zone_Datas + ); - }; - - const zone_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; - - const response = FinalResponse(status, socket, data.organization, messages, zone_Datas); - - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.Zone_v1DeleteResponse, response, connectedUsersByOrg) -} \ No newline at end of file + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.Zone_v1DeleteResponse, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/collaborative/lineController-collab.ts b/src/socket-server/controllers/collaborative/lineController-collab.ts new file mode 100644 index 0000000..2a36b00 --- /dev/null +++ b/src/socket-server/controllers/collaborative/lineController-collab.ts @@ -0,0 +1,173 @@ +import { Socket, Server } from "socket.io"; +import { EVENTS } from "../../socket/events.ts"; +import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; +import { + FinalResponse, + ErrorResponse, + validateFields, +} from "../../utils/socketfunctionHelpers.ts"; +import { + createLineService, + DeleteLineItems, + updateLineService, +} from "../../../shared/services/collaborative/lineService-collab.ts"; +import { getYDoc } from "../../utils/yjs/yjsRoomjoin.ts"; + +export const CreateLineHandleEventYjs = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: any +) => { + if (event !== EVENTS.createLineYjs_v1 || !data?.organization) return; + + const missingFields = validateFields(data, [ + "line", + "type", + "layer", + "projectId", + "userId", + "organization", + ]); + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.createLineYjs_v1Response, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + + const result = await createLineService(data); + const status = result.status; + const response = FinalResponse( + status, + socket, + data.organization, + { + Success: { message: "Line created successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + }, + result?.data + ); + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.createLine_v1Response, + response, + connectedUsersByOrg + ); +}; + +export const UpdateLineHandleEventYjs = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: any +) => { + if (event !== EVENTS.updateLineYjs_v1 || !data?.organization) return; + + const missingFields = validateFields(data, [ + "uuid", + "position", + "projectId", + "userId", + "organization", + ]); + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.updateLineYjs_v1Response, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + + const result = await updateLineService(data); + const status = result.status; + const response = FinalResponse( + status, + socket, + data.organization, + { + Success: { message: "Line updated successfully" }, + "Update failed": { message: "Update failed" }, + }, + result?.data + ); + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.updateLineYjs_v1Response, + response, + connectedUsersByOrg + ); +}; +export const DeleteLineHandleEventYjs = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } +) => { + if (event !== EVENTS.deleteLineYjs_v1 || !data?.organization) return; + const requiredFields = ["line", "projectId", "userId", "organization"]; + + const missingFields = validateFields(data, requiredFields); + + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deleteLineYjs_v1Response, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + const result = await DeleteLineItems(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; + + const messages: Record = { + Success: { message: "line deleted successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + "line not found": { message: "line not found" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Line_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = FinalResponse( + status, + socket, + data.organization, + messages, + Line_Datas + ); + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deleteLineYjs_v1Response, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/projectController/projectController.ts b/src/socket-server/controllers/projectController/projectController.ts index 02b71ff..e9191c3 100644 --- a/src/socket-server/controllers/projectController/projectController.ts +++ b/src/socket-server/controllers/projectController/projectController.ts @@ -23,7 +23,6 @@ export const projectHandleEvent = async ( }, callback?: Function ) => { - console.log("event: ", event); if (event !== EVENTS.addProject || !data?.organization) return; const requiredFields = ["projectUuid", "userId", "thumbnail", "organization"]; const missingFields = validateFields(data, requiredFields); @@ -82,7 +81,6 @@ export const projectDeleteHandleEvent = async ( [org: string]: { socketId: string; userId: string; role: string }[]; } ) => { - console.log("event: ", event); if (event !== EVENTS.deleteProject || !data?.organization) return; const requiredFields = ["projectId", "userId", "organization"]; @@ -106,6 +104,9 @@ export const projectDeleteHandleEvent = async ( Success: { message: "Project Deleted Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, }; const msg = messages[status] || { message: "Internal server error" }; @@ -145,7 +146,6 @@ export const projecUpdateHandleEvent = async ( [org: string]: { socketId: string; userId: string; role: string }[]; } ) => { - console.log("event: ", event); if (event !== EVENTS.ProjectUpdate || !data?.organization) return; const requiredFields = ["projectId", "userId", "organization"]; const missingFields = validateFields(data, requiredFields); @@ -168,6 +168,9 @@ export const projecUpdateHandleEvent = async ( Success: { message: "Project updated Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, }; const msg = messages[status] || { message: "Internal server error" }; @@ -207,7 +210,6 @@ export const DuplicateProjectHandleEvent = async ( }, callback?: Function ) => { - console.log("event: ", event); if (event !== EVENTS.DuplicateProject || !data?.organization) return; const requiredFields = [ "projectUuid", diff --git a/src/socket-server/controllers/simulationController/product-Controller.ts b/src/socket-server/controllers/simulationController/product-Controller.ts index 7444727..90b0ae2 100644 --- a/src/socket-server/controllers/simulationController/product-Controller.ts +++ b/src/socket-server/controllers/simulationController/product-Controller.ts @@ -21,6 +21,7 @@ export const productAddHandleEvent = async ( "productName", "productUuid", "projectId", + "versionId", "userId", "organization", ]; @@ -52,6 +53,9 @@ export const productAddHandleEvent = async ( Success: { message: "Product created successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "EventData updated successfully": { message: "EventData updated successfully", }, @@ -89,7 +93,13 @@ export const productDataDeleteHandleEvent = async ( } ) => { if (event !== EVENTS.delete_v1ProductModel || !data?.organization) return; - const requiredFields = ["productUuid", "projectId", "userId", "organization"]; + const requiredFields = [ + "productUuid", + "versionId", + "projectId", + "userId", + "organization", + ]; const missingFields = requiredFields.filter((field) => !data?.[field]); if (missingFields.length > 0) { @@ -118,6 +128,9 @@ export const productDataDeleteHandleEvent = async ( Success: { message: "Product deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Product not found": { message: "Product not found" }, }; @@ -168,6 +181,7 @@ export const EventDataDeleteHandleEvent = async ( "modelUuid", "productUuid", "projectId", + "versionId", "userId", "organization", ]; @@ -199,6 +213,9 @@ export const EventDataDeleteHandleEvent = async ( Success: { message: "EventData deleted successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Product not found": { message: "Product not found" }, "Event Delete Unsuccessful": { message: "Event Delete Unsuccessful" }, }; @@ -249,6 +266,7 @@ export const productRenameHandleEvent = async ( "productName", "productUuid", "projectId", + "versionId", "userId", "organization", ]; @@ -280,6 +298,9 @@ export const productRenameHandleEvent = async ( Success: { message: "product Rename successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "Version Data not found": { + message: "Version Data not found", + }, "Product not found": { message: "Product not found" }, "Rename Unsuccessful": { message: "Rename Unsuccessful" }, }; diff --git a/src/socket-server/controllers/thread/threadController.ts b/src/socket-server/controllers/thread/threadController.ts index e445d20..2f5f830 100644 --- a/src/socket-server/controllers/thread/threadController.ts +++ b/src/socket-server/controllers/thread/threadController.ts @@ -1,22 +1,50 @@ -import { Socket } from "socket.io"; +import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; -import { emitEventResponse } from "../../utils/emitEventResponse.ts"; -import { addComments, createThread, deleteComments, deleteThread } from "../../../shared/services/Thread/ThreadService.ts"; -export const createThreadHandleEvent = async (event: string, socket: Socket, data: any,) => { +import { + emitEventResponse, + emitToSenderAndAdmins, +} from "../../utils/emitEventResponse.ts"; +import { + addComments, + createThread, + deleteComments, + deleteThread, + findThreads, + updateThreadTitle, +} from "../../../shared/services/Thread/ThreadService.ts"; +import { + ErrorResponse, + FinalResponse, + validateFields, +} from "../../utils/socketfunctionHelpers.ts"; +export const createThreadHandleEvent = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } +) => { if (event !== EVENTS.createThread || !data?.organization) return; - const requiredFields = ["userId", "position", "rotation", "organization", "projectId", "versionId"]; - const missingFields = requiredFields.filter(field => !data?.[field]); + const requiredFields = [ + "userId", + "position", + "rotation", + "organization", + "projectId", + ]; + const missingFields = validateFields(data, requiredFields); if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitEventResponse(socket, data?.organization, EVENTS.ThreadCreateResponse, response); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.ThreadCreateResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); return; } @@ -27,38 +55,62 @@ export const createThreadHandleEvent = async (event: string, socket: Socket, dat Success: { message: "Thread created Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, }; const msg = messages[status] || { message: "Internal server error" }; - const threadDatas = - status === "Success" && result?.data + const threadDatas = status === "Success" && result?.data; - const response = { - success: status === "Success", - message: msg.message, + // const response = { + // success: status === "Success", + // message: msg.message, + // status, + // socketId: socket.id, + // organization: data.organization, + // ...(threadDatas ? { data: threadDatas } : {}), + // }; + + const response = FinalResponse( status, - socketId: socket.id, - organization: data.organization, - ...(threadDatas ? { data: threadDatas } : {}), - }; + socket, + data.organization, + messages, + threadDatas + ); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.ThreadCreateResponse, + response, + connectedUsersByOrg + ); - - emitEventResponse(socket, data.organization, EVENTS.ThreadCreateResponse, response); -} -export const deleteThreadHandleEvent = async (event: string, socket: Socket, data: any,) => { + // emitEventResponse(socket, data.organization, EVENTS.ThreadCreateResponse, response); +}; +export const deleteThreadHandleEvent = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } +) => { if (event !== EVENTS.deleteThread || !data?.organization) return; - const requiredFields = ["userId", "threadId", "organization", "projectId", "versionId"]; - const missingFields = requiredFields.filter(field => !data?.[field]); + const requiredFields = ["userId", "threadId", "organization", "projectId"]; + const missingFields = validateFields(data, requiredFields); if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitEventResponse(socket, data?.organization, EVENTS.deleteThreadResponse, response); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deleteThreadResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); return; } @@ -69,39 +121,53 @@ export const deleteThreadHandleEvent = async (event: string, socket: Socket, dat Success: { message: "Thread deleted Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, "can't deleted": { message: "Thread could not be deleted" }, }; const msg = messages[status] || { message: "Internal server error" }; - const threadDatas = - status === "Success" && result?.data + const threadDatas = status === "Success" && result?.data; - const response = { - success: status === "Success", - message: msg.message, + const response = FinalResponse( status, - socketId: socket.id, - organization: data.organization, - ...(threadDatas ? { data: threadDatas } : {}), - }; - - - emitEventResponse(socket, data.organization, EVENTS.deleteThreadResponse, response); -} -export const addCommentHandleEvent = async (event: string, socket: Socket, data: any,) => { + socket, + data.organization, + messages, + threadDatas + ); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deleteThreadResponse, + response, + connectedUsersByOrg + ); +}; +export const addCommentHandleEvent = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } +) => { if (event !== EVENTS.addComment || !data?.organization) return; - const requiredFields = ["userId", "comments", "organization", "commentId", "projectId", "versionId"]; - const missingFields = requiredFields.filter(field => !data?.[field]); + const requiredFields = ["userId", "organization", "threadId", "projectId"]; + + const missingFields = validateFields(data, requiredFields); if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitEventResponse(socket, data?.organization, EVENTS.addCommentResponse, response); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addCommentResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); return; } @@ -109,69 +175,144 @@ export const addCommentHandleEvent = async (event: string, socket: Socket, data: const status = typeof result?.status === "string" ? result.status : "unknown"; const messages: Record = { - Success: { message: "Thread created Successfully" }, + Success: { message: "Thread comments add Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, + updated: { message: "Comment updated successfully" }, }; const msg = messages[status] || { message: "Internal server error" }; - const commentsData = - status === "Success" && result?.data - - - const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(commentsData ? { data: commentsData } : {}), - }; - - - emitEventResponse(socket, data.organization, EVENTS.addCommentResponse, response); -} -export const deleteCommentHandleEvent = async (event: string, socket: Socket, data: any,) => { - if (event !== EVENTS.deleteComment || !data?.organization) return; - const requiredFields = ["userId", "organization", "commentId", "projectId", "versionId"]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitEventResponse(socket, data?.organization, EVENTS.deleteCommentResponse, response); - return; + let commentsData; + if (status === "Success" || status === "updated") { + commentsData = result?.data; } + const response = FinalResponse( + status, + socket, + data.organization, + messages, + commentsData + ); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addCommentResponse, + response, + connectedUsersByOrg + ); +}; +export const deleteCommentHandleEvent = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } +) => { + if (event !== EVENTS.deleteComment || !data?.organization) return; + const requiredFields = ["userId", "organization", "commentId", "projectId"]; + + const missingFields = validateFields(data, requiredFields); + + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deleteCommentResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } const result = await deleteComments(data); const status = typeof result?.status === "string" ? result.status : "unknown"; const messages: Record = { - Success: { message: "Thread created Successfully" }, + Success: { message: "Thread comment deleted Successfully" }, "User not found": { message: "User not found" }, "Project not found": { message: "Project not found" }, - "unauthorized": { message: "You can only delete your own comment." }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, + unauthorized: { message: "You can only delete your own comment." }, "thread not found": { message: "thread not found" }, }; const msg = messages[status] || { message: "Internal server error" }; - const commentsData = - status === "Success" && result?.data + const commentsData = status === "Success" && result?.data; - - const response = { - success: status === "Success", - message: msg.message, + const response = FinalResponse( status, - socketId: socket.id, - organization: data.organization, - ...(commentsData ? { data: commentsData } : {}), + socket, + data.organization, + messages, + commentsData + ); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deleteCommentResponse, + response, + connectedUsersByOrg + ); +}; +export const threadUpdateHandleEvent = async ( + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } +) => { + if (event !== EVENTS.updateThreat || !data?.organization) return; + const requiredFields = ["userId", "organization", "threadId", "projectId"]; + const missingFields = validateFields(data, requiredFields); + + if (missingFields.length > 0) { + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.updateThreatResponse, + ErrorResponse(missingFields, socket, data.organization), + connectedUsersByOrg + ); + return; + } + const result = await updateThreadTitle(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; + + const messages: Record = { + Success: { message: "ThreadTitle updated Successfully" }, + "User not found": { message: "User not found" }, + "Project not found": { message: "Project not found" }, + "CurrentVersion Data not found": { + message: "CurrentVersion Data not found", + }, }; + const msg = messages[status] || { message: "Internal server error" }; + const commentsData = status === "Success" && result?.data; - - emitEventResponse(socket, data.organization, EVENTS.deleteCommentResponse, response); -} \ No newline at end of file + const response = FinalResponse( + status, + socket, + data.organization, + messages, + commentsData + ); + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.updateThreatResponse, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/trashController/trash-Controller.ts b/src/socket-server/controllers/trashController/trash-Controller.ts index 1029515..1d4ea71 100644 --- a/src/socket-server/controllers/trashController/trash-Controller.ts +++ b/src/socket-server/controllers/trashController/trash-Controller.ts @@ -11,7 +11,6 @@ export const TrashDeleteHandleEvent = async ( data: any, connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, callback?: Function ) => { - console.log('event: ', event); if (event !== EVENTS.deleteTrash_v1 || !data?.organization) return; const requiredFields = ["projectId","userId", "organization"]; const missingFields = requiredFields.filter(field => !data?.[field]); diff --git a/src/socket-server/controllers/vizualizationController/3dWidget-Controller.ts b/src/socket-server/controllers/vizualizationController/3dWidget-Controller.ts index 665786d..45aa52d 100644 --- a/src/socket-server/controllers/vizualizationController/3dWidget-Controller.ts +++ b/src/socket-server/controllers/vizualizationController/3dWidget-Controller.ts @@ -1,168 +1,232 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; -import { Add3DWidget, Delete3Dwidget, Update3Dwidget } from "../../../shared/services/visualization/widget3dService.ts"; +import { + Add3DWidget, + Delete3Dwidget, + Update3Dwidget, +} from "../../../shared/services/visualization/widget3dService.ts"; export const add3DwidgetHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.addWidget3D || !data?.organization) return; - const requiredFields = ["projectId", "userId", "organization", "zoneUuid", "widget"]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.addWidget3DResponse, response, connectedUsersByOrg) - return; - } - const result = await Add3DWidget(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Widget created successfully" }, - "User not found": { message: "User not found" }, - "Zone not found for the zoneUuid": { message: "Zone not found for the zoneUuid" }, - "3dwidget update successfully": { message: "widget update successfully" }, - "3dWidget not updated": { message: "3dWidget not updated" }, - "Widget 3d not created": { message: "Widget 3d not created" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const widgemodel3D_Datas = - status === "Success" && result?.data - - ? { - } - : undefined; + if (event !== EVENTS.addWidget3D || !data?.organization) return; + const requiredFields = [ + "projectId", + "versionId", + "userId", + "organization", + "zoneUuid", + "widget", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(widgemodel3D_Datas ? { data: widgemodel3D_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addWidget3DResponse, + response, + connectedUsersByOrg + ); + return; + } + const result = await Add3DWidget(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.addWidget3DResponse, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "Widget created successfully" }, + "User not found": { message: "User not found" }, + "Zone not found for the zoneUuid": { + message: "Zone not found for the zoneUuid", + }, + "Version Data not found": { message: "Version Data not found" }, + "3dwidget update successfully": { message: "widget update successfully" }, + "3dWidget not updated": { message: "3dWidget not updated" }, + "Widget 3d not created": { message: "Widget 3d not created" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const widgemodel3D_Datas = + status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(widgemodel3D_Datas ? { data: widgemodel3D_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addWidget3DResponse, + response, + connectedUsersByOrg + ); +}; export const update3DHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.updateWidget3DPosition || !data?.organization) return; - const requiredFields = ["projectId", "id", "position", "rotation", "userId", "organization", "zoneUuid", "widget"]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.updateWidget3DPositionResponse, response, connectedUsersByOrg) - return; - } - const result = await Update3Dwidget(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "widget update successfully" }, - "User not found": { message: "User not found" }, - "Zone not found": { message: "Zone not found" }, - "Widget not updated": { message: "Widget not updated" }, - "widget not found": { message: "widget not found" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const widget3D_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.updateWidget3DPosition || !data?.organization) return; + const requiredFields = [ + "projectId", + "versionId", + "id", + "position", + "rotation", + "userId", + "organization", + "zoneUuid", + "widget", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(widget3D_Datas ? { data: widget3D_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.updateWidget3DPositionResponse, + response, + connectedUsersByOrg + ); + return; + } + const result = await Update3Dwidget(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.updateWidget3DPositionResponse, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "widget update successfully" }, + "User not found": { message: "User not found" }, + "Zone not found": { message: "Zone not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Widget not updated": { message: "Widget not updated" }, + "widget not found": { message: "widget not found" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const widget3D_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(widget3D_Datas ? { data: widget3D_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.updateWidget3DPositionResponse, + response, + connectedUsersByOrg + ); +}; export const Delete3DwidgetHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.deleteWidget3D || !data?.organization) return; - const requiredFields = ["projectId", "id", "userId", "organization", "zoneUuid",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.deletewidget3DResponse, response, connectedUsersByOrg) - return; - } - const result = await Delete3Dwidget(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "3DWidget delete unsuccessfull" }, - "User not found": { message: "User not found" }, - "Zone not found": { message: "Zone not found" }, - "3D widget not found for the ID": { message: "3D widget not found for the ID" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const widget3D_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.deleteWidget3D || !data?.organization) return; + const requiredFields = [ + "projectId", + "versionId", + "id", + "userId", + "organization", + "zoneUuid", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(widget3D_Datas ? { data: widget3D_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deletewidget3DResponse, + response, + connectedUsersByOrg + ); + return; + } + const result = await Delete3Dwidget(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.deletewidget3DResponse, response, connectedUsersByOrg) -} \ No newline at end of file + const messages: Record = { + Success: { message: "3DWidget delete unsuccessfull" }, + "User not found": { message: "User not found" }, + "Zone not found": { message: "Zone not found" }, + "Version Data not found": { message: "Version Data not found" }, + "3D widget not found for the ID": { + message: "3D widget not found for the ID", + }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const widget3D_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(widget3D_Datas ? { data: widget3D_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deletewidget3DResponse, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/vizualizationController/floatWidget-Controller.ts b/src/socket-server/controllers/vizualizationController/floatWidget-Controller.ts index 06e5ef8..7baa196 100644 --- a/src/socket-server/controllers/vizualizationController/floatWidget-Controller.ts +++ b/src/socket-server/controllers/vizualizationController/floatWidget-Controller.ts @@ -20,6 +20,7 @@ export const AddFloatHandleEvent = async ( "zoneUuid", "widget", "projectId", + "versionId", "userId", "organization", ]; @@ -53,6 +54,7 @@ export const AddFloatHandleEvent = async ( "Zone not found for the zoneUuid": { message: "Zone not found for the zoneUuid", }, + "Version Data not found": { message: "Version Data not found" }, "Widget updated successfully": { message: "Widget updated successfully" }, "Failed to create FloatWidget": { message: "Failed to create FloatWidget" }, }; @@ -92,6 +94,7 @@ export const DeleteFloatHandleEvent = async ( "zoneUuid", "floatWidgetID", "projectId", + "versionId", "userId", "organization", ]; @@ -125,6 +128,7 @@ export const DeleteFloatHandleEvent = async ( "Zone not found for the zoneUuid": { message: "Zone not found for the zoneUuid", }, + "Version Data not found": { message: "Version Data not found" }, "FloatWidget not found for the Id": { message: "FloatWidget not found for the Id", }, @@ -167,6 +171,7 @@ export const DuplicateFloatHandleEvent = async ( "index", "widget", "projectId", + "versionId", "userId", "organization", ]; @@ -200,6 +205,7 @@ export const DuplicateFloatHandleEvent = async ( "Zone not found for the zoneUuid": { message: "Zone not found for the zoneUuid", }, + "Version Data not found": { message: "Version Data not found" }, "FloatWidget update unsuccessfull": { message: "FloatWidget update unsuccessfull", }, diff --git a/src/socket-server/controllers/vizualizationController/panel-Controller.ts b/src/socket-server/controllers/vizualizationController/panel-Controller.ts index 3a7945c..d4a6b9a 100644 --- a/src/socket-server/controllers/vizualizationController/panel-Controller.ts +++ b/src/socket-server/controllers/vizualizationController/panel-Controller.ts @@ -1,222 +1,299 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; -import { AddPanel, ClearPanel, DelPanel, LockedPanel } from "../../../shared/services/visualization/panelService.ts"; +import { + AddPanel, + ClearPanel, + DelPanel, + LockedPanel, +} from "../../../shared/services/visualization/panelService.ts"; export const AddPanelHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.addPanel_v1 || !data?.organization) return; - const requiredFields = ["zoneUuid", "panelOrder", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.addPanel_v1Response, response, connectedUsersByOrg) - return; - } - const result = await AddPanel(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Panels created successfully" }, - "User not found": { message: "User not found" }, - "Zone not found": { message: "Zone not found" }, - "No new panels were created. All panels already exist": { message: "No new panels were created. All panels already exist" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.addPanel_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "panelOrder", + "versionId", + "projectId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addPanel_v1Response, + response, + connectedUsersByOrg + ); + return; + } + const result = await AddPanel(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.addPanel_v1Response, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "Panels created successfully" }, + "User not found": { message: "User not found" }, + "Zone not found": { message: "Zone not found" }, + "Version Data not found": { message: "Version Data not found" }, + "No new panels were created. All panels already exist": { + message: "No new panels were created. All panels already exist", + }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addPanel_v1Response, + response, + connectedUsersByOrg + ); +}; export const DeletePanelHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.deletePanel_v1 || !data?.organization) return; - const requiredFields = ["zoneUuid", "panelName", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.deletePanel_v1Response, response, connectedUsersByOrg) - return; - } - const result = await DelPanel(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Panel deleted successfully" }, - "User not found": { message: "User not found" }, - "Zone not found": { message: "Zone not found" }, - "Panel Already Deleted": { message: "Panel Already Deleted" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.deletePanel_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "panelName", + "versionId", + "projectId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deletePanel_v1Response, + response, + connectedUsersByOrg + ); + return; + } + const result = await DelPanel(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.deletePanel_v1Response, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "Panel deleted successfully" }, + "User not found": { message: "User not found" }, + "Zone not found": { message: "Zone not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Panel Already Deleted": { message: "Panel Already Deleted" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.deletePanel_v1Response, + response, + connectedUsersByOrg + ); +}; export const ClearPanelHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.clearPanel_v1 || !data?.organization) return; - const requiredFields = ["zoneUuid", "panelName", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.clearPanel_v1Response, response, connectedUsersByOrg) - return; - } - const result = await ClearPanel(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "PanelWidgets cleared successfully" }, - "User not found": { message: "User not found" }, - "Zone not found": { message: "Zone not found" }, - "Requested Panel not found": { message: "Requested Panel not found" }, - "No widgets to clear": { message: "No widgets to clear" }, - "Failed to clear widgets in panel": { message: "Failed to clear widgets in panel" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - } - : undefined; + if (event !== EVENTS.clearPanel_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "panelName", + "projectId", + "versionId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.clearPanel_v1Response, + response, + connectedUsersByOrg + ); + return; + } + const result = await ClearPanel(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.clearPanel_v1Response, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "PanelWidgets cleared successfully" }, + "User not found": { message: "User not found" }, + "Zone not found": { message: "Zone not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Requested Panel not found": { message: "Requested Panel not found" }, + "No widgets to clear": { message: "No widgets to clear" }, + "Failed to clear widgets in panel": { + message: "Failed to clear widgets in panel", + }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.clearPanel_v1Response, + response, + connectedUsersByOrg + ); +}; export const LockedPanelHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.lockedPanel_v1 || !data?.organization) return; - const requiredFields = ["zoneUuid", "lockedPanel", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.lockedPanel_v1Response, response, connectedUsersByOrg) - return; - } - const result = await LockedPanel(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "PanelWidgets cleared successfully" }, - "User not found": { message: "User not found" }, - "Zone not found": { message: "Zone not found" }, - "locked panel not updated": { message: "locked panel not updated" }, - - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.lockedPanel_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "lockedPanel", + "versionId", + "projectId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.lockedPanel_v1Response, + response, + connectedUsersByOrg + ); + return; + } + const result = await LockedPanel(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.lockedPanel_v1Response, response, connectedUsersByOrg) -} \ No newline at end of file + const messages: Record = { + Success: { message: "PanelWidgets cleared successfully" }, + "User not found": { message: "User not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Zone not found": { message: "Zone not found" }, + "locked panel not updated": { message: "locked panel not updated" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.lockedPanel_v1Response, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/vizualizationController/template-Controller.ts b/src/socket-server/controllers/vizualizationController/template-Controller.ts index f5770fd..104b620 100644 --- a/src/socket-server/controllers/vizualizationController/template-Controller.ts +++ b/src/socket-server/controllers/vizualizationController/template-Controller.ts @@ -1,183 +1,244 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; -import { AddTemplate, AddTemplateToZone, TemplateDelete } from "../../../shared/services/visualization/templateService.ts"; +import { + AddTemplate, + AddTemplateToZone, + TemplateDelete, +} from "../../../shared/services/visualization/templateService.ts"; export const AddTemplateHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.addTemplate_v1 || !data?.organization) return; - const requiredFields = ["template", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.template_v1UpdateResponse, response, connectedUsersByOrg) - return; - } - const result = await AddTemplate(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Panels created successfully" }, - "User not found": { message: "User not found" }, - "TemplateID alreay exists": { message: "TemplateID alreay exists" }, - "Template not saved": { message: "Template not saved" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.addTemplate_v1 || !data?.organization) return; + const requiredFields = [ + "template", + "projectId", + "versionId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.template_v1UpdateResponse, + response, + connectedUsersByOrg + ); + return; + } + const result = await AddTemplate(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.template_v1UpdateResponse, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "Panels created successfully" }, + "User not found": { message: "User not found" }, + "Version Data not found": { message: "Version Data not found" }, + "TemplateID alreay exists": { message: "TemplateID alreay exists" }, + "Template not saved": { message: "Template not saved" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.template_v1UpdateResponse, + response, + connectedUsersByOrg + ); +}; export const addTemplateZoneHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.addTemplateZone_v1 || !data?.organization) return; - const requiredFields = ["template", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.addTemplateZone_v1Response, response, connectedUsersByOrg) - return; - } - const result = await AddTemplateToZone(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Template placed in Zone" }, - "User not found": { message: "User not found" }, - "Zone not found ": { message: "Zone not found " }, - "TemplateID not found": { message: "TemplateID not found" }, - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - // const templateZoneDatas = { - // template: { - // id: existingTemplate.templateID, - // name: existingTemplate.templateName, - // panelOrder: existingTemplate.panelOrder, - // widgets: existingTemplate.widgets, - // snapshot: existingTemplate.snapshot, - // floatingWidget: existingTemplate.floatWidgets, - // }, - // zoneUuid: existingZone.zoneUuid, - // zoneName: existingZone.zoneName, - // }; - } - : undefined; + if (event !== EVENTS.addTemplateZone_v1 || !data?.organization) return; + const requiredFields = [ + "template", + "projectId", + "versionId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addTemplateZone_v1Response, + response, + connectedUsersByOrg + ); + return; + } + const result = await AddTemplateToZone(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.addTemplateZone_v1Response, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "Template placed in Zone" }, + "User not found": { message: "User not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Zone not found ": { message: "Zone not found " }, + "TemplateID not found": { message: "TemplateID not found" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = + status === "Success" && result?.data + ? { + // const templateZoneDatas = { + // template: { + // id: existingTemplate.templateID, + // name: existingTemplate.templateName, + // panelOrder: existingTemplate.panelOrder, + // widgets: existingTemplate.widgets, + // snapshot: existingTemplate.snapshot, + // floatingWidget: existingTemplate.floatWidgets, + // }, + // zoneUuid: existingZone.zoneUuid, + // zoneName: existingZone.zoneName, + // }; + } + : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.addTemplateZone_v1Response, + response, + connectedUsersByOrg + ); +}; export const TemplateDeleteHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.deleteTemplate_v1 || !data?.organization) return; - const requiredFields = ["templateID", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.TemplateDelete_v1Response, response, connectedUsersByOrg) - return; - } - const result = await TemplateDelete(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Template deleted successfully" }, - "User not found": { message: "User not found" }, - "Template not Deleted": { message: "Template not Deleted" }, - - }; - - const msg = messages[status] || { message: "Internal server error" }; - const Panel_Datas = - status === "Success" && result?.data - - ? { - // widget: { - // id: result.data.widgetID, - // type: result.data.projectName, - // position: result.data.position, - // }, - // Data: result.data.Data, - // zoneUuid: result.data.zoneUuid, - } - : undefined; + if (event !== EVENTS.deleteTemplate_v1 || !data?.organization) return; + const requiredFields = [ + "templateID", + "versionId", + "projectId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(Panel_Datas ? { data: Panel_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.TemplateDelete_v1Response, + response, + connectedUsersByOrg + ); + return; + } + const result = await TemplateDelete(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.TemplateDelete_v1Response, response, connectedUsersByOrg) -} \ No newline at end of file + const messages: Record = { + Success: { message: "Template deleted successfully" }, + "User not found": { message: "User not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Template not Deleted": { message: "Template not Deleted" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const Panel_Datas = + status === "Success" && result?.data + ? { + // widget: { + // id: result.data.widgetID, + // type: result.data.projectName, + // position: result.data.position, + // }, + // Data: result.data.Data, + // zoneUuid: result.data.zoneUuid, + } + : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(Panel_Datas ? { data: Panel_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.TemplateDelete_v1Response, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/controllers/vizualizationController/widget-Controller.ts b/src/socket-server/controllers/vizualizationController/widget-Controller.ts index a805228..fe2ba6c 100644 --- a/src/socket-server/controllers/vizualizationController/widget-Controller.ts +++ b/src/socket-server/controllers/vizualizationController/widget-Controller.ts @@ -1,122 +1,166 @@ import { Socket, Server } from "socket.io"; import { EVENTS } from "../../socket/events.ts"; import { emitToSenderAndAdmins } from "../../utils/emitEventResponse.ts"; -import { AddWidget, WidgetDelete } from "../../../shared/services/visualization/widgetService.ts"; +import { + AddWidget, + WidgetDelete, +} from "../../../shared/services/visualization/widgetService.ts"; export const AddWidgetHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.addWidget_v1 || !data?.organization) return; - const requiredFields = ["zoneUuid", "widget", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.widget_v1UpdateResponse, response, connectedUsersByOrg) - return; - } - const result = await AddWidget(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Widget created successfully" }, - "User not found": { message: "User not found" }, - "Zone not found for the zoneUuid": { message: "Zone not found for the zoneUuid" }, - "panelName not found": { message: "panelName not found" }, - "Widget update unsuccessfull": { message: "Widget update unsuccessfull" }, - "Type mismatch": { message: "Type mismatch" }, - - }; - - const msg = messages[status] || { message: "Internal server error" }; - const widget_Datas = - status === "Success" && result?.data - - ? { - - } - : undefined; + if (event !== EVENTS.addWidget_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "widget", + "projectId", + "versionId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(widget_Datas ? { data: widget_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.widget_v1UpdateResponse, + response, + connectedUsersByOrg + ); + return; + } + const result = await AddWidget(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.widget_v1UpdateResponse, response, connectedUsersByOrg) -} + const messages: Record = { + Success: { message: "Widget created successfully" }, + "User not found": { message: "User not found" }, + "Zone not found for the zoneUuid": { + message: "Zone not found for the zoneUuid", + }, + "Version Data not found": { message: "Version Data not found" }, + "panelName not found": { message: "panelName not found" }, + "Widget update unsuccessfull": { message: "Widget update unsuccessfull" }, + "Type mismatch": { message: "Type mismatch" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const widget_Datas = status === "Success" && result?.data ? {} : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(widget_Datas ? { data: widget_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.widget_v1UpdateResponse, + response, + connectedUsersByOrg + ); +}; export const WidgetDeleteHandleEvent = async ( - event: string, - socket: Socket, - io: Server, - data: any, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, + event: string, + socket: Socket, + io: Server, + data: any, + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { - if (event !== EVENTS.deleteWidget_v1 || !data?.organization) return; - const requiredFields = ["zoneUuid", "widgetID", "projectId", "userId", "organization",]; - const missingFields = requiredFields.filter(field => !data?.[field]); - - if (missingFields.length > 0) { - const response = { - success: false, - message: `Missing required field(s): ${missingFields.join(", ")}`, - status: "MissingFields", - socketId: socket.id, - organization: data?.organization ?? "unknown", - }; - - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.widget_v1DeleteResponse, response, connectedUsersByOrg) - return; - } - const result = await WidgetDelete(data); - const status = typeof result?.status === "string" ? result.status : "unknown"; - - const messages: Record = { - Success: { message: "Widget deleted successfully" }, - "User not found": { message: "User not found" }, - "Zone not found for the zoneUuid": { message: "Zone not found for the zoneUuid" }, - "Widget not found": { message: "Widget not found" }, - - }; - - const msg = messages[status] || { message: "Internal server error" }; - const widget_Datas = - status === "Success" && result?.data - - ? { - // widget: { - // id: result.data.widgetID, - // type: result.data.projectName, - // position: result.data.position, - // }, - // Data: result.data.Data, - // zoneUuid: result.data.zoneUuid, - } - : undefined; + if (event !== EVENTS.deleteWidget_v1 || !data?.organization) return; + const requiredFields = [ + "zoneUuid", + "widgetID", + "projectId", + "versionId", + "userId", + "organization", + ]; + const missingFields = requiredFields.filter((field) => !data?.[field]); + if (missingFields.length > 0) { const response = { - success: status === "Success", - message: msg.message, - status, - socketId: socket.id, - organization: data.organization, - ...(widget_Datas ? { data: widget_Datas } : {}), + success: false, + message: `Missing required field(s): ${missingFields.join(", ")}`, + status: "MissingFields", + socketId: socket.id, + organization: data?.organization ?? "unknown", }; + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.widget_v1DeleteResponse, + response, + connectedUsersByOrg + ); + return; + } + const result = await WidgetDelete(data); + const status = typeof result?.status === "string" ? result.status : "unknown"; - emitToSenderAndAdmins(io, socket, data.organization, EVENTS.widget_v1DeleteResponse, response, connectedUsersByOrg) -} \ No newline at end of file + const messages: Record = { + Success: { message: "Widget deleted successfully" }, + "User not found": { message: "User not found" }, + "Version Data not found": { message: "Version Data not found" }, + "Zone not found for the zoneUuid": { + message: "Zone not found for the zoneUuid", + }, + "Widget not found": { message: "Widget not found" }, + }; + + const msg = messages[status] || { message: "Internal server error" }; + const widget_Datas = + status === "Success" && result?.data + ? { + // widget: { + // id: result.data.widgetID, + // type: result.data.projectName, + // position: result.data.position, + // }, + // Data: result.data.Data, + // zoneUuid: result.data.zoneUuid, + } + : undefined; + + const response = { + success: status === "Success", + message: msg.message, + status, + socketId: socket.id, + organization: data.organization, + ...(widget_Datas ? { data: widget_Datas } : {}), + }; + + emitToSenderAndAdmins( + io, + socket, + data.organization, + EVENTS.widget_v1DeleteResponse, + response, + connectedUsersByOrg + ); +}; diff --git a/src/socket-server/manager/manager.ts b/src/socket-server/manager/manager.ts index 4314ac5..4f2f815 100644 --- a/src/socket-server/manager/manager.ts +++ b/src/socket-server/manager/manager.ts @@ -8,6 +8,7 @@ import { createThreadHandleEvent, deleteCommentHandleEvent, deleteThreadHandleEvent, + threadUpdateHandleEvent, } from "../controllers/thread/threadController.ts"; import { DuplicateProjectHandleEvent, @@ -74,6 +75,11 @@ import { productDataDeleteHandleEvent, productRenameHandleEvent, } from "../controllers/simulationController/product-Controller.ts"; +import { + CreateLineHandleEventYjs, + DeleteLineHandleEventYjs, + UpdateLineHandleEventYjs, +} from "../controllers/collaborative/lineController-collab.ts"; interface UserSocketInfo { socketId: string; @@ -90,14 +96,15 @@ export const SocketServer = (io: Server) => { Builder_v1: io.of("/Builder_v1"), visualization_v1: io.of("/Visualization_v1"), simulation_v1: io.of("/Simulation_v1"), + BuilderYjs_v1: io.of("/BuilderYjs_v1"), }; const onlineUsers: { [organization: string]: Set } = {}; const handleNamespace = (namespace: any, ...eventHandlers: Function[]) => { namespace.use(async (socket: Socket, next: any) => { - const token = socket.handshake.auth.token; - + const token = socket.handshake.auth.token as string; + // const token = socket.handshake.query.token as string; const jwt_secret = process.env.JWT_SECRET as string; if (!token) { @@ -164,6 +171,27 @@ export const SocketServer = (io: Server) => { console.warn(`❌ Cannot store user. Missing data:`); } + //........ + // // ✅ Join organization and admin room + // if (organization) socket.join(organization); + // const role = await getUserRole(userId, organization); + // if (role === "Admin") socket.join(`${organization}_admins`); + + // // ✅ Room-based logic (MUST DO) + // if (projectId && versionId) { + // const projectRoom = `${projectId}-${versionId}`; + // socket.join(projectRoom); + // console.log(`✅ User ${userId} joined room: ${projectRoom}`); + // } + + // // ✅ Track connected user + // if (organization && userId && role) { + // if (!connectedUsersByOrg[organization]) connectedUsersByOrg[organization] = []; + // connectedUsersByOrg[organization].push({ socketId: socket.id, userId, role }); + // } else { + // console.warn(`❌ Cannot store user. Missing data:`); + // } + socket.onAny((event: string, data: any, callback: any) => { eventHandlers.forEach((handler) => handler(event, socket, io, data, connectedUsersByOrg, callback) @@ -185,12 +213,19 @@ export const SocketServer = (io: Server) => { }; handleNamespace(namespaces.dashboard); + handleNamespace( + namespaces.BuilderYjs_v1, + CreateLineHandleEventYjs, + UpdateLineHandleEventYjs, + DeleteLineHandleEventYjs + ); handleNamespace( namespaces.thread, createThreadHandleEvent, deleteThreadHandleEvent, addCommentHandleEvent, - deleteCommentHandleEvent + deleteCommentHandleEvent, + threadUpdateHandleEvent ); handleNamespace( diff --git a/src/socket-server/services/lines/zone-controller.ts b/src/socket-server/services/lines/zone-controller.ts index 083d4dd..6922e9e 100644 --- a/src/socket-server/services/lines/zone-controller.ts +++ b/src/socket-server/services/lines/zone-controller.ts @@ -6,7 +6,6 @@ import templateModel from "../../../shared/model/vizualization/templatemodel.ts" import widgetModel from "../../../shared/model/vizualization/widgemodel.ts"; export const setZone = async (data: any) => { const { organization, userId, zoneData } = data; - console.log("data service: ", data); try { const zoneId = zoneData.zoneId; const points = zoneData.points; diff --git a/src/socket-server/socket/events.ts b/src/socket-server/socket/events.ts index 21b6bda..a891d79 100644 --- a/src/socket-server/socket/events.ts +++ b/src/socket-server/socket/events.ts @@ -100,10 +100,12 @@ export const EVENTS = { ThreadCreateResponse: "v1-thread:response:create", deleteThread: "v1:thread:delete", deleteThreadResponse: "v1-thread:response:delete", - addComment: "v1-Comment:response:add", + addComment: "v1-Comment:add", addCommentResponse: "v1-Comment:response:add", - deleteComment: "v1-Comment:response:delete", + deleteComment: "v1-Comment:delete", deleteCommentResponse: "v1-Comment:response:delete", + updateThreat: "v1:thread:updateTitle", + updateThreatResponse: "v1-thread:response:updateTitle", addWidget3D: "v1:viz-3D-widget:add", addWidget3DResponse: "v1:viz-widget3D:response:add", @@ -191,4 +193,14 @@ export const EVENTS = { Product_v1DeleteResponse: "v1:model-product:response:delete", deleteEvent_v1ProductModel: "v1:model-productevent:delete", ProductEvent_v1DeleteResponse: "v1:model-productevent:response:delete", + + + +//COLLAB + createLineYjs_v1: "v1:Line-collab:create", + createLineYjs_v1Response: "v1:Line-collab:response:create", + updateLineYjs_v1: "v1:Line-collab:update", + updateLineYjs_v1Response: "v1:Line-collab:response:update", + deleteLineYjs_v1: "v1:Line-collab:delete", + deleteLineYjs_v1Response: "v1:Line-collab:response:delete", }; diff --git a/src/socket-server/socket/socketManager.ts b/src/socket-server/socket/socketManager.ts index a8a8e72..5dc6247 100644 --- a/src/socket-server/socket/socketManager.ts +++ b/src/socket-server/socket/socketManager.ts @@ -962,6 +962,7 @@ export const initSocketServer = (io: Server) => { namespace._handlersRegistered = true; namespace.use((socket: Socket, next: (err?: Error) => void) => { const token = socket.handshake.auth.token; + console.log('token: ', token); if (!token) { console.log("No token provided"); diff --git a/src/socket-server/utils/emitEventResponse.ts b/src/socket-server/utils/emitEventResponse.ts index 742338b..7763a64 100644 --- a/src/socket-server/utils/emitEventResponse.ts +++ b/src/socket-server/utils/emitEventResponse.ts @@ -1,4 +1,4 @@ -import { Socket,Server } from "socket.io"; +import { Socket, Server } from "socket.io"; interface EmitOptions { success: boolean; @@ -10,14 +10,12 @@ interface EmitOptions { status?: string; } - export const emitEventResponse = ( socket: Socket, organization: string, event: string, result: EmitOptions ) => { - console.log('event: ', event); if (!organization) { console.log(`Organization missing in response for event: ${event}`); return; @@ -26,23 +24,24 @@ export const emitEventResponse = ( socket.to(organization).emit(event, { // success: result.success, message: result.message, - data: result.data , + data: result.data, error: result.error, socketId: result.socketId, organization, }); }; - - -export const emitToSenderAndAdmins = ( +export const emitToSenderAndAdmins = ( io: Server, socket: Socket, organization: string, event: string, result: EmitOptions, - connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] } + connectedUsersByOrg: { + [org: string]: { socketId: string; userId: string; role: string }[]; + } ) => { + socket.emit(event, { message: result.message, data: result.data, @@ -50,12 +49,27 @@ export const emitToSenderAndAdmins = ( socketId: result.socketId, organization, }); - socket.to(`${organization}_admins`).emit(event, { + socket.to(`${organization}_admins`).emit(event, { message: result.message, data: result.data, error: result.error, socketId: result.socketId, organization, }); - }; +export const emitToRoom = ( + io: Server, + room: string, + event: string, + result: EmitOptions +) => { + const payload = { + message: result.message, + data: result.data, + error: result.error, + socketId: result.socketId, + organization: result.organization, + }; + + io.to(room).emit(event, payload); +}; \ No newline at end of file diff --git a/src/socket-server/utils/room.ts b/src/socket-server/utils/room.ts new file mode 100644 index 0000000..6a87645 --- /dev/null +++ b/src/socket-server/utils/room.ts @@ -0,0 +1,29 @@ +import { Socket } from "socket.io"; + +interface JoinRoomInput { + projectId: string; + versionId: string; + userId: string; + organization: string; +} +interface LeaveRoomInput { + projectId: string; + versionId: string; + userId: string; +} +export const joinRoom = (socket: Socket, data: JoinRoomInput): string => { + const { projectId, versionId } = data; + const room = `${projectId}-${versionId}`; + socket.join(room); + console.log(`✅ ${data.userId} joined room: ${room}`); + return room; +}; + + +export const leaveRoom = (socket: Socket, data: LeaveRoomInput): string => { + const { projectId, versionId, userId } = data; + const room = `${projectId}-${versionId}`; + socket.leave(room); + console.log(`🚪 ${userId} left room: ${room}`); + return room; +}; \ No newline at end of file diff --git a/src/socket-server/utils/socketfunctionHelpers.ts b/src/socket-server/utils/socketfunctionHelpers.ts index 2cfdfff..fd61c91 100644 --- a/src/socket-server/utils/socketfunctionHelpers.ts +++ b/src/socket-server/utils/socketfunctionHelpers.ts @@ -29,12 +29,13 @@ export const FinalResponse = ( data?: any ) => { const msg = messages[status] || { message: "Internal server error" }; - return { - success: status === "Success", + const includeData = (status === "Success" || status === "updated") && data; + return { + success: status === "Success" || status === "updated", message: msg.message, status, socketId: socket.id, organization, - ...(status === "Success" && data ? { data } : {}), +...(includeData ? { data } : {}), }; }; diff --git a/src/socket-server/utils/yjs/attachLineObserver.ts b/src/socket-server/utils/yjs/attachLineObserver.ts new file mode 100644 index 0000000..aaa0bc7 --- /dev/null +++ b/src/socket-server/utils/yjs/attachLineObserver.ts @@ -0,0 +1,41 @@ +import * as Y from "yjs"; +import { Server } from "socket.io"; +import { emitToRoom } from "../emitEventResponse.ts"; + +const observerAttached = new Set(); + +export const attachLineObserver = ( + ydoc: Y.Doc, + versionId: string, + projectId: string, + organization: string, + io: Server +) => { + const key = `${projectId}-${versionId}`; + if (observerAttached.has(key)) return; + + const lineMap = ydoc.getMap("lines"); + + lineMap.observe((event) => { + console.log(`[Yjs] ${key} updated`); + event.changes.keys.forEach((change, keyName) => { + const line = lineMap.get(keyName); + const lineJSON = line instanceof Y.Map ? line.toJSON() : line; + + const payload = { + success: true, + message: `${change.action} line`, + data: { id: keyName, line: lineJSON, type: change.action }, + organization: projectId, + socketId: "", + error: null, + }; + + emitToRoom(io, key, `line:${change.action}`, payload); + }); + + }); + + + observerAttached.add(key); +}; diff --git a/src/socket-server/utils/yjs/yjsRoomjoin.ts b/src/socket-server/utils/yjs/yjsRoomjoin.ts new file mode 100644 index 0000000..f102ee4 --- /dev/null +++ b/src/socket-server/utils/yjs/yjsRoomjoin.ts @@ -0,0 +1,119 @@ +import * as Y from "yjs"; +import autoSaveModel from "../../../shared/V1Models/yjs/auto-saveModel.ts"; + +export const yDocStore = new Map(); +export const observerAttached = new Set(); + +export const getYDoc = async ( + projectId: string, + versionId: string, + organization: string +): Promise => { + const key = `${projectId}-${versionId}`; + + if (!yDocStore.has(key)) { + const doc = new Y.Doc(); + const Model = autoSaveModel(organization); + const existing = await Model.findOne({ projectId, versionId }); + + if (existing?.yjsData) { + try { + // ✅ use applyUpdateV2 + Y.applyUpdateV2(doc, new Uint8Array(existing.yjsData.buffer)); + console.log("🔁 Y.Doc restored from DB for:", key); + } catch (err: any) { + console.error("❌ Failed to apply Yjs update:", err.message); + } + } else { + doc.getMap("lines"); // make sure map is created + } + + yDocStore.set(key, doc); + } + + const ydoc = yDocStore.get(key)!; + + if (!observerAttached.has(key)) { + ydoc.on("update", async () => { + try { + // ✅ use encodeStateAsUpdateV2 + const updateBuffer = Buffer.from(Y.encodeStateAsUpdateV2(ydoc)); + const Model = autoSaveModel(organization); + + await Model.findOneAndUpdate( + { projectId, versionId }, + { + yjsData: updateBuffer, + updatedAt: new Date(), + }, + { upsert: true } + ); + + console.log(`💾 Auto-saved Y.Doc to DB for: ${key}`); + } catch (err: any) { + console.error("❌ Auto-save failed:", err.message); + } + }); + + observerAttached.add(key); + } + + return ydoc; +}; + + + + + +// import * as Y from "yjs"; + +// const yDocStore: Map = new Map(); +// const observerAttached: Set = new Set(); // prevent multiple observer + +// export const getYDoc = (projectId: string, versionId: string): Y.Doc => { +// const key = `${projectId}-${versionId}`; + +// if (!yDocStore.has(key)) { +// const doc = new Y.Doc(); +// yDocStore.set(key, doc); +// } + +// const ydoc = yDocStore.get(key)!; + +// // // ❗ Only one observer per room/doc +// if (!observerAttached.has(key)) { +// const lineMap = ydoc.getMap("lines"); + +// lineMap.observe((event) => { +// console.log(`🔍 ${key} - lineMap updated`); + +// event.changes.keys.forEach((change, keyName) => { +// console.log(`👉 key: ${keyName}, action: ${change.action}`); + +// if (change.action === "add") { +// const line = lineMap.get(keyName); +// const lineJSON = line instanceof Y.Map ? line.toJSON() : line; +// console.log("🟢 New line added:", lineJSON); +// } + +// if (change.action === "update") { +// const line = lineMap.get(keyName); +// const lineJSON = line instanceof Y.Map ? line.toJSON() : line; +// console.log("🟡 Line updated:", lineJSON); +// } + +// if (change.action === "delete") { +// console.log("🔴 Line deleted:", keyName); +// } +// }); +// }); + + + +// observerAttached.add(key); +// console.log(`✅ Observer attached for ${key}`); +// } + +// return ydoc; +// }; +// getYDoc.ts \ No newline at end of file diff --git a/src/socket-server/utils/yjs/yjsStore.ts b/src/socket-server/utils/yjs/yjsStore.ts new file mode 100644 index 0000000..2db798b --- /dev/null +++ b/src/socket-server/utils/yjs/yjsStore.ts @@ -0,0 +1,6 @@ +import * as Y from "yjs"; + +const ydoc = new Y.Doc(); +const lineMap = ydoc.getMap("lines"); + +export { ydoc, lineMap };