From 322db1911b762e98801fe89ffa8f6bbf2a20a328 Mon Sep 17 00:00:00 2001 From: Nivetharamesh Date: Mon, 1 Sep 2025 16:52:30 +0530 Subject: [PATCH] RBAC, jwt implemented in Projects,home and collections routing --- .env | 2 +- src/api-server/app.ts | 2 + src/api-server/controller/authController.ts | 2 - .../controller/collectionNodeController.ts | 122 +++++++----- .../controller/homePageController.ts | 45 +++++ .../controller/projectController.ts | 119 +++++++++++- src/api-server/routes/collectionRoutes.ts | 31 ++- src/api-server/routes/homeRoutes.ts | 8 + src/api-server/routes/projectRoutes.ts | 43 +++- src/shared/connection/redis.ts | 2 +- src/shared/middleware/rbacMiddleware.ts | 13 ++ src/shared/model/mvcModel.ts | 5 + src/shared/model/userModel.ts | 4 +- src/shared/services/AuthService.ts | 19 +- src/shared/services/collectionService.ts | 27 ++- src/shared/services/homePageService.ts | 51 +++++ src/shared/services/projectService.ts | 183 +++++++++--------- 17 files changed, 503 insertions(+), 175 deletions(-) create mode 100644 src/api-server/controller/homePageController.ts create mode 100644 src/api-server/routes/homeRoutes.ts create mode 100644 src/shared/middleware/rbacMiddleware.ts create mode 100644 src/shared/services/homePageService.ts diff --git a/.env b/.env index d9263e2..3725204 100644 --- a/.env +++ b/.env @@ -14,4 +14,4 @@ REDIS_PORT=6379 EMAIL_USER=nivetha@hexrfactory.com EMAIL_PASS=tikq fjry hzgr ootn -CLIENT_URL=http://192.168.0.104:9696 +CLIENT_URL=http://192.168.0.102:9696 diff --git a/src/api-server/app.ts b/src/api-server/app.ts index e774f86..b634cf1 100644 --- a/src/api-server/app.ts +++ b/src/api-server/app.ts @@ -5,6 +5,7 @@ import projectRoutes from "./routes/projectRoutes"; import collectionNodeRoutes from "./routes/collectionRoutes"; import edgeRoutes from "./routes/edgeRoutes"; import authRoutes from "./routes/authRoutes"; +import homeRoutes from "./routes/homeRoutes"; dotenv.config(); const app = express(); @@ -18,5 +19,6 @@ app.use("/api/v1", authRoutes); app.use("/api/v1", projectRoutes); app.use("/api/v1", collectionNodeRoutes); app.use("/api/v1", edgeRoutes); +app.use("/api/v1", homeRoutes); export default app; diff --git a/src/api-server/controller/authController.ts b/src/api-server/controller/authController.ts index 929994c..f614fd6 100644 --- a/src/api-server/controller/authController.ts +++ b/src/api-server/controller/authController.ts @@ -75,7 +75,6 @@ export const signinController = async ( password, }; const result = await signinService(data); - console.log("result: ", result); switch (result.status) { case "User not found!!! Kindly Signup": @@ -123,7 +122,6 @@ export const forgetPasswordController = async ( email, }; const result = await forgetPassword(data); - console.log("result: ", result); switch (result.status) { case "User not found!!! Kindly Signup": diff --git a/src/api-server/controller/collectionNodeController.ts b/src/api-server/controller/collectionNodeController.ts index 60938f8..554be3f 100644 --- a/src/api-server/controller/collectionNodeController.ts +++ b/src/api-server/controller/collectionNodeController.ts @@ -10,14 +10,15 @@ import { SetCollectionName, UpdateAttributes, } from "../../shared/services/collectionService"; - +import { AuthenticatedRequest } from "../../shared/utils/token"; export const NodeCreationController = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { organization, projectId, position } = req.body; - if (!organization || !projectId || !position) { + const { organization, userId } = req.user || {}; + const { projectId, position } = req.body; + if (!organization || !projectId || !position || !userId) { res.status(400).json({ message: "All fields are required", }); @@ -27,6 +28,7 @@ export const NodeCreationController = async ( organization, projectId, position, + userId, }; const result = await Nodecreation(data); @@ -59,19 +61,21 @@ export const NodeCreationController = async ( }); } }; + export const SetCollectionNameController = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { - organization, - projectId, - collectionNodeId, - collectionName, - position, - } = req.body; - if (!organization || !projectId || !collectionName || !collectionNodeId) { + const { organization, userId } = req.user || {}; + const { projectId, collectionNodeId, collectionName, position } = req.body; + if ( + !organization || + !projectId || + !userId || + !collectionName || + !collectionNodeId + ) { res.status(400).json({ message: "All fields are required", }); @@ -80,6 +84,7 @@ export const SetCollectionNameController = async ( const data = { organization, projectId, + userId, collectionNodeId, collectionName, position, @@ -114,13 +119,15 @@ export const SetCollectionNameController = async ( }); } }; + export const CollectionDatas = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { projectId, organization, collectionNodeId } = req.params; - if (!organization || !projectId || !collectionNodeId) { + const { organization, userId } = req.user || {}; + const { projectId, collectionNodeId } = req.params; + if (!organization || !projectId || !collectionNodeId || !userId) { res.status(400).json({ message: "All fields are required", }); @@ -129,6 +136,7 @@ export const CollectionDatas = async ( const data = { organization, projectId, + userId, collectionNodeId, }; const result = await GetcollectionNode(data); @@ -159,13 +167,15 @@ export const CollectionDatas = async ( }); } }; + export const DeleteCollectionsController = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { organization, projectId, collectionNodeId } = req.params; - if (!organization || !projectId || !collectionNodeId) { + const { organization, userId } = req.user || {}; + const { projectId, collectionNodeId } = req.params; + if (!organization || !projectId || !collectionNodeId || !userId) { res.status(400).json({ message: "All fields are required", }); @@ -174,6 +184,7 @@ export const DeleteCollectionsController = async ( const data = { organization, projectId, + userId, collectionNodeId, }; const result = await delCollection(data); @@ -203,15 +214,16 @@ export const DeleteCollectionsController = async ( }); } }; + export const DuplicateNodeCollectionController = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { + const { organization, userId } = req.user || {}; const { collectionNodeId } = req.params; - const { projectId, organization, collectionName, position, attributes } = - req.body; - if (!organization || !projectId || !collectionNodeId) { + const { projectId, collectionName, position, attributes } = req.body; + if (!organization || !projectId || !collectionNodeId || !userId) { res.status(400).json({ message: "All fields are required", }); @@ -220,6 +232,7 @@ export const DuplicateNodeCollectionController = async ( const data = { organization, projectId, + userId, collectionName, position, attributes, @@ -253,14 +266,14 @@ export const DuplicateNodeCollectionController = async ( } }; - export const NodesCollectionsBasedOnproject = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { projectId, organization } = req.params; - if (!organization || !projectId) { + const { organization, userId } = req.user || {}; + const { projectId } = req.params; + if (!organization || !projectId || !userId) { res.status(400).json({ message: "All fields are required", }); @@ -269,6 +282,7 @@ export const NodesCollectionsBasedOnproject = async ( const data = { organization, projectId, + userId, }; const result = await GetNodesInProject(data); switch (result.status) { @@ -300,13 +314,20 @@ export const NodesCollectionsBasedOnproject = async ( }; export const AddAttributesController = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { + const { organization, userId } = req.user || {}; const { collectionNodeId } = req.params; - const { organization, projectId, attributes } = req.body; - if (!organization || !projectId || !attributes || !collectionNodeId) { + const { projectId, attributes } = req.body; + if ( + !organization || + !projectId || + !attributes || + !userId || + !collectionNodeId + ) { res.status(400).json({ message: "All fields are required", }); @@ -315,6 +336,7 @@ export const AddAttributesController = async ( const data = { organization, projectId, + userId, collectionNodeId, attributes, }; @@ -347,23 +369,23 @@ export const AddAttributesController = async ( }); } }; + export const updateAttributesCollections = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { + const { organization, userId } = req.user || {}; const { collectionNodeId, attributeId } = req.params; - const { - organization, - projectId, - required, - defaultValue, - unique, - index, - key, - type, - } = req.body; - if (!organization || !projectId || !collectionNodeId || !attributeId) { + const { projectId, required, defaultValue, unique, index, key, type } = + req.body; + if ( + !organization || + !userId || + !projectId || + !collectionNodeId || + !attributeId + ) { res.status(400).json({ message: "All fields are required", }); @@ -372,6 +394,7 @@ export const updateAttributesCollections = async ( const data = { organization, projectId, + userId, collectionNodeId, attributeId, required, @@ -410,13 +433,20 @@ export const updateAttributesCollections = async ( }; export const delAttributesCollections = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { + const { organization, userId } = req.user || {}; const { collectionNodeId } = req.params; - const { organization, projectId, AttributeId } = req.body; - if (!organization || !projectId || !collectionNodeId || !AttributeId) { + const { projectId, AttributeId } = req.body; + if ( + !organization || + !projectId || + !collectionNodeId || + !AttributeId || + !userId + ) { res.status(400).json({ message: "All fields are required", }); @@ -424,6 +454,7 @@ export const delAttributesCollections = async ( } const data = { organization, + userId, projectId, collectionNodeId, AttributeId, @@ -456,4 +487,3 @@ export const delAttributesCollections = async ( }); } }; - diff --git a/src/api-server/controller/homePageController.ts b/src/api-server/controller/homePageController.ts new file mode 100644 index 0000000..82541cf --- /dev/null +++ b/src/api-server/controller/homePageController.ts @@ -0,0 +1,45 @@ +import { Request, Response } from "express"; +import { AuthenticatedRequest } from "../../shared/utils/token"; +import { recentlyViewedServices } from "../../shared/services/homePageService"; + +export const homePageRecentlyViewedController = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, userId } = req.user || {}; + if (!organization || !userId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + userId, + }; + const result = await recentlyViewedServices(data); + + switch (result.status) { + case "User not found": + res.status(403).json({ + message: "User not found", + }); + break; + case "Success": + res.status(200).json({ + datas: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; diff --git a/src/api-server/controller/projectController.ts b/src/api-server/controller/projectController.ts index 7a31df2..b8e7ada 100644 --- a/src/api-server/controller/projectController.ts +++ b/src/api-server/controller/projectController.ts @@ -1,9 +1,12 @@ import { Request, Response } from "express"; import { + DeleteProject, GetNodesInProject, projectCreationService, projectDatas, + ViewProjectService, } from "../../shared/services/projectService"; +import { AuthenticatedRequest } from "../../shared/utils/token"; export const projectCreationController = async ( req: Request, @@ -26,7 +29,8 @@ export const projectCreationController = async ( !projectName || !userId || !apiType || - !architecture|| !application + !architecture || + !application ) { res.status(400).json({ message: "All fields are required", @@ -37,7 +41,8 @@ export const projectCreationController = async ( organization, projectName, useableLanguage, - description,application, + description, + application, userId, apiType, architecture, @@ -85,18 +90,19 @@ export const projectCreationController = async ( }; export const getProjects = async ( - req: Request, + req: AuthenticatedRequest, res: Response ): Promise => { try { - const { organization } = req.body; - if (!organization) { + const { organization, userId } = req.user || {}; + if (!organization || !userId) { res.status(400).json({ message: "All fields are required", }); return; } - const result = await projectDatas(organization); + const result = await projectDatas({ organization, userId }); + console.log("result: ", result); switch (result.status) { case "No project found": @@ -104,7 +110,7 @@ export const getProjects = async ( break; case "Success": res.status(200).json({ - message: "Project created successfully", + // message: "Projec", projectDatas: result.data, }); break; @@ -121,7 +127,6 @@ export const getProjects = async ( } }; - export const NodesCollectionsBasedOnproject = async ( req: Request, res: Response @@ -165,4 +170,100 @@ export const NodesCollectionsBasedOnproject = async ( message: "Unknown error", }); } -}; \ No newline at end of file +}; + +export const accessAproject = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, userId } = req.user || {}; + const { projectId } = req.params; + if (!organization || !userId || !projectId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await ViewProjectService({ + organization, + userId, + projectId, + }); + + switch (result.status) { + case "No project found": + res.status(200).json({}); + break; + case "Datas not found": + res.status(200).json({ message: "Datas not found" }); + break; + case "Success": + res.status(200).json({ + projectDatas: result.data, + }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const deleteProjectController = async ( + req: AuthenticatedRequest, + res: Response +): Promise => { + try { + const { organization, userId } = req.user || {}; + const { projectId } = req.params; + if (!organization || !userId || !projectId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const result = await DeleteProject({ + organization, + userId, + projectId, + }); + + switch (result.status) { + case "User not found": + res.status(200).json({ message: "User not found" }); + break; + case "Project not found": + res.status(200).json({ message: "Project not found" }); + break; + case "No access granted to delete this project": + res + .status(200) + .json({ message: "No access granted to delete this project" }); + break; + case "Project Delete unsuccessfull": + res.status(200).json({ message: "Project Delete unsuccessfull" }); + break; + case "Success": + res.status(200).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/routes/collectionRoutes.ts b/src/api-server/routes/collectionRoutes.ts index f8453ca..766c531 100644 --- a/src/api-server/routes/collectionRoutes.ts +++ b/src/api-server/routes/collectionRoutes.ts @@ -10,49 +10,72 @@ import { SetCollectionNameController, updateAttributesCollections, } from "../controller/collectionNodeController"; +import { tokenValidator } from "../../shared/utils/token"; +import authorizedRoles from "../../shared/middleware/rbacMiddleware"; const collectionNodeRoutes = express.Router(); //Node creation -collectionNodeRoutes.post("/nodes", NodeCreationController); +collectionNodeRoutes.post( + "/nodes", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), + NodeCreationController +); //collection Added collectionNodeRoutes.patch( "/nodes/collectionName", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), SetCollectionNameController ); //duplicate collection collectionNodeRoutes.post( "/nodes/:collectionNodeId/duplicate", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), DuplicateNodeCollectionController ); //particular collection data collectionNodeRoutes.get( - "/nodes/:organization/:projectId/:collectionNodeId", + "/nodes/:projectId/:collectionNodeId", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), CollectionDatas ); //delete collection collectionNodeRoutes.patch( - "/nodes/:organization/:projectId/:collectionNodeId", + "/nodes/:projectId/:collectionNodeId", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), DeleteCollectionsController ); //Add fields collectionNodeRoutes.patch( "/nodes/:collectionNodeId/attributes", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), AddAttributesController ); //Collections and fiels based on the project collectionNodeRoutes.get( - "/nodes/:organization/:projectId", + "/nodes//:projectId", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), NodesCollectionsBasedOnproject ); //update fields collectionNodeRoutes.patch( "/nodes/:collectionNodeId/attributes/:attributeId", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), updateAttributesCollections ); //delete fields collectionNodeRoutes.patch( "/nodes/:collectionNodeId/attributes/softDelete", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), delAttributesCollections ); export default collectionNodeRoutes; diff --git a/src/api-server/routes/homeRoutes.ts b/src/api-server/routes/homeRoutes.ts new file mode 100644 index 0000000..5012e21 --- /dev/null +++ b/src/api-server/routes/homeRoutes.ts @@ -0,0 +1,8 @@ +import express from "express"; +import { homePageRecentlyViewedController } from "../controller/homePageController"; +import { tokenValidator } from "../../shared/utils/token"; +import authorizedRoles from "../../shared/middleware/rbacMiddleware"; +const homeRoutes = express.Router(); + +homeRoutes.get("/home",tokenValidator,authorizedRoles("Admin","Editor","Viewer"), homePageRecentlyViewedController); +export default homeRoutes; diff --git a/src/api-server/routes/projectRoutes.ts b/src/api-server/routes/projectRoutes.ts index da4628a..4265c75 100644 --- a/src/api-server/routes/projectRoutes.ts +++ b/src/api-server/routes/projectRoutes.ts @@ -1,12 +1,47 @@ -import express from "express"; -import { NodesCollectionsBasedOnproject, projectCreationController } from "../controller/projectController"; +import express, { Response, NextFunction } from "express"; +import { AuthenticatedRequest } from "../../shared/utils/token"; +import { + accessAproject, + getProjects, + NodesCollectionsBasedOnproject, + projectCreationController, +} from "../controller/projectController"; +import authorizedRoles from "../../shared/middleware/rbacMiddleware"; +import { tokenValidator } from "../../shared/utils/token"; const projectRoutes = express.Router(); -projectRoutes.post("/Newproject", projectCreationController); +projectRoutes.post( + "/Newproject", + tokenValidator, + authorizedRoles("Admin", "Editor"), + projectCreationController +); projectRoutes.get( "/nodes/:organization/:projectId", + tokenValidator, + authorizedRoles("Viewer", "Admin", "Editor"), NodesCollectionsBasedOnproject ); -// appRoutes.post("/createfileModel", fileModelCreatecontroller); + +projectRoutes.get( + "/Allprojects/:organization", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), + getProjects +); + +projectRoutes.get( + "/Aproject/:projectId", + tokenValidator, + authorizedRoles("Admin", "Editor", "Viewer"), + accessAproject +); + +projectRoutes.put( + "/node/deleteproject/:projectId", + tokenValidator, + authorizedRoles("Admin", "Editor"), + accessAproject +); export default projectRoutes; diff --git a/src/shared/connection/redis.ts b/src/shared/connection/redis.ts index 8baf22a..3998da0 100644 --- a/src/shared/connection/redis.ts +++ b/src/shared/connection/redis.ts @@ -1,6 +1,6 @@ import Redis from "ioredis"; import * as dotenv from "dotenv"; -dotenv.config({quiet:true}); +dotenv.config({}); const redis = new Redis({ host: process.env.REDIS_ENV === "true" diff --git a/src/shared/middleware/rbacMiddleware.ts b/src/shared/middleware/rbacMiddleware.ts new file mode 100644 index 0000000..bed5380 --- /dev/null +++ b/src/shared/middleware/rbacMiddleware.ts @@ -0,0 +1,13 @@ +import { Response, NextFunction } from "express"; +import { AuthenticatedRequest } from "../../shared/utils/token"; +type Role = "Admin" | "Viewer" | "Editor"; +const authorizedRoles = (...allowedRoles: Role[]) => { + return (req: AuthenticatedRequest, res: Response, next: NextFunction) => { + if (!req.user || !allowedRoles.includes(req.user.role as Role)) { + res.status(403).json({ message: "Access Denied" }); + return; + } + next(); + }; +}; +export default authorizedRoles; diff --git a/src/shared/model/mvcModel.ts b/src/shared/model/mvcModel.ts index 49ac3bf..52262a4 100644 --- a/src/shared/model/mvcModel.ts +++ b/src/shared/model/mvcModel.ts @@ -12,6 +12,11 @@ const folderSchema: Schema = new Schema({ export interface IMVCPrject extends Document { projectId: IProject["_id"]; controllers: boolean; + // env:boolean; + // src:boolean; + // package_json:boolean; + // node_modules:boolean; + // gitignore:boolean; routes: boolean; models: boolean; services: boolean; diff --git a/src/shared/model/userModel.ts b/src/shared/model/userModel.ts index f032971..2fc5101 100644 --- a/src/shared/model/userModel.ts +++ b/src/shared/model/userModel.ts @@ -15,8 +15,8 @@ const UserSchema: Schema = new Schema({ }, role: { type: String, - default: "User", - enum: ["User", "Admin"], + default: "Viewer", + enum: ["Editor", "Admin", "Viewer"], }, email: { type: String, diff --git a/src/shared/services/AuthService.ts b/src/shared/services/AuthService.ts index 80fa5f0..7b4fa7d 100644 --- a/src/shared/services/AuthService.ts +++ b/src/shared/services/AuthService.ts @@ -1,11 +1,10 @@ import redis from "../connection/redis"; import tokenModel from "../model/tokenModel"; import nodemailer from "nodemailer"; - import userModel from "../model/userModel"; import { hashGenerate, hashValidator } from "../utils/hashing"; import { tokenGenerator, tokenRefreshGenerator } from "../utils/token"; -import { text } from "body-parser"; +import userDataModel from "../model/userDataModel"; interface Iresponse { status: string; @@ -45,7 +44,7 @@ export const signupService = async (data: Isignup): Promise => { let role; const passwordHashed = await hashGenerate(password); const userCount = await userModel(organization).countDocuments({}); - role = userCount === 0 ? "Admin" : "User"; + role = userCount === 0 ? "Admin" : "Viewer"; const newUser = await userModel(organization).create({ userName, email: mailCaseChange, @@ -81,6 +80,15 @@ export const signinService = async (data: Isignin): Promise => { ); if (!comparePassword) return { status: "Password is invalid...Check the credentials" }; + const userDataExistence = await userDataModel(organization).findOne({ + userId: mailExistance._id, + isArchive: false, + }); + if (!userDataExistence) { + const userDatacreation = await userDataModel(organization).create({ + userId: mailExistance._id, + }); + } const tokenValidation = tokenGenerator( mailExistance.email, mailExistance.role, @@ -145,13 +153,10 @@ export const forgetPassword = async ({ email, }: IforGotPassword): Promise<{ status: string }> => { try { - console.log("hi forgetpassword"); const mailCaseChange = email.toLocaleLowerCase(); const organization = email.split("@")[1].split(".")[0]; const Existing_User = await existingUserData(mailCaseChange, organization); - console.log("Existing_User: ", Existing_User); if (Existing_User) { - console.log("if"); // if (Existing_User.lastPasswordReset) { // console.log("if2"); // const lastPasswordReset = Existing_User.lastPasswordReset; @@ -163,8 +168,6 @@ export const forgetPassword = async ({ // status: "You can only reset your password once every 24 hours.", // }; // } - console.log("process.env.EMAIL_USER: ", process.env.EMAIL_USER); - console.log("process.env.EMAIL_PASS: ", process.env.EMAIL_PASS); const transport = nodemailer.createTransport({ service: "gmail", secure: true, diff --git a/src/shared/services/collectionService.ts b/src/shared/services/collectionService.ts index d664aa8..1430a48 100644 --- a/src/shared/services/collectionService.ts +++ b/src/shared/services/collectionService.ts @@ -7,6 +7,7 @@ interface Iresponse { } interface IcollectionNode { projectId: string; + userId: string; organization: string; position: [number]; } @@ -16,6 +17,7 @@ interface IAttribute { } interface IcollectionNodeName { projectId: string; + userId: string; organization: string; collectionNodeId: string; collectionName: string; @@ -23,21 +25,25 @@ interface IcollectionNodeName { } interface IcollectionAttributes { projectId: string; + userId: string; organization: string; collectionNodeId: string; attributes: IAttribute[]; } interface IcollectionNodes { projectId: string; + userId: string; organization: string; } interface IcollectionNodeById { projectId: string; organization: string; + userId: string; collectionNodeId: string; } interface IAttributesEdit { projectId: string; + userId: string; organization: string; collectionNodeId: string; attributeId: string; @@ -50,6 +56,7 @@ interface IAttributesEdit { } interface IAttributesDel { projectId: string; + userId: string; organization: string; collectionNodeId: string; AttributeId: string; @@ -57,10 +64,12 @@ interface IAttributesDel { interface ICollectionDelete { projectId: string; organization: string; + userId: string; collectionNodeId: string; } interface IDuplicateCollectionNode { projectId: string; + userId: string; collectionNodeId: string; organization: string; collectionName: string; @@ -71,7 +80,7 @@ interface IDuplicateCollectionNode { export const Nodecreation = async ( data: IcollectionNode ): Promise => { - const { organization, projectId, position } = data; + const { organization, projectId, position, userId } = data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, @@ -111,6 +120,7 @@ export const SetCollectionName = async ( position, collectionNodeId, collectionName, + userId, } = data; try { const existingProject = await ProjectType(organization).findOne({ @@ -157,7 +167,8 @@ export const SetCollectionName = async ( export const addAttributes = async ( data: IcollectionAttributes ): Promise => { - const { organization, projectId, collectionNodeId, attributes } = data; + const { organization, projectId, userId, collectionNodeId, attributes } = + data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, @@ -218,7 +229,7 @@ export const addAttributes = async ( export const GetNodesInProject = async ( data: IcollectionNodes ): Promise => { - const { organization, projectId } = data; + const { organization, userId, projectId } = data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, @@ -264,6 +275,7 @@ export const UpdateAttributes = async ( ): Promise => { const { organization, + userId, projectId, collectionNodeId, attributeId, @@ -329,7 +341,8 @@ export const UpdateAttributes = async ( export const DelAttributes = async ( data: IAttributesDel ): Promise => { - const { organization, projectId, collectionNodeId, AttributeId } = data; + const { organization, userId, projectId, collectionNodeId, AttributeId } = + data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, @@ -383,7 +396,7 @@ export const DelAttributes = async ( export const delCollection = async ( data: ICollectionDelete ): Promise => { - const { organization, projectId, collectionNodeId } = data; + const { organization, userId, projectId, collectionNodeId } = data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, @@ -429,7 +442,7 @@ export const delCollection = async ( export const GetcollectionNode = async ( data: IcollectionNodeById ): Promise => { - const { organization, projectId, collectionNodeId } = data; + const { organization, userId, projectId, collectionNodeId } = data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, @@ -499,7 +512,7 @@ const generateUniqueCollectionName = async ( export const DuplicateCollection = async ( data: IDuplicateCollectionNode ): Promise => { - const { organization, projectId, position, collectionNodeId } = data; + const { organization, userId, projectId, position, collectionNodeId } = data; try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, diff --git a/src/shared/services/homePageService.ts b/src/shared/services/homePageService.ts new file mode 100644 index 0000000..4a6332a --- /dev/null +++ b/src/shared/services/homePageService.ts @@ -0,0 +1,51 @@ +import ProjectType from "../../shared/model/projectmodel"; +import userDataModel from "../model/userDataModel"; +import userModel from "../model/userModel"; + +interface IrecentlyViewed { + organization: string; + userId: string; +} +interface Iresponse { + status: string; + data?: any; +} +export const recentlyViewedServices = async ( + data: IrecentlyViewed +): Promise => { + const { organization, userId } = data; + try { + const ExistingUser = await userModel(organization).findOne({ + _id: userId, + isArchive: false, + }); + if (!ExistingUser) return { status: "User not found" }; + const userDatas = await userDataModel(organization) + .findOne({ userId: userId, isArchive: false }) + .select("recentlyViewed userId"); + const populatedProjects = userDatas.recentlyViewed; + const RecentDatas = await Promise.all( + populatedProjects.map(async (projectId: any) => { + const projectExisting = await ProjectType(organization) + .findOne({ + _id: projectId, + isArchive: false, + }) + .select("_id projectName createdBy thumbnail createdAt isViewed"); + return projectExisting; + }) + ); + const filteredProjects = RecentDatas.filter(Boolean); + return { status: "Success", data: filteredProjects }; + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; diff --git a/src/shared/services/projectService.ts b/src/shared/services/projectService.ts index 39813d2..ef9e76c 100644 --- a/src/shared/services/projectService.ts +++ b/src/shared/services/projectService.ts @@ -29,6 +29,11 @@ interface IProjectstructure { organization: string; } +interface IgetProject { + organization: string; + userId: string; +} + export const projectCreationService = async ( data: IProject ): Promise => { @@ -43,6 +48,10 @@ export const projectCreationService = async ( architecture, } = data; try { + const ExistingUser = await userModel(organization).findOne({ + _id: userId, + isArchive: false, + }); const existingProject = await ProjectType(organization).findOne({ projectName: projectName, createdBy: userId, @@ -121,13 +130,30 @@ export const projectCreationService = async ( } }; -export const projectDatas = async (data: IProject): Promise => { - const { organization } = data; +export const projectDatas = async (data: IgetProject): Promise => { + const { organization, userId } = data; try { + const ExistingUser = await userModel(organization).findOne({ + _id: userId, + isArchive: false, + }); + let query: any = { isArchive: false }; + if (ExistingUser.role === "Editor") { + query = { + ...query, + $or: [{ createdBy: userId }, { members: userId }], + }; + } else if (ExistingUser.role === "Viewer") { + query = { + ...query, + members: userId, + }; + } else { + query; + } + console.log("query: ", query); const projectDatas = await ProjectType(organization) - .findOne({ - isArchive: false, - }) + .find(query) .select("-__v -isArchive -createdAt -updatedAt"); if (!projectDatas) return { status: "No project found" }; return { status: "Success", data: projectDatas }; @@ -197,14 +223,41 @@ export const ViewProjectService = async ( ): Promise => { const { organization, projectId, userId } = data; try { + const ExistingUser = await userModel(organization).findOne({ + _id: userId, + isArchive: false, + }); + let query: any = { _id: projectId, isArchive: false }; const RecentUserDoc = await userDataModel(organization).findOne({ userId: userId, isArchive: false, }); - const existingProject = await ProjectType(organization).findOne({ - _id: projectId, - isArchive: false, - }); + + if (ExistingUser.role === "Editor") { + query = { + ...query, + $or: [{ createdBy: userId }, { members: userId }], + }; + } else if (ExistingUser.role === "Viewer") { + query = { + ...query, + members: userId, + }; + } else { + query; + } + const projectData = await ProjectType(organization) + .findOne(query) + .populate({ + path: "createdBy", + model: userModel(organization), + select: "userName", + }) + .select("_id projectName createdBy"); + console.log("projectData: ", projectData); + if (projectData === null) { + return { status: "Datas not found" }; + } const newArr = RecentUserDoc?.recentlyViewed || []; if (RecentUserDoc?.recentlyViewed.length === 0) { newArr.push(projectId); @@ -225,18 +278,8 @@ export const ViewProjectService = async ( { recentlyViewed: newArr }, { new: true } ); - const projectData = await ProjectType(organization) - .findOne({ - _id: projectId, - isArchive: false, - }) - .populate({ - path: "createdBy", - model: userModel(organization), - select: "userName", - }) - .select("_id projectName createdBy"); - return { status: "Success", data: projectData }; + + return { status: "Success", data: projectData || [] }; } catch (error: unknown) { if (error instanceof Error) { return { @@ -250,7 +293,7 @@ export const ViewProjectService = async ( } }; -export const DeleteProject = async (data: IProjectView) => { +export const DeleteProject = async (data: IProjectView): Promise => { try { const { projectId, organization, userId } = data; const ExistingUser = await userModel(organization).findOne({ @@ -259,82 +302,40 @@ export const DeleteProject = async (data: IProjectView) => { }); if (!ExistingUser) return { status: "User not found" }; - let filter = { + let query: any = { _id: projectId, - createdBy: userId, isArchive: false, }; - const existingProject = await ProjectType(organization).findOne(filter); + const existingProject = await ProjectType(organization).findOne(query); if (!existingProject) return { status: "Project not found" }; - const updateProject = await ProjectType(organization).findOneAndUpdate( - filter, + + if (ExistingUser.role === "Editor") { + query = { + ...query, + $or: [{ createdBy: userId }, { members: userId }], + }; + } else if (ExistingUser.role === "Admin") { + query; + } else { + return { status: "No access granted to delete this project" }; + } + + const deleteProject = await ProjectType(organization).findOneAndUpdate( + query, { isArchive: true }, { new: true } ); - await shareModel(organization).updateMany( - { projectId: projectId, isArchive: false }, - { isArchive: true } - ); - if (updateProject) return { status: "Success" }; + if(!deleteProject) return {status:"Project Delete unsuccessfull"} + return { status: "Success" }; } catch (error: unknown) { - return { status: error }; + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } } }; - -// export const ViewProjectService = async ( -// data: IProjectView -// ): Promise => { -// const { organization, projectId, userId } = data; -// try { -// const RecentUserDoc = await userDataModel(organization).findOne({ -// userId: userId, -// isArchive: false, -// }); -// const existingProject = await ProjectType(organization).findOne({ -// _id: projectId, -// isArchive: false, -// }); -// const newArr = RecentUserDoc?.recentlyViewed || []; -// if (RecentUserDoc?.recentlyViewed.length === 0) { -// newArr.push(projectId); -// await RecentUserDoc.save(); -// } else { -// const index = newArr.indexOf(projectId); -// if (index !== -1) { -// newArr.splice(index, 1); -// } -// newArr.unshift(projectId); - -// if (newArr.length > maxLength) { -// newArr.pop(); -// } -// } -// await userDataModel(organization).findOneAndUpdate( -// { userId: userId, isArchive: false }, -// { recentlyViewed: newArr }, -// { new: true } -// ); -// const projectData = await ProjectType(organization) -// .findOne({ -// _id: projectId, -// isArchive: false, -// }) -// .populate({ -// path: "createdBy", -// model: userModel(organization), -// select: "userName", -// }) -// .select("_id projectName createdBy"); -// return { status: "Success", data: projectData }; -// } catch (error: unknown) { -// if (error instanceof Error) { -// return { -// status: error.message, -// }; -// } else { -// return { -// status: "An unexpected error occurred", -// }; -// } -// } -// };