From ca8e8b66f475accfb80f37bf916ae0d78072e5d3 Mon Sep 17 00:00:00 2001 From: Nivetharamesh99 Date: Sat, 10 May 2025 11:02:42 +0530 Subject: [PATCH 1/7] Update ProductId validation to eventData --- src/api-server/controller/simulation/productService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api-server/controller/simulation/productService.ts b/src/api-server/controller/simulation/productService.ts index f213e81..d360ff3 100644 --- a/src/api-server/controller/simulation/productService.ts +++ b/src/api-server/controller/simulation/productService.ts @@ -26,6 +26,7 @@ export class productFlowservice { const updateEventData = await EventsDataModel(organization).findOneAndUpdate( { modelUuid: eventDatas.modelUuid, + productId: productId, isArchive: false, } , { From af8510ad9047ef1196c42381d38f55fc420ae64a Mon Sep 17 00:00:00 2001 From: sabarinathan Date: Wed, 14 May 2025 12:41:27 +0530 Subject: [PATCH 2/7] project create socket --- .../controllers/project/projectController.ts | 51 +++++++++++++++++++ src/socket-server/socket/events.ts | 4 ++ src/socket-server/socket/socketManager.ts | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/socket-server/controllers/project/projectController.ts diff --git a/src/socket-server/controllers/project/projectController.ts b/src/socket-server/controllers/project/projectController.ts new file mode 100644 index 0000000..38a07e7 --- /dev/null +++ b/src/socket-server/controllers/project/projectController.ts @@ -0,0 +1,51 @@ +import { Socket } from "socket.io"; +import { createProject } from "../../../shared/services/project/project-Serivices.ts"; +import { EVENTS } from "../../socket/events.ts"; +import { emitEventResponse } from "../../socket/socketManager.ts"; + +export const projectHandleEvent = async ( + event: string, + socket: Socket, + data: any, + namespace: any +) => { + if (!data?.organization) { + console.warn(`Missing organization in event: ${event}`); + return; + } + + let result; + + switch (event) { + case EVENTS.addProject: { + result = await createProject(data); + + // Create response object + const response = { + success: result.status === "success", + message: + result.status === "project_exists" + ? "Project already exists" + : result.status === "user_not_found" + ? "User not found" + : result.status === "invalid_user_id" + ? "Invalid User ID" + : result.status === "success" + ? "Project created successfully" + : "Something went wrong", + data: result.project || null, + status: result.status, + socketId: socket.id, + organization: data.organization, + }; + + // Emit response to the organization room + emitEventResponse(socket, data.organization, EVENTS.projectResponse, response); + + break; + } + + default: + console.warn(`Unknown project event: ${event}`); + } +}; diff --git a/src/socket-server/socket/events.ts b/src/socket-server/socket/events.ts index 307f0fd..1fee1b1 100644 --- a/src/socket-server/socket/events.ts +++ b/src/socket-server/socket/events.ts @@ -98,4 +98,8 @@ export const EVENTS = { update3dPositionResponse:"viz-widget3D:response:modifyPositionRotation", delete3DWidget:"v2:viz-3D-widget:delete", widget3DDeleteResponse:"viz-widget3D:response:delete", + + //PROJECT + addProject:"v1:project:add", + projectResponse:"v1-project:response:update:", } \ No newline at end of file diff --git a/src/socket-server/socket/socketManager.ts b/src/socket-server/socket/socketManager.ts index f921753..2d25eec 100644 --- a/src/socket-server/socket/socketManager.ts +++ b/src/socket-server/socket/socketManager.ts @@ -1050,7 +1050,7 @@ try { } } -const emitEventResponse = (socket: Socket, organization: string, event: string, result: any) => { +export const emitEventResponse = (socket: Socket, organization: string, event: string, result: any) => { if (organization) { socket.to(organization).emit(event, { success: result.success, From e2be6deb0ad653bee6e3082865ec854112b5e235 Mon Sep 17 00:00:00 2001 From: Nivetharamesh Date: Wed, 14 May 2025 14:29:14 +0530 Subject: [PATCH 3/7] projectData and version model added --- .env | 16 +- package-lock.json | 495 +++++++++++++++++- package.json | 1 + .../controller/project/projectController.ts | 25 +- src/shared/connect/mongoose.ts | 9 +- src/shared/model/project/project-model.ts | 40 +- src/shared/model/version/versionModel.ts | 27 + .../services/project/project-Serivices.ts | 80 --- .../services/project/project-Services.ts | 135 +++++ .../controllers/project/projectController.ts | 5 +- src/socket-server/socket/socketManager.ts | 2 +- 11 files changed, 699 insertions(+), 136 deletions(-) create mode 100644 src/shared/model/version/versionModel.ts delete mode 100644 src/shared/services/project/project-Serivices.ts create mode 100644 src/shared/services/project/project-Services.ts diff --git a/.env b/.env index 69561f1..dab6736 100644 --- a/.env +++ b/.env @@ -1,13 +1,13 @@ -# MONGO_URI=mongodb://192.168.0.110/ -# MONGO_USER=mydata -# MONGO_PASSWORD=mongodb@hexr2002 -# MONGO_AUTH_DB=admin - -MONGO_URI=mongodb://mongo/ -MONGO_USER=admin -MONGO_PASSWORD=admin321 +MONGO_URI=mongodb://192.168.0.110/ +MONGO_USER=mydata +MONGO_PASSWORD=mongodb@hexr2002 MONGO_AUTH_DB=admin +# MONGO_URI=mongodb://mongo/ +# MONGO_USER=admin +# MONGO_PASSWORD=admin321 +# MONGO_AUTH_DB=admin + API_PORT=5000 SOCKET_PORT=8000 NODE_ENV=development diff --git a/package-lock.json b/package-lock.json index a9e0e96..3e98cae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "http": "^0.0.1-security", "ip": "^2.0.1", "jsonwebtoken": "^9.0.2", + "minio": "^8.0.5", "mongoose": "^8.8.1", "socket.io": "^4.8.1", "swagger-autogen": "^2.23.7", @@ -276,6 +277,12 @@ "@types/webidl-conversions": "*" } }, + "node_modules/@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -336,6 +343,25 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -370,6 +396,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/block-stream2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz", + "integrity": "sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -414,6 +448,11 @@ "node": ">=8" } }, + "node_modules/browser-or-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", + "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" + }, "node_modules/bson": { "version": "6.10.1", "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", @@ -422,6 +461,14 @@ "node": ">=16.20.1" } }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -435,10 +482,27 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -448,12 +512,12 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -549,6 +613,14 @@ "ms": "2.0.0" } }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -557,6 +629,22 @@ "node": ">=0.10.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -724,6 +812,11 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, "node_modules/express": { "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", @@ -769,6 +862,23 @@ "url": "https://opencollective.com/express" } }, + "node_modules/fast-xml-parser": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^1.1.1" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -781,6 +891,14 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/finalhandler": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", @@ -798,6 +916,20 @@ "node": ">= 0.8" } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -833,16 +965,16 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -919,6 +1051,17 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -930,6 +1073,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1006,6 +1163,21 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1018,6 +1190,17 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1027,6 +1210,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1048,6 +1248,37 @@ "node": ">=0.12.0" } }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1112,6 +1343,11 @@ "node": ">=12.0.0" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -1231,6 +1467,38 @@ "node": "*" } }, + "node_modules/minio": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.5.tgz", + "integrity": "sha512-/vAze1uyrK2R/DSkVutE4cjVoAowvIQ18RAwn7HrqnLecLlMazFnY0oNBqfuoAWvu7mZIGX75AzpuV05TJeoHg==", + "dependencies": { + "async": "^3.2.4", + "block-stream2": "^2.1.0", + "browser-or-node": "^2.1.1", + "buffer-crc32": "^1.0.0", + "eventemitter3": "^5.0.1", + "fast-xml-parser": "^4.4.1", + "ipaddr.js": "^2.0.1", + "lodash": "^4.17.21", + "mime-types": "^2.1.35", + "query-string": "^7.1.3", + "stream-json": "^1.8.0", + "through2": "^4.0.2", + "web-encoding": "^1.1.5", + "xml2js": "^0.5.0 || ^0.6.2" + }, + "engines": { + "node": "^16 || ^18 || >=20" + } + }, + "node_modules/minio/node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "engines": { + "node": ">= 10" + } + }, "node_modules/mongodb": { "version": "6.12.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.12.0.tgz", @@ -1495,6 +1763,14 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1535,6 +1811,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1557,6 +1850,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1588,11 +1894,32 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -1654,6 +1981,22 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -1853,6 +2196,14 @@ "memory-pager": "^1.0.2" } }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "engines": { + "node": ">=6" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1861,6 +2212,46 @@ "node": ">= 0.8" } }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1917,6 +2308,14 @@ "express": ">=4.0.0 || >=5.0.0-beta" } }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2044,6 +2443,23 @@ "node": ">= 0.8" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2066,6 +2482,17 @@ "node": ">= 0.8" } }, + "node_modules/web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "dependencies": { + "util": "^0.12.3" + }, + "optionalDependencies": { + "@zxing/text-encoding": "0.9.0" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -2086,6 +2513,26 @@ "node": ">=18" } }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2111,6 +2558,26 @@ } } }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "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 e5682e4..2387750 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "http": "^0.0.1-security", "ip": "^2.0.1", "jsonwebtoken": "^9.0.2", + "minio": "^8.0.5", "mongoose": "^8.8.1", "socket.io": "^4.8.1", "swagger-autogen": "^2.23.7", diff --git a/src/api-server/controller/project/projectController.ts b/src/api-server/controller/project/projectController.ts index fd34a70..0d4b8cc 100644 --- a/src/api-server/controller/project/projectController.ts +++ b/src/api-server/controller/project/projectController.ts @@ -1,46 +1,47 @@ import { Request, Response } from "express"; -import { createProject } from "../../../shared/services/project/project-Serivices.ts"; +import { createProject } from "../../../shared/services/project/project-Services.ts"; -export const createProjectController = async (req: Request, res: Response): Promise => { +export const createProjectController = async ( + req: Request, + res: Response +): Promise => { try { const result = await createProject(req.body); - console.log("result:", result); + console.log("result: ", result); switch (result.status) { case "project_exists": res.status(409).json({ - success: false, message: "Project already exists", }); break; case "user_not_found": res.status(404).json({ - success: false, message: "User not found", }); break; case "success": res.status(201).json({ - success: true, message: "Project created successfully", - data: result.project, + projectId: result.project._id, + }); + break; + case "All fields are required": + res.status(400).json({ + message: "All fields are required", }); break; - default: res.status(500).json({ - success: false, message: "Internal server error", }); break; } } catch (error) { - console.error("Error in controller:", error); res.status(500).json({ - success: false, - message: "Internal server error", + message: "Unknown error", }); } }; diff --git a/src/shared/connect/mongoose.ts b/src/shared/connect/mongoose.ts index ead358d..6548369 100644 --- a/src/shared/connect/mongoose.ts +++ b/src/shared/connect/mongoose.ts @@ -1,5 +1,5 @@ import mongoose, { Schema, Connection, Model } from "mongoose"; - +import { Client } from "minio"; interface ConnectionCache { [key: string]: Connection; } @@ -49,5 +49,12 @@ const MainModel = ( throw error; } }; +export const minioClient = new Client({ + endPoint: "185.100.212.76", // MinIO server IP or hostname + port: 9999, // MinIO server port + useSSL: false, // Set to true if SSL is configured + accessKey: "sabarinathan", // Access key + secretKey: "sabarinathan", +}); export default MainModel; diff --git a/src/shared/model/project/project-model.ts b/src/shared/model/project/project-model.ts index 634ef57..504ad3d 100644 --- a/src/shared/model/project/project-model.ts +++ b/src/shared/model/project/project-model.ts @@ -1,29 +1,35 @@ -import { Schema, Document, Types } from "mongoose"; +import { Schema, Document } from "mongoose"; import MainModel from "../../connect/mongoose.ts"; -import {User} from "../user-Model.ts"; +import { User } from "../user-Model.ts"; export interface Project extends Document { - projectUuid: string; - projectName: string; - createdBy: User["_id"]; - isArchive: boolean - thumbnail: string - sharedUsers: [] - + projectUuid: string; + projectName: string; + createdBy: User["_id"]; + isArchive: boolean; + thumbnail: string; + sharedUsers: []; + DeletedAt: Date; + total_versions: string; + Present_version: string; } -const projectSchema:Schema = new Schema({ +const projectSchema: Schema = new Schema( + { projectUuid: { type: String, required: true }, projectName: { type: String }, thumbnail: { type: String }, - isArchive: { type: Boolean,default:false }, + isArchive: { type: Boolean, default: false }, createdBy: { type: Schema.Types.ObjectId, ref: "user" }, - sharedUsers: [{ type: Schema.Types.ObjectId, ref: "user" }], - - -}, { timestamps: true }) + sharedUsers: [{ type: Schema.Types.ObjectId, ref: "user" }], + DeletedAt: { type: Date, default: null }, + total_versions: { type: String }, + Present_version: { type: String }, + }, + { timestamps: true } +); const projectModel = (db: string) => { - return MainModel(db, "Projects", projectSchema, "Projects"); + return MainModel(db, "Projects", projectSchema, "Projects"); }; -export default projectModel; \ No newline at end of file +export default projectModel; diff --git a/src/shared/model/version/versionModel.ts b/src/shared/model/version/versionModel.ts new file mode 100644 index 0000000..0ab23f8 --- /dev/null +++ b/src/shared/model/version/versionModel.ts @@ -0,0 +1,27 @@ +import { Schema, Document } from "mongoose"; +import MainModel from "../../connect/mongoose.ts"; +import { Project } from "../project/project-model.ts"; +import { User } from "../user-Model.ts"; +export interface Version extends Document { + versionName: string; + projectId: Project["_id"]; + createdBy: User["_id"]; + isArchive: boolean; + version: number; +} +const versionSchema: Schema = new Schema( + { + versionName: { type: String }, + version: { type: Number }, + isArchive: { type: Boolean, default: false }, + projectId: { type: Schema.Types.ObjectId, ref: "project" }, + createdBy: { type: Schema.Types.ObjectId, ref: "user" }, + }, + { timestamps: true } +); + +const versionModel = (db: string) => { + return MainModel(db, "Versions", versionSchema, "Versions"); +}; + +export default versionModel; diff --git a/src/shared/services/project/project-Serivices.ts b/src/shared/services/project/project-Serivices.ts deleted file mode 100644 index 3b67a0e..0000000 --- a/src/shared/services/project/project-Serivices.ts +++ /dev/null @@ -1,80 +0,0 @@ -import projectModel from "../../model/project/project-model.ts"; -import userModel from "../../model/user-Model.ts"; -import { Types } from 'mongoose'; -interface CreateProjectInput { - projectName: string; - projectUuid: string; - createdBy: string; // user ID - thumbnail?: string; - sharedUsers?: string[]; - organization:string -} - -export const createProject = async (data: CreateProjectInput) => { - console.log('data: ', data); - try { - const{projectName,projectUuid,createdBy,thumbnail,sharedUsers,organization}=data - console.log('createdBy: ', typeof createdBy); - const userExisting =await existingUser(createdBy,organization) - if (!userExisting) - { - return { - status: "user_not_found", - }; - - } - const projectExisting = await existingProject(projectUuid, organization); - console.log('projectExisting: ', projectExisting); - - if (projectExisting) { - return { - status: "project_exists", - project: projectExisting, - }; - } - - const project = await projectModel(organization).create({ - projectName: projectName, - projectUuid: projectUuid, - createdBy: createdBy, - thumbnail: thumbnail || "", - sharedUsers: sharedUsers || [], - isArchive: false, - }); - return { - status: "success", - project: project, - }; - } catch (error) { - console.log('error: ', error); - return { - exists: false, - }; - } - -}; - -export const existingProject = async (projectUuid: string,organization:string) => { - console.log("projectUuid",typeof projectUuid); - const projectData= await projectModel(organization).findOne({projectUuid:projectUuid,isArchive:false}) - console.log('projectData: ', projectData); - return projectData -}; - -export const existingUser = async (createdBy: string, organization: string) => { - console.log('createdBy: ', typeof createdBy); - if (!Types.ObjectId.isValid(createdBy)) { - console.log('Invalid ObjectId format'); - return null; - } - const userData = await userModel(organization).findOne({ - _id: createdBy, - }); - console.log('userData:', userData); - return userData; // ✅ Make sure you return it - }; - - -export const archiveProject = async (projectId: string,organization:string) => { - return await projectModel(organization).findByIdAndUpdate(projectId, { isArchive: true }, { new: true }); -}; diff --git a/src/shared/services/project/project-Services.ts b/src/shared/services/project/project-Services.ts new file mode 100644 index 0000000..21975f9 --- /dev/null +++ b/src/shared/services/project/project-Services.ts @@ -0,0 +1,135 @@ +import projectModel from "../../model/project/project-model.ts"; +import userModel from "../../model/user-Model.ts"; +import { Types } from "mongoose"; +import versionModel from "../../model/version/versionModel.ts"; +interface CreateProjectInput { + projectName: string; + projectUuid: string; + userId: string; // user ID + thumbnail?: string; + sharedUsers?: string[]; + organization: string; +} + +export const createProject = async (data: CreateProjectInput) => { + try { + const { + projectName, + projectUuid, + userId, + thumbnail, + sharedUsers, + organization, + } = data; + if ( + !projectName || + !projectUuid || + !userId || + !thumbnail || + // !sharedUsers || + !organization + ) + return { status: "All fields are required" }; + const userExisting = await existingUser(userId, organization); + if (!userExisting) { + return { + status: "user_not_found", + }; + } + const projectExisting = await existingProject(projectUuid, organization); + + if (projectExisting) { + return { + status: "project_exists", + project: projectExisting, + }; + } + + const project = await projectModel(organization).create({ + projectName: projectName, + projectUuid: projectUuid, + createdBy: userId, + thumbnail: thumbnail || "", + sharedUsers: sharedUsers || [], + isArchive: false, + }); + const versionData = previousVersion(project._id, organization); + if (!versionData) { + await versionModel(organization).create({ + projectId: project._id, + createdBy: userId, + version: 0.01, + }); + } + return { + status: "success", + project: project, + }; + } catch (error) { + console.log('error: ', error); + return { + status: error, + }; + } +}; + +export const GetAllProjects = async (data: CreateProjectInput) => { + try { + const { userId, organization } = data; + await existingUser(userId, organization); + if (!existingUser) return { status: "User not found" }; + const projectDatas = await projectModel(organization) + .find({ + isArchive: false, + }) + .select("_id projectName createdBy thumbnail"); + if (projectDatas) return { Datas: projectDatas }; + } catch (error: unknown) { + return { status: error }; + } +}; + +export const existingProject = async ( + projectUuid: string, + organization: string +) => { + const projectData = await projectModel(organization).findOne({ + projectUuid: projectUuid, + isArchive: false, + }); + return projectData; +}; + +export const existingUser = async (userId: string, organization: string) => { + if (!Types.ObjectId.isValid(userId)) { + console.log("Invalid ObjectId format"); + return null; + } + const userData = await userModel(organization).findOne({ + _id: userId, + }); + return userData; // ✅ Make sure you return it +}; + +export const archiveProject = async ( + projectId: string, + organization: string +) => { + return await projectModel(organization).findByIdAndUpdate( + projectId, + { isArchive: true }, + { new: true } + ); +}; +export const previousVersion = async ( + projectId: string, + organization: string +): Promise => { + const result = await versionModel(organization) + .findOne({ + projectId: projectId, + isArchive: false, + }) + .sort({ version: -1 }); + return result; +}; diff --git a/src/socket-server/controllers/project/projectController.ts b/src/socket-server/controllers/project/projectController.ts index 38a07e7..b046cf1 100644 --- a/src/socket-server/controllers/project/projectController.ts +++ b/src/socket-server/controllers/project/projectController.ts @@ -1,7 +1,6 @@ import { Socket } from "socket.io"; -import { createProject } from "../../../shared/services/project/project-Serivices.ts"; +import { createProject } from "../../../shared/services/project/project-Services.ts"; import { EVENTS } from "../../socket/events.ts"; -import { emitEventResponse } from "../../socket/socketManager.ts"; export const projectHandleEvent = async ( event: string, @@ -40,7 +39,7 @@ export const projectHandleEvent = async ( }; // Emit response to the organization room - emitEventResponse(socket, data.organization, EVENTS.projectResponse, response); + break; } diff --git a/src/socket-server/socket/socketManager.ts b/src/socket-server/socket/socketManager.ts index 2d25eec..0581e2f 100644 --- a/src/socket-server/socket/socketManager.ts +++ b/src/socket-server/socket/socketManager.ts @@ -1050,7 +1050,7 @@ try { } } -export const emitEventResponse = (socket: Socket, organization: string, event: string, result: any) => { + const emitEventResponse = (socket: Socket, organization: string, event: string, result: any) => { if (organization) { socket.to(organization).emit(event, { success: result.success, From 79b6a4fa751ee2a9c1cc31a8919cf2e67509e08d Mon Sep 17 00:00:00 2001 From: sabarinathan Date: Wed, 14 May 2025 18:47:04 +0530 Subject: [PATCH 4/7] Project Create and Get All projects API completed --- .env | 8 +- package-lock.json | 152 ++++++++++++++++++ package.json | 3 + src/api-server/Routes/projectRoutes.ts | 3 +- src/api-server/app.ts | 7 +- .../controller/project/projectController.ts | 40 ++++- src/shared/connect/blobConnection.ts | 10 ++ src/shared/connect/mongoose.ts | 8 +- src/shared/model/project/project-model.ts | 2 +- src/shared/services/blob/blobServices.ts | 67 ++++++++ .../services/project/project-Services.ts | 44 ++--- .../controllers/project/projectController.ts | 34 ++-- src/socket-server/index.ts | 4 +- src/socket-server/manager/manager.ts | 78 +++++++++ src/socket-server/socket/events.ts | 2 +- src/socket-server/utils/emitEventResponse.ts | 36 +++++ 16 files changed, 447 insertions(+), 51 deletions(-) create mode 100644 src/shared/connect/blobConnection.ts create mode 100644 src/shared/services/blob/blobServices.ts create mode 100644 src/socket-server/manager/manager.ts create mode 100644 src/socket-server/utils/emitEventResponse.ts diff --git a/.env b/.env index dab6736..f7cfbd6 100644 --- a/.env +++ b/.env @@ -11,4 +11,10 @@ MONGO_AUTH_DB=admin API_PORT=5000 SOCKET_PORT=8000 NODE_ENV=development -FRONTEND_ORIGIN_PROD=http://185.100.212.76:8200 \ No newline at end of file +FRONTEND_ORIGIN_PROD=http://185.100.212.76:8200 + +# MinIO +MinIO_URL=185.100.212.76 +MinIO_PORT=9999 +MinIO_accessKey=sabarinathan +MinIO_secretKey=sabarinathan diff --git a/package-lock.json b/package-lock.json index 3e98cae..fb2e2c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "jsonwebtoken": "^9.0.2", "minio": "^8.0.5", "mongoose": "^8.8.1", + "multer": "^1.4.5-lts.2", "socket.io": "^4.8.1", "swagger-autogen": "^2.23.7", "swagger-ui-express": "^5.0.1" @@ -28,6 +29,8 @@ "@types/express": "^5.0.0", "@types/ip": "^1.1.3", "@types/jsonwebtoken": "^9.0.7", + "@types/mime-types": "^2.1.4", + "@types/multer": "^1.4.12", "@types/node": "^22.9.0", "@types/swagger-ui-express": "^4.1.7", "nodemon": "^3.1.7", @@ -207,12 +210,27 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, + "node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "dev": true + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "dev": true }, + "node_modules/@types/multer": { + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.12.tgz", + "integrity": "sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "22.10.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", @@ -332,6 +350,11 @@ "node": ">= 8" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -474,6 +497,22 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -555,6 +594,47 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -587,6 +667,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -1279,6 +1364,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1467,6 +1557,14 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minio": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.5.tgz", @@ -1499,6 +1597,17 @@ "node": ">= 10" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mongodb": { "version": "6.12.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.12.0.tgz", @@ -1624,6 +1733,23 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/multer": { + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -1771,6 +1897,11 @@ "node": ">= 0.4" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2225,6 +2356,14 @@ "stream-chain": "^2.2.5" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/strict-uri-encode": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", @@ -2411,6 +2550,11 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", @@ -2578,6 +2722,14 @@ "node": ">=4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "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 2387750..b39f925 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "jsonwebtoken": "^9.0.2", "minio": "^8.0.5", "mongoose": "^8.8.1", + "multer": "^1.4.5-lts.2", "socket.io": "^4.8.1", "swagger-autogen": "^2.23.7", "swagger-ui-express": "^5.0.1" @@ -32,6 +33,8 @@ "@types/express": "^5.0.0", "@types/ip": "^1.1.3", "@types/jsonwebtoken": "^9.0.7", + "@types/mime-types": "^2.1.4", + "@types/multer": "^1.4.12", "@types/node": "^22.9.0", "@types/swagger-ui-express": "^4.1.7", "nodemon": "^3.1.7", diff --git a/src/api-server/Routes/projectRoutes.ts b/src/api-server/Routes/projectRoutes.ts index 92a3862..80016d9 100644 --- a/src/api-server/Routes/projectRoutes.ts +++ b/src/api-server/Routes/projectRoutes.ts @@ -1,6 +1,7 @@ import * as express from "express"; -import { createProjectController } from "../controller/project/projectController.ts"; +import { createProjectController, GetProjects } from "../controller/project/projectController.ts"; const projectRouter = express.Router(); projectRouter.post("/upsertProject",createProjectController) +projectRouter.get("/Projects/:userId/:organization",GetProjects) export default projectRouter \ No newline at end of file diff --git a/src/api-server/app.ts b/src/api-server/app.ts index 006d302..7e47001 100644 --- a/src/api-server/app.ts +++ b/src/api-server/app.ts @@ -53,7 +53,11 @@ app.use(cors()); // }, // credentials: true // })); -app.use(express.json()); + +app.use(express.json({ limit: "50mb" })); +app.use( + express.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 }) +); dotenv.config(); app.get("/", (req, res) => { res.send("Hello, I am Major-Dwinzo API!"); @@ -62,6 +66,7 @@ app.get("/", (req, res) => { app.get("/health", (req, res) => { res.status(200).json({ message: "Server is running" }); }); + app.use("/api/v1", cameraRoutes); app.use("/api/v1", environmentsRoutes); app.use("/api/v1", linesRoutes); diff --git a/src/api-server/controller/project/projectController.ts b/src/api-server/controller/project/projectController.ts index 0d4b8cc..c9e8bef 100644 --- a/src/api-server/controller/project/projectController.ts +++ b/src/api-server/controller/project/projectController.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import { createProject } from "../../../shared/services/project/project-Services.ts"; +import { createProject,GetAllProjects } from "../../../shared/services/project/project-Services.ts"; export const createProjectController = async ( req: Request, @@ -7,7 +7,6 @@ export const createProjectController = async ( ): Promise => { try { const result = await createProject(req.body); - console.log("result: ", result); switch (result.status) { case "project_exists": @@ -45,3 +44,40 @@ export const createProjectController = async ( }); } }; +export const GetProjects = async ( + req: Request, + res: Response +): Promise => { + try { + const { userId, organization } = req.params; + const result = await GetAllProjects({ userId, organization}); + switch (result?.status) { + + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + + case "success": + res.status(201).json({ + Projects: result?.Datas, + }); + break; + case "All fields are required": + res.status(400).json({ + message: "All fields are required", + }); + 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/shared/connect/blobConnection.ts b/src/shared/connect/blobConnection.ts new file mode 100644 index 0000000..414ae14 --- /dev/null +++ b/src/shared/connect/blobConnection.ts @@ -0,0 +1,10 @@ +import { Client } from 'minio'; +const minioClient = new Client({ + endPoint: process.env.MinIO_URL!, + port: parseInt(process.env.MinIO_PORT!, 10), + useSSL: false, + accessKey: process.env.MinIO_accessKey!, + secretKey: process.env.MinIO_secretKey!, +}); + + export { minioClient} \ No newline at end of file diff --git a/src/shared/connect/mongoose.ts b/src/shared/connect/mongoose.ts index 6548369..ffba38c 100644 --- a/src/shared/connect/mongoose.ts +++ b/src/shared/connect/mongoose.ts @@ -49,12 +49,6 @@ const MainModel = ( throw error; } }; -export const minioClient = new Client({ - endPoint: "185.100.212.76", // MinIO server IP or hostname - port: 9999, // MinIO server port - useSSL: false, // Set to true if SSL is configured - accessKey: "sabarinathan", // Access key - secretKey: "sabarinathan", -}); + export default MainModel; diff --git a/src/shared/model/project/project-model.ts b/src/shared/model/project/project-model.ts index 504ad3d..3320391 100644 --- a/src/shared/model/project/project-model.ts +++ b/src/shared/model/project/project-model.ts @@ -15,7 +15,7 @@ export interface Project extends Document { } const projectSchema: Schema = new Schema( { - projectUuid: { type: String, required: true }, + projectUuid: { type: String }, projectName: { type: String }, thumbnail: { type: String }, isArchive: { type: Boolean, default: false }, diff --git a/src/shared/services/blob/blobServices.ts b/src/shared/services/blob/blobServices.ts new file mode 100644 index 0000000..87df4d0 --- /dev/null +++ b/src/shared/services/blob/blobServices.ts @@ -0,0 +1,67 @@ +import { minioClient } from "../../connect/blobConnection.ts"; + +type MulterFile = { + fieldname: string; + originalname: string; + encoding: string; + mimetype: string; + size: number; + buffer: Buffer; +}; + +const bucketName = "assets-public-bucket"; + +// Define public read policy +const publicReadPolicy = { + Version: "2012-10-17", + Statement: [ + { + Effect: "Allow", + Principal: { AWS: "*" }, + Action: ["s3:GetObject"], + Resource: [`arn:aws:s3:::${bucketName}/*`], + }, + ], +}; + +async function ensureBucketExists() { + const exists = await minioClient.bucketExists(bucketName); + if (!exists) { + await minioClient.makeBucket(bucketName, "local-region"); + console.log("Bucket created"); + } +} + +async function ensureFolderExists(folderName: string) { + const folderPrefix = folderName.endsWith("/") ? folderName : `${folderName}/`; + const objects = minioClient.listObjects(bucketName, folderPrefix, true); + for await (const _ of objects) return; // Folder exists + await minioClient.putObject(bucketName, folderPrefix, Buffer.from("")); +} + +async function setPublicPolicy() { + await minioClient.setBucketPolicy(bucketName, JSON.stringify(publicReadPolicy)); +} + +export async function uploadProjectThumbnail(file: MulterFile, folderName: string): Promise { + try { + const folderName = "models"; + const objectName = `${folderName}/${Date.now()}_${file.originalname}`; + + + await ensureBucketExists(); + await ensureFolderExists(folderName); + await minioClient.putObject(bucketName, objectName, file.buffer, file.size, { + "Content-Type": file.mimetype, + }); + await setPublicPolicy(); + + const encodedName = encodeURIComponent(objectName); + const blobUrl = `${process.env.MinIO_USESSL === "true" ? "https" : "http"}://${process.env.MinIO_URL}:${process.env.MINIO_PORT}/${bucketName}/${encodedName}`; + + return blobUrl; + } catch (err) { + console.error("Upload failed:", err); + throw new Error("Thumbnail upload failed"); + } +} diff --git a/src/shared/services/project/project-Services.ts b/src/shared/services/project/project-Services.ts index 21975f9..90b8ac2 100644 --- a/src/shared/services/project/project-Services.ts +++ b/src/shared/services/project/project-Services.ts @@ -2,6 +2,8 @@ import projectModel from "../../model/project/project-model.ts"; import userModel from "../../model/user-Model.ts"; import { Types } from "mongoose"; import versionModel from "../../model/version/versionModel.ts"; +import { uploadProjectThumbnail } from "../blob/blobServices.ts"; + interface CreateProjectInput { projectName: string; projectUuid: string; @@ -10,7 +12,10 @@ interface CreateProjectInput { sharedUsers?: string[]; organization: string; } - +interface GetInterface { + userId: string; + organization: string; +} export const createProject = async (data: CreateProjectInput) => { try { const { @@ -21,9 +26,9 @@ export const createProject = async (data: CreateProjectInput) => { sharedUsers, organization, } = data; + if ( !projectName || - !projectUuid || !userId || !thumbnail || // !sharedUsers || @@ -36,7 +41,7 @@ export const createProject = async (data: CreateProjectInput) => { status: "user_not_found", }; } - const projectExisting = await existingProject(projectUuid, organization); + const projectExisting = await existingProject(projectName, organization,userId); if (projectExisting) { return { @@ -49,17 +54,18 @@ export const createProject = async (data: CreateProjectInput) => { projectName: projectName, projectUuid: projectUuid, createdBy: userId, - thumbnail: thumbnail || "", + thumbnail: thumbnail, sharedUsers: sharedUsers || [], isArchive: false, }); - const versionData = previousVersion(project._id, organization); - if (!versionData) { - await versionModel(organization).create({ + 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.01, }); + await projectModel(organization).findByIdAndUpdate({_id:project._id,isArchive:false},{total_versions:`v-${newVersion.version.toFixed(2)}`}) } return { status: "success", @@ -73,7 +79,7 @@ export const createProject = async (data: CreateProjectInput) => { } }; -export const GetAllProjects = async (data: CreateProjectInput) => { +export const GetAllProjects = async (data: GetInterface) => { try { const { userId, organization } = data; await existingUser(userId, organization); @@ -83,18 +89,20 @@ export const GetAllProjects = async (data: CreateProjectInput) => { isArchive: false, }) .select("_id projectName createdBy thumbnail"); - if (projectDatas) return { Datas: projectDatas }; + if (projectDatas) return {status:"success", Datas: projectDatas }; } catch (error: unknown) { return { status: error }; } }; export const existingProject = async ( - projectUuid: string, - organization: string + projectName: string, + organization: string, + userId:string ) => { const projectData = await projectModel(organization).findOne({ - projectUuid: projectUuid, + projectName: projectName, + createdBy:userId, isArchive: false, }); return projectData; @@ -124,12 +132,10 @@ export const archiveProject = async ( export const previousVersion = async ( projectId: string, organization: string -): Promise => { - const result = await versionModel(organization) - .findOne({ - projectId: projectId, - isArchive: false, - }) - .sort({ version: -1 }); +)=> { + console.log('projectId: ', projectId); + const result = await versionModel(organization).findOne({ projectId: projectId, isArchive: false}) + console.log('result: ', result); + // .sort({ version: -1 }); return result; }; diff --git a/src/socket-server/controllers/project/projectController.ts b/src/socket-server/controllers/project/projectController.ts index b046cf1..df4ffa3 100644 --- a/src/socket-server/controllers/project/projectController.ts +++ b/src/socket-server/controllers/project/projectController.ts @@ -1,15 +1,17 @@ -import { Socket } from "socket.io"; +import { Socket, Server } from "socket.io"; import { createProject } from "../../../shared/services/project/project-Services.ts"; import { EVENTS } from "../../socket/events.ts"; +import { emitEventResponse } from "../../utils/emitEventResponse.ts"; export const projectHandleEvent = async ( event: string, socket: Socket, data: any, - namespace: any + namespace: any, + io: Server // Make sure this is passed in from the socket manager ) => { if (!data?.organization) { - console.warn(`Missing organization in event: ${event}`); + console.log(`Missing organization in event: ${event}`); return; } @@ -18,29 +20,29 @@ export const projectHandleEvent = async ( switch (event) { case EVENTS.addProject: { result = await createProject(data); - - // Create response object + console.log('result: ', result); + const isSuccess = result.status === "success"; + // ✅ Build response object const response = { success: result.status === "success", message: result.status === "project_exists" ? "Project already exists" : result.status === "user_not_found" - ? "User not found" - : result.status === "invalid_user_id" - ? "Invalid User ID" - : result.status === "success" - ? "Project created successfully" - : "Something went wrong", - data: result.project || null, - status: result.status, + ? "User not found" + : result.status === "invalid_user_id" + ? "Invalid User ID" + : isSuccess + ? "Project created successfully" + : "Something went wrong", + ...(isSuccess ? { data: result.project } : {}), + status: String(result.status), socketId: socket.id, organization: data.organization, }; - // Emit response to the organization room - - + // ✅ Emit response + emitEventResponse(socket, data.organization, EVENTS.projectResponse, response); break; } diff --git a/src/socket-server/index.ts b/src/socket-server/index.ts index 044f064..88dbdbd 100644 --- a/src/socket-server/index.ts +++ b/src/socket-server/index.ts @@ -7,7 +7,7 @@ import dotenv from "dotenv"; // Import dotenv dotenv.config(); import { initSocketServer } from "./socket/socketManager.ts"; - +import { SocketServer } from "./manager/manager.ts"; const app = express(); const PORT = process.env.SOCKET_PORT; const server = http.createServer(app); @@ -15,8 +15,8 @@ const server = http.createServer(app); app.get('/', (req: Request, res: Response) => { res.send('Hello, I am Major-Dwinzo RealTime!'); }); - initSocketServer(server); +// SocketServer(server) server.listen(PORT, () => { console.log(`socket-Server is running on http://localhost:${PORT}`); }); diff --git a/src/socket-server/manager/manager.ts b/src/socket-server/manager/manager.ts new file mode 100644 index 0000000..1ef2dc8 --- /dev/null +++ b/src/socket-server/manager/manager.ts @@ -0,0 +1,78 @@ +import { Server, Socket } from 'socket.io'; +import { projectHandleEvent } from '../controllers/project/projectController.ts'; + +export const SocketServer = (httpServer: any) => { + const io = new Server(httpServer, { + cors: { + origin: '*', // Allow CORS for all origins (adjust in production) + methods: ['GET', 'POST'], + }, + }); + + + + const namespaces = { + + project: io.of('/project'), + + }; + + // const onlineUsers = new Map>(); + const onlineUsers: { [organization: string]: Set } = {}; + + + const handleNamespace = ( namespace: any, ...eventHandlers: Function[]) => { + + namespace.on("connection", (socket: Socket) => { + console.log(`✅ Client connected to ${namespace.name}: ${socket.id}`); + // Extract organization from query parameters + + const organization = socket.handshake.query.organization as string; + const email = socket.handshake.query.email as string; + // const {organization,email} = socket.handshake.auth + console.log(`🔍 Received organization: ${organization}`); + + if (organization) { + socket.join(organization); + // console.log(`🔹 Socket ${socket.id} joined room: ${organization}`); + } + // Handle all events + if (organization && email) { + if (!onlineUsers[organization]) { + onlineUsers[organization] = new Set(); + } + onlineUsers[organization].add(socket.id); + + } + + // userStatus(EVENTS.connection, socket, socket.handshake.auth, socket); + + socket.onAny((event: string, data: any ,callback:any) => { + eventHandlers.forEach(handler => handler(event, socket, data, namespace,io,callback)); + }); + + // Handle disconnection + socket.on("disconnect", () => { + onlineUsers[organization]?.delete(socket.id); + if (onlineUsers[organization]?.size === 0) delete onlineUsers[organization]; + // userStatus(EVENTS.disconnect, socket, socket.handshake.auth, socket); + + }); + + // Handle reconnection (Auto rejoin) + socket.on("reconnect", (attempt: number) => { + + if (organization) { + socket.join(organization); + + } + }); + }); + }; + + + + +handleNamespace(namespaces.project,projectHandleEvent) + return io; +}; \ No newline at end of file diff --git a/src/socket-server/socket/events.ts b/src/socket-server/socket/events.ts index 1fee1b1..6d0dc31 100644 --- a/src/socket-server/socket/events.ts +++ b/src/socket-server/socket/events.ts @@ -101,5 +101,5 @@ export const EVENTS = { //PROJECT addProject:"v1:project:add", - projectResponse:"v1-project:response:update:", + projectResponse:"v1-project:response:update", } \ No newline at end of file diff --git a/src/socket-server/utils/emitEventResponse.ts b/src/socket-server/utils/emitEventResponse.ts new file mode 100644 index 0000000..8546ef8 --- /dev/null +++ b/src/socket-server/utils/emitEventResponse.ts @@ -0,0 +1,36 @@ +import { Socket } from "socket.io"; + +interface EmitOptions { + success: boolean; + message: string; + data?: any; + error?: any; + organization: string; + socketId: string; + status?: string; +} + +/** + * Emit a structured socket event response to a specific organization room. + */ +export const emitEventResponse = ( + socket: Socket, + organization: string, + event: string, + result: EmitOptions +) => { + console.log(`📤 emitEventResponse called for event: ${event}, organization: ${organization}`); + if (!organization) { + console.log(`Organization missing in response for event: ${event}`); + return; + } + + socket.emit(event, { + success: result.success, + message: result.message, + data: result.data , + error: result.error ?? null, + socketId: result.socketId, + organization, + }); +}; From 46dafd44171a662f5678f0c35a4d422f5b28a96a Mon Sep 17 00:00:00 2001 From: Nivetharamesh Date: Thu, 15 May 2025 14:08:14 +0530 Subject: [PATCH 5/7] Trash Get, Restore API completed, Project Delete API completed --- src/api-server/Routes/projectRoutes.ts | 13 ++- src/api-server/Routes/trashRoutes.ts | 8 ++ src/api-server/app.ts | 2 + .../controller/project/projectController.ts | 78 ++++++++++--- .../controller/trash/trashcontrollers.ts | 96 ++++++++++++++++ src/shared/model/project/project-model.ts | 2 + .../services/helpers/ProjecthelperFn.ts | 49 ++++++++ .../services/project/project-Services.ts | 108 ++++++++---------- src/shared/services/trash/trashService.ts | 68 +++++++++++ .../controllers/project/projectController.ts | 4 +- 10 files changed, 342 insertions(+), 86 deletions(-) create mode 100644 src/api-server/Routes/trashRoutes.ts create mode 100644 src/api-server/controller/trash/trashcontrollers.ts create mode 100644 src/shared/services/helpers/ProjecthelperFn.ts create mode 100644 src/shared/services/trash/trashService.ts diff --git a/src/api-server/Routes/projectRoutes.ts b/src/api-server/Routes/projectRoutes.ts index 80016d9..95d4373 100644 --- a/src/api-server/Routes/projectRoutes.ts +++ b/src/api-server/Routes/projectRoutes.ts @@ -1,7 +1,12 @@ import * as express from "express"; -import { createProjectController, GetProjects } from "../controller/project/projectController.ts"; +import { + createProjectController, + GetProjects, + RemoveProject, +} from "../controller/project/projectController.ts"; const projectRouter = express.Router(); -projectRouter.post("/upsertProject",createProjectController) -projectRouter.get("/Projects/:userId/:organization",GetProjects) -export default projectRouter \ No newline at end of file +projectRouter.post("/upsertProject", createProjectController); +projectRouter.get("/Projects/:userId/:organization", GetProjects); +projectRouter.patch("/Project/archive/:projectId", RemoveProject); +export default projectRouter; diff --git a/src/api-server/Routes/trashRoutes.ts b/src/api-server/Routes/trashRoutes.ts new file mode 100644 index 0000000..89709ca --- /dev/null +++ b/src/api-server/Routes/trashRoutes.ts @@ -0,0 +1,8 @@ +import * as express from "express"; +import { GetTrashList, RestoreTrash } from "../controller/trash/trashcontrollers.ts"; + +const trashRouter = express.Router(); +trashRouter.get("/Trash/Lists", GetTrashList); +trashRouter.patch("/restore",RestoreTrash) + +export default trashRouter; diff --git a/src/api-server/app.ts b/src/api-server/app.ts index 7e47001..aa446f2 100644 --- a/src/api-server/app.ts +++ b/src/api-server/app.ts @@ -20,6 +20,7 @@ import templateRoutes from "./Routes/templateRoutes.ts"; import widget3dRoutes from "./Routes/widget3dRoutes.ts"; import productRouter from "./Routes/productRoutes.ts"; import projectRouter from "./Routes/projectRoutes.ts"; +import trashRouter from "./Routes/trashRoutes.ts"; // import productFlowRoutes from "./Routes/productFlowRouts.ts"; const app = express(); @@ -87,4 +88,5 @@ app.use("/api/v2", widget3dRoutes); app.use("/api/v2", productRouter); // app.use("/api/v2", productFlowRoutes); app.use("/api/v1",projectRouter) +app.use("/api/v1",trashRouter) export default app; diff --git a/src/api-server/controller/project/projectController.ts b/src/api-server/controller/project/projectController.ts index c9e8bef..790861c 100644 --- a/src/api-server/controller/project/projectController.ts +++ b/src/api-server/controller/project/projectController.ts @@ -1,16 +1,25 @@ import { Request, Response } from "express"; -import { createProject,GetAllProjects } from "../../../shared/services/project/project-Services.ts"; +import { + createProject, + DeleteProject, + GetAllProjects, +} from "../../../shared/services/project/project-Services.ts"; export const createProjectController = async ( req: Request, res: Response ): Promise => { try { + const { projectName, userId, thumbnail, organization } = req.body; + if (!projectName || !userId || !thumbnail || !organization) + res.status(400).json({ + message: "All fields are required", + }); const result = await createProject(req.body); switch (result.status) { case "project_exists": - res.status(409).json({ + res.status(403).json({ message: "Project already exists", }); break; @@ -21,17 +30,12 @@ export const createProjectController = async ( }); break; - case "success": + case "Success": res.status(201).json({ - message: "Project created successfully", + message: "Project created Successfully", projectId: result.project._id, }); break; - case "All fields are required": - res.status(400).json({ - message: "All fields are required", - }); - break; default: res.status(500).json({ message: "Internal server error", @@ -50,25 +54,23 @@ export const GetProjects = async ( ): Promise => { try { const { userId, organization } = req.params; - const result = await GetAllProjects({ userId, organization}); + if (!userId || !organization) + res.status(400).json({ + message: "All fields are required", + }); + const result = await GetAllProjects({ userId, organization }); switch (result?.status) { - case "User not found": res.status(404).json({ message: "User not found", }); break; - case "success": + case "Success": res.status(201).json({ Projects: result?.Datas, }); break; - case "All fields are required": - res.status(400).json({ - message: "All fields are required", - }); - break; default: res.status(500).json({ message: "Internal server error", @@ -80,4 +82,44 @@ export const GetProjects = async ( message: "Unknown error", }); } -}; \ No newline at end of file +}; +export const RemoveProject = async ( + req: Request, + res: Response +): Promise => { + try { + const { projectId } = req.params; + const { organization, userId } = req.body; + if (!projectId || !organization || !userId) + res.status(400).json({ + message: "All fields are required", + }); + const result = await DeleteProject({ projectId, organization, userId }); + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(201).json({ + message: "Project Deleted Successfully", + }); + 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/controller/trash/trashcontrollers.ts b/src/api-server/controller/trash/trashcontrollers.ts new file mode 100644 index 0000000..2e7b1d4 --- /dev/null +++ b/src/api-server/controller/trash/trashcontrollers.ts @@ -0,0 +1,96 @@ +import { Request, Response } from "express"; +import { + TrashDatas, + RestoreTrashData, +} from "../../../shared/services/trash/trashService.ts"; + +export const GetTrashList = async ( + req: Request, + res: Response +): Promise => { + try { + const { organization } = req.query as { organization?: string }; + console.log("organization: ", organization); + if (!organization) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await TrashDatas({ organization }); + + switch (result.status) { + case "Trash is Empty": + res.status(200).json({ + message: "Trash is Empty", + TrashDatas: [], + }); + break; + + case "Success": + res.status(200).json({ + // message: "Project created Successfully", + TrashDatas: result.ListDatas, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + console.log("error: ", error); + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const RestoreTrash = async ( + req: Request, + res: Response +): Promise => { + try { + const { organization, projectId } = req.query as { + organization?: string; + projectId?: string; + }; + console.log("organization: ", organization); + if (!organization || !projectId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await RestoreTrashData({ organization, projectId }); + + switch (result.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "Project Restore unsuccessfull": + res.status(200).json({ + message: "Project Restore unsuccessfull", + }); + break; + case "Project Restored successfully": + res.status(200).json({ + message: "Project Restored successfully", + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + console.log("error: ", error); + res.status(500).json({ + message: "Unknown error", + }); + } +}; diff --git a/src/shared/model/project/project-model.ts b/src/shared/model/project/project-model.ts index 3320391..09a8fd2 100644 --- a/src/shared/model/project/project-model.ts +++ b/src/shared/model/project/project-model.ts @@ -7,6 +7,7 @@ export interface Project extends Document { projectName: string; createdBy: User["_id"]; isArchive: boolean; + isDeleted: boolean; thumbnail: string; sharedUsers: []; DeletedAt: Date; @@ -22,6 +23,7 @@ const projectSchema: Schema = new Schema( createdBy: { type: Schema.Types.ObjectId, ref: "user" }, sharedUsers: [{ type: Schema.Types.ObjectId, ref: "user" }], DeletedAt: { type: Date, default: null }, + isDeleted: { type: Boolean, default: false }, total_versions: { type: String }, Present_version: { type: String }, }, diff --git a/src/shared/services/helpers/ProjecthelperFn.ts b/src/shared/services/helpers/ProjecthelperFn.ts new file mode 100644 index 0000000..1b16f94 --- /dev/null +++ b/src/shared/services/helpers/ProjecthelperFn.ts @@ -0,0 +1,49 @@ +import projectModel from "../../model/project/project-model.ts"; +import userModel from "../../model/user-Model.ts"; +import { Types } from "mongoose"; +import versionModel from "../../model/version/versionModel.ts"; +export const existingProject = async ( + projectName: string, + organization: string, + userId: string +) => { + const projectData = await projectModel(organization).findOne({ + projectName: projectName, + createdBy: userId, + isArchive: false, + }); + return projectData; +}; + +export const existingUser = async (userId: string, organization: string) => { + if (!Types.ObjectId.isValid(userId)) { + console.log("Invalid ObjectId format"); + return null; + } + const userData = await userModel(organization).findOne({ + _id: userId, + }); + return userData; +}; + +export const archiveProject = async ( + projectId: string, + organization: string +) => { + return await projectModel(organization).findByIdAndUpdate( + projectId, + { isArchive: true }, + { new: true } + ); +}; +export const previousVersion = async ( + projectId: string, + organization: string +) => { + const result = await versionModel(organization).findOne({ + projectId: projectId, + isArchive: false, + }); + // .sort({ version: -1 }); + return result; +}; diff --git a/src/shared/services/project/project-Services.ts b/src/shared/services/project/project-Services.ts index 90b8ac2..1b8c409 100644 --- a/src/shared/services/project/project-Services.ts +++ b/src/shared/services/project/project-Services.ts @@ -2,8 +2,12 @@ import projectModel from "../../model/project/project-model.ts"; import userModel from "../../model/user-Model.ts"; import { Types } from "mongoose"; import versionModel from "../../model/version/versionModel.ts"; -import { uploadProjectThumbnail } from "../blob/blobServices.ts"; - +import { + existingProject, + existingUser, + archiveProject, + previousVersion, +} from "../helpers/ProjecthelperFn.ts"; interface CreateProjectInput { projectName: string; projectUuid: string; @@ -12,8 +16,13 @@ interface CreateProjectInput { sharedUsers?: string[]; organization: string; } -interface GetInterface { - userId: string; +interface GetProjectsInterface { + userId: string; + organization: string; +} +interface DeleteProjectInterface { + projectId: string; + userId: string; organization: string; } export const createProject = async (data: CreateProjectInput) => { @@ -26,22 +35,17 @@ export const createProject = async (data: CreateProjectInput) => { sharedUsers, organization, } = data; - - if ( - !projectName || - !userId || - !thumbnail || - // !sharedUsers || - !organization - ) - return { status: "All fields are required" }; const userExisting = await existingUser(userId, organization); if (!userExisting) { return { status: "user_not_found", }; } - const projectExisting = await existingProject(projectName, organization,userId); + const projectExisting = await existingProject( + projectName, + organization, + userId + ); if (projectExisting) { return { @@ -60,26 +64,29 @@ export const createProject = async (data: CreateProjectInput) => { }); const versionData = await previousVersion(project._id, organization); if (!versionData || versionData.length === 0) { - const newVersion= await versionModel(organization).create({ + const newVersion = await versionModel(organization).create({ projectId: project._id, createdBy: userId, version: 0.01, }); - await projectModel(organization).findByIdAndUpdate({_id:project._id,isArchive:false},{total_versions:`v-${newVersion.version.toFixed(2)}`}) + await projectModel(organization).findByIdAndUpdate( + { _id: project._id, isArchive: false }, + { total_versions: `v-${newVersion.version.toFixed(2)}` } + ); } return { - status: "success", + status: "Success", project: project, }; } catch (error) { - console.log('error: ', error); + console.log("error: ", error); return { status: error, }; } }; -export const GetAllProjects = async (data: GetInterface) => { +export const GetAllProjects = async (data: GetProjectsInterface) => { try { const { userId, organization } = data; await existingUser(userId, organization); @@ -89,53 +96,30 @@ export const GetAllProjects = async (data: GetInterface) => { isArchive: false, }) .select("_id projectName createdBy thumbnail"); - if (projectDatas) return {status:"success", Datas: projectDatas }; + if (projectDatas) return { status: "Success", Datas: projectDatas }; } catch (error: unknown) { return { status: error }; } }; -export const existingProject = async ( - projectName: string, - organization: string, - userId:string -) => { - const projectData = await projectModel(organization).findOne({ - projectName: projectName, - createdBy:userId, - isArchive: false, - }); - return projectData; -}; - -export const existingUser = async (userId: string, organization: string) => { - if (!Types.ObjectId.isValid(userId)) { - console.log("Invalid ObjectId format"); - return null; +export const DeleteProject = async (data: DeleteProjectInterface) => { + try { + const { projectId, organization, userId } = data; + const ExistingUser = await existingUser(userId, organization); + if (!ExistingUser) return { status: "User not found" }; + const existingProject = await projectModel(organization).findOne({ + _id: projectId, + createdBy: userId, + isArchive: false, + }); + if (!existingProject) return { status: "Project not found" }; + const updateProject = await projectModel(organization).findOneAndUpdate( + { _id: projectId, isArchive: false }, + { isArchive: true, DeletedAt: new Date() }, + { new: true } + ); + if (updateProject) return { status: "Success" }; + } catch (error: unknown) { + return { status: error }; } - const userData = await userModel(organization).findOne({ - _id: userId, - }); - return userData; // ✅ Make sure you return it -}; - -export const archiveProject = async ( - projectId: string, - organization: string -) => { - return await projectModel(organization).findByIdAndUpdate( - projectId, - { isArchive: true }, - { new: true } - ); -}; -export const previousVersion = async ( - projectId: string, - organization: string -)=> { - console.log('projectId: ', projectId); - const result = await versionModel(organization).findOne({ projectId: projectId, isArchive: false}) - console.log('result: ', result); - // .sort({ version: -1 }); - return result; }; diff --git a/src/shared/services/trash/trashService.ts b/src/shared/services/trash/trashService.ts new file mode 100644 index 0000000..c1c1511 --- /dev/null +++ b/src/shared/services/trash/trashService.ts @@ -0,0 +1,68 @@ +import projectModel from "../../model/project/project-model.ts"; +interface IOrg { + organization: string; +} +interface IRestore { + projectId: string; + organization: string; +} +export const TrashDatas = async (data: IOrg) => { + try { + const { organization } = data; + + const TrashLists = await projectModel(organization).find({ + isArchive: true, + isDeleted: false, + }); + if (!TrashLists) return { staus: "Trash is Empty" }; + const TrashDocs: any[] = []; + for (const Trash of TrashLists) { + const now = new Date(); + const deletedPlus15 = new Date( + 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 } } + ); + } else { + TrashDocs.push(Trash); + } + } + const ListDatas = TrashDocs.map((data) => { + return { + projectName: data.projectName, + thumbnail: data.thumbnail, + createdBy: data.createdBy, + _id: data._id, + }; + }); + + return { status: "Success", ListDatas }; + } catch (error) { + return { status: error }; + } +}; +export const RestoreTrashData = async (data: IRestore) => { + try { + const { projectId, organization } = data; + console.log("projectId: ", projectId); + const findProject = await projectModel(organization).findOne({ + _id: projectId, + isArchive: true, + }); + console.log("findProject: ", findProject); + if (!findProject) return { status: "Project not found" }; + const restoreData = await projectModel(organization).findOneAndUpdate( + { _id: projectId, isArchive: true }, + { isArchive: false, DeletedAt: null }, + { new: true } + ); + if (!restoreData) return { status: "Project Restore unsuccessfull" }; + return { status: "Project Restored successfully" }; + } catch (error) { + return { status: error }; + } +}; diff --git a/src/socket-server/controllers/project/projectController.ts b/src/socket-server/controllers/project/projectController.ts index df4ffa3..7c17519 100644 --- a/src/socket-server/controllers/project/projectController.ts +++ b/src/socket-server/controllers/project/projectController.ts @@ -21,10 +21,10 @@ export const projectHandleEvent = async ( case EVENTS.addProject: { result = await createProject(data); console.log('result: ', result); - const isSuccess = result.status === "success"; + const isSuccess = result.status === "Success"; // ✅ Build response object const response = { - success: result.status === "success", + success: result.status === "Success", message: result.status === "project_exists" ? "Project already exists" From bd0c5013a91fbacb19fe98b165b39822d34fe21f Mon Sep 17 00:00:00 2001 From: Nivetharamesh Date: Thu, 15 May 2025 18:53:18 +0530 Subject: [PATCH 6/7] View project, update project Data, Usermodel modified Based on the recentlyViewed --- src/api-server/Routes/projectRoutes.ts | 4 + .../controller/project/projectController.ts | 116 +++++++++++++++++- .../controller/trash/trashcontrollers.ts | 7 +- src/shared/model/user-Model.ts | 34 ++--- .../services/helpers/ProjecthelperFn.ts | 34 ++++- .../services/project/project-Services.ts | 93 +++++++++++--- src/shared/services/trash/trashService.ts | 2 - 7 files changed, 248 insertions(+), 42 deletions(-) diff --git a/src/api-server/Routes/projectRoutes.ts b/src/api-server/Routes/projectRoutes.ts index 95d4373..5ddb6fa 100644 --- a/src/api-server/Routes/projectRoutes.ts +++ b/src/api-server/Routes/projectRoutes.ts @@ -3,10 +3,14 @@ import { createProjectController, GetProjects, RemoveProject, + updateProjectController, + ViewData, } from "../controller/project/projectController.ts"; const projectRouter = express.Router(); projectRouter.post("/upsertProject", createProjectController); projectRouter.get("/Projects/:userId/:organization", GetProjects); projectRouter.patch("/Project/archive/:projectId", RemoveProject); +projectRouter.patch("/Project/modify", updateProjectController); +projectRouter.get("/Project/view", ViewData); export default projectRouter; diff --git a/src/api-server/controller/project/projectController.ts b/src/api-server/controller/project/projectController.ts index 790861c..a061d11 100644 --- a/src/api-server/controller/project/projectController.ts +++ b/src/api-server/controller/project/projectController.ts @@ -3,6 +3,8 @@ import { createProject, DeleteProject, GetAllProjects, + updateProject, + viewProject, } from "../../../shared/services/project/project-Services.ts"; export const createProjectController = async ( @@ -10,11 +12,13 @@ export const createProjectController = async ( res: Response ): Promise => { try { - const { projectName, userId, thumbnail, organization } = req.body; - if (!projectName || !userId || !thumbnail || !organization) + const { projectUuid, userId, thumbnail, organization } = req.body; + if (!projectUuid || !userId || !thumbnail || !organization) { res.status(400).json({ message: "All fields are required", }); + return; + } const result = await createProject(req.body); switch (result.status) { @@ -46,6 +50,7 @@ export const createProjectController = async ( res.status(500).json({ message: "Unknown error", }); + return; } }; export const GetProjects = async ( @@ -54,10 +59,12 @@ export const GetProjects = async ( ): Promise => { try { const { userId, organization } = req.params; - if (!userId || !organization) + if (!userId || !organization) { res.status(400).json({ message: "All fields are required", }); + return; + } const result = await GetAllProjects({ userId, organization }); switch (result?.status) { case "User not found": @@ -81,6 +88,7 @@ export const GetProjects = async ( res.status(500).json({ message: "Unknown error", }); + return; } }; export const RemoveProject = async ( @@ -90,10 +98,12 @@ export const RemoveProject = async ( try { const { projectId } = req.params; const { organization, userId } = req.body; - if (!projectId || !organization || !userId) + if (!projectId || !organization || !userId) { res.status(400).json({ message: "All fields are required", }); + return; + } const result = await DeleteProject({ projectId, organization, userId }); switch (result?.status) { case "Project not found": @@ -121,5 +131,103 @@ export const RemoveProject = async ( res.status(500).json({ message: "Unknown error", }); + return; + } +}; +export const updateProjectController = async ( + req: Request, + res: Response +): Promise => { + try { + const { projectId, organization, projectName, thumbnail, userId } = + req.body; + if (!userId || !organization || !projectId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await updateProject({ + projectId, + organization, + userId, + projectName, + thumbnail, + }); + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(200).json({ + message: "Project updated Successfully", + projectData: 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 ViewData = async (req: Request, res: Response): Promise => { + try { + const { projectId, organization, userId } = req.query as { + organization: string; + projectId: string; + userId: string; + }; + if (!userId || !organization || !projectId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await viewProject({ + projectId, + organization, + userId, + }); + switch (result?.status) { + case "Project not found": + res.status(404).json({ + message: "Project not found", + }); + break; + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Success": + res.status(200).json({ + projectData: 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/controller/trash/trashcontrollers.ts b/src/api-server/controller/trash/trashcontrollers.ts index 2e7b1d4..7b02590 100644 --- a/src/api-server/controller/trash/trashcontrollers.ts +++ b/src/api-server/controller/trash/trashcontrollers.ts @@ -9,8 +9,7 @@ export const GetTrashList = async ( res: Response ): Promise => { try { - const { organization } = req.query as { organization?: string }; - console.log("organization: ", organization); + const { organization } = req.query as { organization: string }; if (!organization) { res.status(400).json({ message: "All fields are required", @@ -53,8 +52,8 @@ export const RestoreTrash = async ( ): Promise => { try { const { organization, projectId } = req.query as { - organization?: string; - projectId?: string; + organization: string; + projectId: string; }; console.log("organization: ", organization); if (!organization || !projectId) { diff --git a/src/shared/model/user-Model.ts b/src/shared/model/user-Model.ts index 191a1a7..2f1e13d 100644 --- a/src/shared/model/user-Model.ts +++ b/src/shared/model/user-Model.ts @@ -4,12 +4,11 @@ export interface User extends Document { userName: String; email: String; password: String; - + recentlyViewed: string[]; role: String; profilePicture: String; - isShare:Boolean, - activeStatus:string - + isShare: Boolean; + activeStatus: string; } const signupschema: Schema = new Schema({ userName: { @@ -35,16 +34,19 @@ const signupschema: Schema = new Schema({ type: String, // default: "default-profile-picture.jpg" }, - isShare:{ - type:Boolean, - default:false - }, - activeStatus:{ - type:String, + isShare: { + type: Boolean, + default: false, + }, + activeStatus: { + type: String, enum: ["online", "offline"], - default: "offline" - } - + default: "offline", + }, + recentlyViewed: { + type: [String], + default: [], + }, }); // const userModel = (db: string) => { // const mongoUrl = process.env.MONGO_URI || ""; @@ -63,7 +65,7 @@ const signupschema: Schema = new Schema({ // }; // export default userModel; -const userModel = (db:string) => { - return MainModel(db, "Users", signupschema, "Users") +const userModel = (db: string) => { + return MainModel(db, "Users", signupschema, "Users"); }; -export default userModel; \ No newline at end of file +export default userModel; diff --git a/src/shared/services/helpers/ProjecthelperFn.ts b/src/shared/services/helpers/ProjecthelperFn.ts index 1b16f94..5749781 100644 --- a/src/shared/services/helpers/ProjecthelperFn.ts +++ b/src/shared/services/helpers/ProjecthelperFn.ts @@ -3,12 +3,12 @@ import userModel from "../../model/user-Model.ts"; import { Types } from "mongoose"; import versionModel from "../../model/version/versionModel.ts"; export const existingProject = async ( - projectName: string, + projectUuid: string, organization: string, userId: string ) => { const projectData = await projectModel(organization).findOne({ - projectName: projectName, + projectUuid: projectUuid, createdBy: userId, isArchive: false, }); @@ -47,3 +47,33 @@ export const previousVersion = async ( // .sort({ version: -1 }); return result; }; +export const generateUntitledProjectName = async ( + organization: string, + userId: string +): Promise => { + const projects = await projectModel(organization) + .find({ + createdBy: userId, + isArchive: false, + projectName: { $regex: /^Untitled(?: \s?\d+)?$/, $options: "i" }, + }) + .select("projectName"); + + const usedNumbers = new Set(); + + for (const proj of projects) { + const match = proj.projectName.match(/^Untitled(?:\s?(\d+))?$/); + console.log("match: ", match); + if (match) { + const num = match[1] ? parseInt(match[1], 10) : 0; + usedNumbers.add(num); + } + } + + let newNumber = 0; + while (usedNumbers.has(newNumber)) { + newNumber++; + } + + return newNumber === 0 ? "Untitled" : `Untitled ${newNumber}`; +}; diff --git a/src/shared/services/project/project-Services.ts b/src/shared/services/project/project-Services.ts index 1b8c409..85b7495 100644 --- a/src/shared/services/project/project-Services.ts +++ b/src/shared/services/project/project-Services.ts @@ -7,6 +7,7 @@ import { existingUser, archiveProject, previousVersion, + generateUntitledProjectName, } from "../helpers/ProjecthelperFn.ts"; interface CreateProjectInput { projectName: string; @@ -16,25 +17,26 @@ interface CreateProjectInput { sharedUsers?: string[]; organization: string; } +interface updateProjectInput { + projectName: string; + projectId: string; + userId: string; // user ID + thumbnail?: string; + sharedUsers?: string[]; + organization: string; +} interface GetProjectsInterface { userId: string; organization: string; } -interface DeleteProjectInterface { +interface ProjectInterface { projectId: string; userId: string; organization: string; } export const createProject = async (data: CreateProjectInput) => { try { - const { - projectName, - projectUuid, - userId, - thumbnail, - sharedUsers, - organization, - } = data; + const { userId, thumbnail, sharedUsers, organization, projectUuid } = data; const userExisting = await existingUser(userId, organization); if (!userExisting) { return { @@ -42,7 +44,7 @@ export const createProject = async (data: CreateProjectInput) => { }; } const projectExisting = await existingProject( - projectName, + projectUuid, organization, userId ); @@ -53,9 +55,12 @@ export const createProject = async (data: CreateProjectInput) => { project: projectExisting, }; } - + const newProjectName = await generateUntitledProjectName( + organization, + userId + ); const project = await projectModel(organization).create({ - projectName: projectName, + projectName: newProjectName, projectUuid: projectUuid, createdBy: userId, thumbnail: thumbnail, @@ -95,14 +100,14 @@ export const GetAllProjects = async (data: GetProjectsInterface) => { .find({ isArchive: false, }) - .select("_id projectName createdBy thumbnail"); + .select("_id projectName createdBy thumbnail createdAt"); if (projectDatas) return { status: "Success", Datas: projectDatas }; } catch (error: unknown) { return { status: error }; } }; -export const DeleteProject = async (data: DeleteProjectInterface) => { +export const DeleteProject = async (data: ProjectInterface) => { try { const { projectId, organization, userId } = data; const ExistingUser = await existingUser(userId, organization); @@ -123,3 +128,63 @@ export const DeleteProject = async (data: DeleteProjectInterface) => { return { status: error }; } }; +export const updateProject = async (data: updateProjectInput) => { + try { + const { projectId, organization, userId, projectName, thumbnail } = data; + const ExistingUser = await existingUser(userId, organization); + if (!ExistingUser) return { status: "User not found" }; + const existingProject = await projectModel(organization).findOne({ + _id: projectId, + createdBy: userId, + isArchive: false, + }); + if (!existingProject) return { status: "Project not found" }; + if (projectName !== undefined) projectName; + if (thumbnail !== undefined) thumbnail; + const updateProject = await projectModel(organization) + .findOneAndUpdate( + { _id: projectId, isArchive: false }, + { projectName: projectName, thumbnail: thumbnail }, + { new: true } + ) + .select("_id projectName createdBy thumbnail createdAt"); + if (updateProject) return { status: "Success", data: updateProject }; + } catch (error: unknown) { + return { status: error }; + } +}; +const maxLength: number = 6; +export const viewProject = async (data: ProjectInterface) => { + try { + const { projectId, organization, userId } = data; + const userExisting = await existingUser(userId, organization); + if (!userExisting) return { status: "User not found" }; + const existingProject = await projectModel(organization).findOne({ + _id: projectId, + createdBy: userId, + isArchive: false, + }); + if (!existingProject) return { status: "Project not found" }; + const newArr = userExisting?.recentlyViewed || []; + if (userExisting?.recentlyViewed.length === 0) { + newArr.push(projectId); + } else { + const index = newArr.indexOf(projectId); + if (index !== -1) { + newArr.splice(index, 1); + } + newArr.unshift(projectId); + + if (newArr.length > maxLength) { + newArr.pop(); + } + } + await userExisting.updateOne( + { _id: userId, isArchive: false }, + { recentlyViewed: newArr } + ); + return { data: existingProject }; + } catch (error: unknown) { + return { status: error }; + } +}; diff --git a/src/shared/services/trash/trashService.ts b/src/shared/services/trash/trashService.ts index c1c1511..2976f95 100644 --- a/src/shared/services/trash/trashService.ts +++ b/src/shared/services/trash/trashService.ts @@ -48,12 +48,10 @@ export const TrashDatas = async (data: IOrg) => { export const RestoreTrashData = async (data: IRestore) => { try { const { projectId, organization } = data; - console.log("projectId: ", projectId); const findProject = await projectModel(organization).findOne({ _id: projectId, isArchive: true, }); - console.log("findProject: ", findProject); if (!findProject) return { status: "Project not found" }; const restoreData = await projectModel(organization).findOneAndUpdate( { _id: projectId, isArchive: true }, From 0e7db2af8db9173245fffdce1c88cf6d68ea2440 Mon Sep 17 00:00:00 2001 From: Nivetharamesh Date: Fri, 16 May 2025 12:25:00 +0530 Subject: [PATCH 7/7] RecentlyViewed API, view API, home page file added --- src/api-server/Routes/homepageRoutes.ts | 7 +++ src/api-server/app.ts | 14 +++--- .../controller/home/recentsControllers.ts | 46 +++++++++++++++++++ .../controller/project/projectController.ts | 2 + src/shared/model/project/project-model.ts | 2 + .../services/home/recentDatasService.ts | 34 ++++++++++++++ .../services/project/project-Services.ts | 20 ++++++-- 7 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 src/api-server/Routes/homepageRoutes.ts create mode 100644 src/api-server/controller/home/recentsControllers.ts create mode 100644 src/shared/services/home/recentDatasService.ts diff --git a/src/api-server/Routes/homepageRoutes.ts b/src/api-server/Routes/homepageRoutes.ts new file mode 100644 index 0000000..f84e818 --- /dev/null +++ b/src/api-server/Routes/homepageRoutes.ts @@ -0,0 +1,7 @@ +import * as express from "express"; +import { recentDataController } from "../controller/home/recentsControllers.ts"; + +const homePageRouter = express.Router(); + +homePageRouter.get("/RecentlyViewed/:userId/:organization", recentDataController); +export default homePageRouter; diff --git a/src/api-server/app.ts b/src/api-server/app.ts index aa446f2..c4cf874 100644 --- a/src/api-server/app.ts +++ b/src/api-server/app.ts @@ -21,11 +21,12 @@ import widget3dRoutes from "./Routes/widget3dRoutes.ts"; import productRouter from "./Routes/productRoutes.ts"; import projectRouter from "./Routes/projectRoutes.ts"; import trashRouter from "./Routes/trashRoutes.ts"; +import homePageRouter from "./Routes/homepageRoutes.ts"; // import productFlowRoutes from "./Routes/productFlowRouts.ts"; const app = express(); app.use(cors()); -// const allowedOriginsDev = [ +// const allowedOriginsDev = [ // "http://localhost:3000", // "http://192.168.0.183:8200", // "http://192.168.0.101:8200", @@ -45,11 +46,11 @@ app.use(cors()); // ) { // return callback(null, true); // } - + // if (typeof allowedOrigin === "string" && origin === allowedOrigin) { // return callback(null, true); // } - + // return callback(new Error("Not allowed by CORS")); // }, // credentials: true @@ -57,7 +58,7 @@ app.use(cors()); app.use(express.json({ limit: "50mb" })); app.use( - express.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 }) + express.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 }) ); dotenv.config(); app.get("/", (req, res) => { @@ -87,6 +88,7 @@ app.use("/api/v2", templateRoutes); app.use("/api/v2", widget3dRoutes); app.use("/api/v2", productRouter); // app.use("/api/v2", productFlowRoutes); -app.use("/api/v1",projectRouter) -app.use("/api/v1",trashRouter) +app.use("/api/v1", projectRouter); +app.use("/api/v1", trashRouter); +app.use("/api/v1", homePageRouter); export default app; diff --git a/src/api-server/controller/home/recentsControllers.ts b/src/api-server/controller/home/recentsControllers.ts new file mode 100644 index 0000000..34b43b3 --- /dev/null +++ b/src/api-server/controller/home/recentsControllers.ts @@ -0,0 +1,46 @@ +import { Request, Response } from "express"; +import { RecentlyAdded } from "../../../shared/services/home/recentDatasService.ts"; + +export const recentDataController = async ( + req: Request, + res: Response +): Promise => { + try { + const { userId, organization } = req.params; + if (!userId || !organization) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await RecentlyAdded({ userId, organization }); + + switch (result.status) { + case "User not found": + res.status(404).json({ + message: "User not found", + }); + break; + case "Datas were empty": + res.status(200).json({ + RecentlyViewed: [], + }); + break; + case "Success": + res.status(200).json({ + RecentlyViewed: 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/controller/project/projectController.ts b/src/api-server/controller/project/projectController.ts index a061d11..aa21ba9 100644 --- a/src/api-server/controller/project/projectController.ts +++ b/src/api-server/controller/project/projectController.ts @@ -186,6 +186,7 @@ export const updateProjectController = async ( }; export const ViewData = async (req: Request, res: Response): Promise => { try { + console.log("req.query: ", req.query); const { projectId, organization, userId } = req.query as { organization: string; projectId: string; @@ -202,6 +203,7 @@ export const ViewData = async (req: Request, res: Response): Promise => { organization, userId, }); + console.log("result: ", result); switch (result?.status) { case "Project not found": res.status(404).json({ diff --git a/src/shared/model/project/project-model.ts b/src/shared/model/project/project-model.ts index 09a8fd2..e3bf659 100644 --- a/src/shared/model/project/project-model.ts +++ b/src/shared/model/project/project-model.ts @@ -11,6 +11,7 @@ export interface Project extends Document { thumbnail: string; sharedUsers: []; DeletedAt: Date; + isViewed: number; total_versions: string; Present_version: string; } @@ -24,6 +25,7 @@ const projectSchema: Schema = new Schema( sharedUsers: [{ type: Schema.Types.ObjectId, ref: "user" }], DeletedAt: { type: Date, default: null }, isDeleted: { type: Boolean, default: false }, + isViewed: { type: Number }, total_versions: { type: String }, Present_version: { type: String }, }, diff --git a/src/shared/services/home/recentDatasService.ts b/src/shared/services/home/recentDatasService.ts new file mode 100644 index 0000000..b8a12d8 --- /dev/null +++ b/src/shared/services/home/recentDatasService.ts @@ -0,0 +1,34 @@ +import projectModel from "../../model/project/project-model.ts"; +import userModel from "../../model/user-Model.ts"; +import { existingUser } from "../helpers/ProjecthelperFn.ts"; + +interface IRecentData { + organization: string; + userId: string; +} +export const RecentlyAdded = async (data: IRecentData) => { + try { + const { userId, organization } = data; + const userExisting = await existingUser(userId, organization); + if (!userExisting) return { status: "User not found" }; + const userRecentData = await userModel(organization) + .findOne({ _id: userId }) + .populate({ + path: "recentlyViewed", + model: projectModel(organization), + select: "_id projectName createdBy thumbnail createdAt isViewed", + }); + let RecentDatas = []; + userRecentData.recentlyViewed.map(async (project: object) => { + console.log("project: ", typeof project); + const projectExisting = await projectModel(organization).findOne({ + _id: project, + isArchive: false, + }); + }); + if (!userRecentData) return { status: "Datas were empty" }; + return { status: "Success", data: userRecentData.recentlyViewed }; + } catch (error) { + return { status: error }; + } +}; diff --git a/src/shared/services/project/project-Services.ts b/src/shared/services/project/project-Services.ts index 85b7495..7a23cad 100644 --- a/src/shared/services/project/project-Services.ts +++ b/src/shared/services/project/project-Services.ts @@ -179,11 +179,23 @@ export const viewProject = async (data: ProjectInterface) => { newArr.pop(); } } - await userExisting.updateOne( - { _id: userId, isArchive: false }, - { recentlyViewed: newArr } + await userModel(organization).updateOne( + { _id: userId }, + { recentlyViewed: newArr }, + { new: true } ); - return { data: existingProject }; + const projectData = await projectModel(organization) + .findOneAndUpdate( + { + _id: projectId, + createdBy: userId, + isArchive: false, + }, + { isViewed: Date.now() }, + { new: true } + ) + .select("_id projectName createdBy thumbnail createdAt"); + return { status: "Success", data: projectData }; } catch (error: unknown) { return { status: error }; }