diff --git a/src/api-server/controller/collectionNodeController.ts b/src/api-server/controller/collectionNodeController.ts index db3a702..1fbdfce 100644 --- a/src/api-server/controller/collectionNodeController.ts +++ b/src/api-server/controller/collectionNodeController.ts @@ -1,8 +1,14 @@ import { Request, Response } from "express"; import { addAttributes, + DelAttributes, + delCollection, + DuplicateCollection, + GetcollectionNode, + GetNodesInProject, Nodecreation, SetCollectionName, + UpdateAttributes, } from "../../shared/services/collectionService"; export const NodeCreationController = async ( @@ -23,7 +29,7 @@ export const NodeCreationController = async ( position, }; const result = await Nodecreation(data); - console.log('result: ', result); + console.log("result: ", result); switch (result.status) { case "project not found": @@ -54,7 +60,6 @@ export const NodeCreationController = async ( }); } }; - export const SetCollectionNameController = async ( req: Request, res: Response @@ -110,14 +115,12 @@ export const SetCollectionNameController = async ( }); } }; - export const AddAttributesController = async ( req: Request, res: Response ): Promise => { try { const { organization, projectId, collectionNodeId, attributes } = req.body; - console.log('req.body: ', req.body); if (!organization || !projectId || !attributes || !collectionNodeId) { res.status(400).json({ message: "All fields are required", @@ -131,7 +134,6 @@ export const AddAttributesController = async ( attributes, }; const result = await addAttributes(data); - switch (result.status) { case "project not found": res.status(200).json({ @@ -145,7 +147,7 @@ export const AddAttributesController = async ( break; case "Success": res.status(200).json({ - message: "collection name updated", + message: "collection Attributes Added", }); break; default: @@ -160,3 +162,304 @@ export const AddAttributesController = async ( }); } }; + +export const NodesCollectionsBasedOnproject = async ( + req: Request, + res: Response +): Promise => { + try { + const { projectId, organization } = req.params; + if (!organization || !projectId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + projectId, + }; + const result = await GetNodesInProject(data); + switch (result.status) { + case "project not found": + res.status(200).json({ + message: "project not found", + }); + break; + case "No collection Nodes present": + res.status(200).json({ + message: "No collection Nodes present", + Collections: result.data, + }); + break; + case "Success": + res.status(200).json({ Collections: result.data }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const updateAttributesCollections = async ( + req: Request, + res: Response +): Promise => { + try { + const { + organization, + projectId, + collectionNodeId, + AttributeId, + required, + defaultValue, + unique, + index, + key, + type, + } = req.body; + if (!organization || !projectId || !collectionNodeId || !AttributeId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + projectId, + collectionNodeId, + AttributeId, + required, + defaultValue, + unique, + index, + key, + type, + }; + const result = await UpdateAttributes(data); + switch (result.status) { + case "project not found": + res.status(200).json({ + message: "project not found", + }); + break; + case "Collection not found": + res.status(200).json({ + message: "Collection not found", + }); + break; + case "Success": + res.status(200).json({ message: "Field updated successfully" }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const delAttributesCollections = async ( + req: Request, + res: Response +): Promise => { + try { + const { organization, projectId, collectionNodeId, AttributeId } = req.body; + if (!organization || !projectId || !collectionNodeId || !AttributeId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + projectId, + collectionNodeId, + AttributeId, + }; + const result = await DelAttributes(data); + console.log("result: ", result); + switch (result.status) { + case "project not found": + res.status(200).json({ + message: "project not found", + }); + break; + case "Collection not found": + res.status(200).json({ + message: "Collection not found", + Collections: result.data, + }); + break; + case "Success": + res.status(200).json({ message: "Field deleted successfully" }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; + +export const CollectionDatas = async ( + req: Request, + res: Response +): Promise => { + try { + const { projectId, organization, collectionNodeId } = req.params; + if (!organization || !projectId || !collectionNodeId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + projectId, + collectionNodeId, + }; + const result = await GetcollectionNode(data); + switch (result.status) { + case "project not found": + res.status(200).json({ + message: "project not found", + }); + break; + case "No collection Nodes present": + res.status(200).json({ + message: "No collection Nodes present", + Collections: result.data, + }); + break; + case "Success": + res.status(200).json(result.data); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const DeleteCollectionsController = async ( + req: Request, + res: Response +): Promise => { + try { + const { organization, projectId, collectionNodeId } = req.params; + if (!organization || !projectId || !collectionNodeId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + projectId, + collectionNodeId, + }; + const result = await delCollection(data); + switch (result.status) { + case "project not found": + res.status(200).json({ + message: "project not found", + }); + break; + case "Collection not found": + res.status(200).json({ + message: "Collection not found", + }); + break; + case "Success": + res.status(200).json({ message: "Collection deleted successfully" }); + break; + default: + res.status(500).json({ + message: "Internal server error", + }); + break; + } + } catch (error) { + res.status(500).json({ + message: "Unknown error", + }); + } +}; +export const DuplicateNodeCollectionController = async ( + req: Request, + res: Response +): Promise => { + try { + const { + projectId, + organization, + collectionName, + position, + collectionNodeId, + attributes, + } = req.body; + console.log("req.body;: ", req.body); + if (!organization || !projectId || !collectionNodeId) { + res.status(400).json({ + message: "All fields are required", + }); + return; + } + const data = { + organization, + projectId, + collectionName, + position, + attributes, + collectionNodeId, + }; + const result = await DuplicateCollection(data); + switch (result.status) { + case "project not found": + res.status(200).json({ + message: "project not found", + }); + break; + case "Duplication unsuccessfull": + res.status(200).json({ + message: "Duplication unsuccessfull", + }); + break; + case "Success": + res.status(200).json({ message: "Duplicated 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/projectController.ts b/src/api-server/controller/projectController.ts index bbaee31..edcbe5f 100644 --- a/src/api-server/controller/projectController.ts +++ b/src/api-server/controller/projectController.ts @@ -15,6 +15,7 @@ export const projectCreationController = async ( projectName, userName, apiType, + application, architecture, description, } = req.body; @@ -24,7 +25,7 @@ export const projectCreationController = async ( !projectName || !userName || !apiType || - !architecture + !architecture|| !application ) { res.status(400).json({ message: "All fields are required", @@ -35,7 +36,7 @@ export const projectCreationController = async ( organization, projectName, useableLanguage, - description, + description,application, userName, apiType, architecture, diff --git a/src/api-server/routes/collectionRoutes.ts b/src/api-server/routes/collectionRoutes.ts index 54490c7..ca32ed8 100644 --- a/src/api-server/routes/collectionRoutes.ts +++ b/src/api-server/routes/collectionRoutes.ts @@ -1,13 +1,46 @@ import express from "express"; import { AddAttributesController, + CollectionDatas, + delAttributesCollections, + DeleteCollectionsController, + DuplicateNodeCollectionController, NodeCreationController, + NodesCollectionsBasedOnproject, SetCollectionNameController, + updateAttributesCollections, } from "../controller/collectionNodeController"; const collectionNodeRoutes = express.Router(); - +//Node creation collectionNodeRoutes.post("/NewNode", NodeCreationController); +//collection Added collectionNodeRoutes.patch("/collectionName", SetCollectionNameController); +//duplicate collection +collectionNodeRoutes.post( + "/duplicateCollection", + DuplicateNodeCollectionController +); +//particular collection data +collectionNodeRoutes.get( + "/collectionNodeById/:projectId/:collectionNodeId/:organization", + CollectionDatas +); +//delete collection +collectionNodeRoutes.patch( + "/delCollection/:projectId/:collectionNodeId/:organization", + DeleteCollectionsController +); + +//Add fields collectionNodeRoutes.patch("/AddAttributes", AddAttributesController); +//Collections and fiels based on the project +collectionNodeRoutes.get( + "/collectionNodes/:projectId/:organization", + NodesCollectionsBasedOnproject +); +//update fields +collectionNodeRoutes.patch("/Attributeupdate", updateAttributesCollections); +//delete fields +collectionNodeRoutes.patch("/softDelAttribute", delAttributesCollections); export default collectionNodeRoutes; diff --git a/src/shared/connection/connection.ts b/src/shared/connection/connection.ts index ac2c857..6a76248 100644 --- a/src/shared/connection/connection.ts +++ b/src/shared/connection/connection.ts @@ -13,7 +13,6 @@ const MainModel = ( collectionName: string ): Model => { const db1_url = `${process.env.MONGO_URI}${db}`; - console.log('process.env.MONGO_URI: ', process.env.MONGO_URI); const authOptions = { user: process.env.MONGO_USER, pass: process.env.MONGO_PASSWORD, diff --git a/src/shared/model/projectmodel.ts b/src/shared/model/projectmodel.ts index b9e9d03..9446d48 100644 --- a/src/shared/model/projectmodel.ts +++ b/src/shared/model/projectmodel.ts @@ -2,6 +2,7 @@ import { Schema, Document } from "mongoose"; import MainModel from "../connection/connection"; export interface IProject extends Document { projectName: string; + appType: string; slug: string; isArchive: boolean; createdBy: string; @@ -16,6 +17,7 @@ export interface IProject extends Document { const projectSchema: Schema = new Schema( { projectName: { type: String }, + appType:{type:String,enum:["Backend","Frontend"]}, slug: { type: String }, isArchive: { type: Boolean, default: false }, createdBy: { type: String }, diff --git a/src/shared/services/collectionService.ts b/src/shared/services/collectionService.ts index 3aad469..d915ee6 100644 --- a/src/shared/services/collectionService.ts +++ b/src/shared/services/collectionService.ts @@ -1,3 +1,4 @@ +import mongoose from "mongoose"; import ProjectType from "../../shared/model/projectmodel"; import collectionsModel from "../model/collectionModel"; interface Iresponse { @@ -26,6 +27,47 @@ interface IcollectionAttributes { collectionNodeId: string; attributes: IAttribute[]; } +interface IcollectionNodes { + projectId: string; + organization: string; +} +interface IcollectionNodeById { + projectId: string; + organization: string; + collectionNodeId: string; +} +interface IAttributesEdit { + projectId: string; + organization: string; + collectionNodeId: string; + AttributeId: string; + key?: string; + type?: string; + required?: boolean; + defaultValue?: any; + unique?: boolean; + index?: boolean; +} +interface IAttributesDel { + projectId: string; + organization: string; + collectionNodeId: string; + AttributeId: string; +} +interface ICollectionDelete { + projectId: string; + organization: string; + collectionNodeId: string; +} +interface IDuplicateCollectionNode { + projectId: string; + collectionNodeId: string; + organization: string; + collectionName: string; + position: [number]; + attributes: []; +} + export const Nodecreation = async ( data: IcollectionNode ): Promise => { @@ -33,7 +75,6 @@ export const Nodecreation = async ( try { const existingProject = await ProjectType(organization).findOne({ _id: projectId, - // createdBy: userName, isArchive: false, }); if (!existingProject) { @@ -138,12 +179,12 @@ export const addAttributes = async ( const updatedAttributesMap = new Map(); for (const attr of existingAttributes) { - updatedAttributesMap.set(attr.key, attr); + updatedAttributesMap.set(attr.key, attr.type.toLocaleLowerCase()); } for (const attr of newAttributes) { if (!updatedAttributesMap.has(attr.key)) { - updatedAttributesMap.set(attr.key, attr); + updatedAttributesMap.set(attr.key, attr.type.toLocaleLowerCase()); } } @@ -174,86 +215,347 @@ export const addAttributes = async ( } }; -// const attrToSchema = (attr: any): string => { -// const lines: string[] = []; -// // console.log('lines: ', lines); +export const GetNodesInProject = async ( + data: IcollectionNodes +): Promise => { + const { organization, projectId } = data; + try { + const existingProject = await ProjectType(organization).findOne({ + _id: projectId, + isArchive: false, + }); + if (!existingProject) { + return { status: "project not found" }; + } else { + const collectionNodes = await collectionsModel(organization) + .find({ projectId: projectId, isArchive: false }) + .select("collectionNodeName attributes position -_id "); + if (!collectionNodes) + return { status: "No collection Nodes present", data: [] }; + else { + const formattedCollections = collectionNodes.map((collection) => ({ + position: collection.position, + collectionNodeName: collection.collectionNodeName, + attributes: collection.attributes + .filter((attr: any) => !attr.isArchive) + .map((attr: any) => { + const { isArchive, ...rest } = attr.toObject(); + return { ...rest }; + }), + })); + return { status: "Success", data: formattedCollections }; + } + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; -// for (const [key, config] of Object.entries(attr)) { -// const cfg: any = config; -// let typeValue = cfg.type; -// const line: string[] = []; +export const UpdateAttributes = async ( + data: IAttributesEdit +): Promise => { + const { + organization, + projectId, + collectionNodeId, + AttributeId, + required, + defaultValue, + unique, + index, + key, + type, + } = data; + try { + const existingProject = await ProjectType(organization).findOne({ + _id: projectId, + isArchive: false, + }); + if (!existingProject) { + return { status: "project not found" }; + } else { + const existingCollection = await collectionsModel(organization).findOne({ + projectId: projectId, + _id: collectionNodeId, + isArchive: false, + }); + if (!existingCollection) return { status: "Collection not found" }; -// if (!typeValue && config !== null && typeof config === "object") { -// const nestedLines: string[] = []; + const editCollection = await collectionsModel( + organization + ).findOneAndUpdate( + { + projectId: projectId, + isArchive: false, + attributes: { + $elemMatch: { _id: new mongoose.Types.ObjectId(AttributeId) }, + }, + }, + { + $set: { + "attributes.$.required": required, + "attributes.$.default": defaultValue, + "attributes.$.index": index, + "attributes.$.unique": unique, + "attributes.$.key": key, + "attributes.$.type": type, + }, + }, + { new: true } + ); + console.log("editCollection: ", editCollection); + return { status: "Success" }; + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; -// for (const [nestedKey, nestedConfig] of Object.entries(config)) { -// const nestedCfg: any = nestedConfig; -// const nestedLine: string[] = []; -// nestedLine.push(`${nestedKey}: {`); -// nestedLine.push(` type: ${nestedCfg.type},`); +export const DelAttributes = async ( + data: IAttributesDel +): Promise => { + const { organization, projectId, collectionNodeId, AttributeId } = data; + try { + const existingProject = await ProjectType(organization).findOne({ + _id: projectId, + isArchive: false, + }); + if (!existingProject) { + return { status: "project not found" }; + } else { + const existingCollection = await collectionsModel(organization).findOne({ + projectId: projectId, + _id: collectionNodeId, + isArchive: false, + }); + if (!existingCollection) return { status: "Collection not found" }; -// if (nestedCfg.required) -// nestedLine.push(` required: ${nestedCfg.required},`); -// if (nestedCfg.default !== undefined) -// nestedLine.push( -// ` default: ${JSON.stringify(nestedCfg.default)},` -// ); + const softDeleteAttribute = await collectionsModel( + organization + ).findOneAndUpdate( + { + projectId: projectId, + isArchive: false, + attributes: { + $elemMatch: { + _id: new mongoose.Types.ObjectId(AttributeId), + isArchive: false, + }, + }, + }, + { + $set: { + "attributes.$.isArchive": true, + }, + }, + { new: true } + ); + return { status: "Success" }; + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; -// nestedLine.push("}"); -// nestedLines.push(nestedLine.join("\n")); -// } +export const delCollection = async ( + data: ICollectionDelete +): Promise => { + const { organization, projectId, collectionNodeId } = data; + try { + const existingProject = await ProjectType(organization).findOne({ + _id: projectId, + isArchive: false, + }); + if (!existingProject) { + return { status: "project not found" }; + } else { + const existingCollection = await collectionsModel(organization).findOne({ + projectId: projectId, + isArchive: false, + _id: collectionNodeId, + }); + if (!existingCollection) { + return { status: "Collection not found" }; + } + const collectionSoftDelete = await collectionsModel( + organization + ).findOneAndUpdate( + { + projectId: projectId, + isArchive: false, + _id: collectionNodeId, + }, + { isArchive: true }, + { new: true } + ); + return { status: "Success" }; + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; -// line.push(`${key}: {`); -// line.push(nestedLines.join(",\n")); -// line.push("}"); -// lines.push(line.join("\n")); -// continue; -// } +export const GetcollectionNode = async ( + data: IcollectionNodeById +): Promise => { + const { organization, projectId, collectionNodeId } = data; + try { + const existingProject = await ProjectType(organization).findOne({ + _id: projectId, + isArchive: false, + }); + if (!existingProject) { + return { status: "project not found" }; + } else { + const existingCollection = await collectionsModel(organization).findOne({ + projectId: projectId, + isArchive: false, + _id: collectionNodeId, + }); + if (!existingCollection) { + return { status: "Collection not found" }; + } + const formattedCollection = { + position: existingCollection.position, + collectionNodeName: existingCollection.collectionNodeName, + attributes: existingCollection.attributes + .filter((attr: any) => !attr.isArchive) + .map((attr: any) => { + const { isArchive, ...rest } = attr.toObject(); + return rest; + }), + }; + return { status: "Success", data: formattedCollection }; + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; -// line.push(`${key}: {`); +const generateUniqueCollectionName = async ( + baseName: string, + organization: string, + projectId: string +): Promise => { + let nameToTry = baseName; + let attempt = 0; -// if (Array.isArray(typeValue)) { -// typeValue = `[${typeValue -// .map((t) => (typeof t === "string" ? t : JSON.stringify(t))) -// .join(", ")}]`; -// } + while (true) { + const existingCollection = await collectionsModel(organization).findOne({ + projectId, + isArchive: false, + collectionNodeName: nameToTry, + }); + if (!existingCollection) { + return nameToTry; + } + attempt++; + nameToTry = `${baseName} (duplicate${attempt > 1 ? ` ${attempt}` : ""})`; + console.log("nameToTry: ", nameToTry); -// line.push(` type: ${typeValue},`); + if (attempt > 10) { + throw new Error("Too many duplicate project name attempts"); + } + } +}; +export const DuplicateCollection = async ( + data: IDuplicateCollectionNode +): Promise => { + const { organization, projectId, position, collectionNodeId } = data; + try { + const existingProject = await ProjectType(organization).findOne({ + _id: projectId, + isArchive: false, + }); + if (!existingProject) { + return { status: "project not found" }; + } else { + const existingCollection = await collectionsModel(organization).findOne({ + projectId: projectId, + isArchive: false, + _id: collectionNodeId, + }); + if (!existingCollection) + return { status: "CollectionId not found for duplication" }; + else { + const NewduplicateName = await generateUniqueCollectionName( + existingCollection.collectionNodeName, + organization, + projectId + ); -// if (cfg.ref) line.push(` ref: "${cfg.ref}",`); -// if (cfg.required) line.push(` required: ${cfg.required},`); -// if (cfg.default !== undefined) -// line.push(` default: ${JSON.stringify(cfg.default)},`); -// if (cfg.minLength) line.push(` minlength: ${cfg.minLength},`); -// if (cfg.maxLength) line.push(` maxlength: ${cfg.maxLength},`); -// if (cfg.enum) { -// const enumValues = (cfg.enum as string[]) -// .map((v) => `"${v}"`) -// .join(", "); -// line.push(` enum: [${enumValues}],`); -// } -// if (cfg.min !== undefined) line.push(` min: ${cfg.min},`); -// if (cfg.max !== undefined) line.push(` max: ${cfg.max},`); - -// line.push("}"); -// lines.push(line.join("\n")); -// } - -// return lines.join(",\n"); -// }; -// const AttributesToAdd = attrToSchema(attributes); -// console.log('AttributesToAdd: ', AttributesToAdd); -// const buildAttributesArray = (attr: Record): Record[] => { -// console.log('attr: ', attr); -// const result: Record[] = []; - -// for (const [key, config] of Object.entries(attr)) { -// if (config && typeof config === "object" && !config.type) { -// result.push({ [key]: buildAttributesArray(config) }); -// } else { -// result.push({ [key]: { ...config } }); -// } -// } -// return result; -// }; -// const AttributesToAdd = buildAttributesArray(attributes); + const NewCollectionDuplicate = await collectionsModel( + organization + ).create({ + projectId, + isArchive: false, + position, + collectionNodeName: NewduplicateName, + }); + if (!NewCollectionDuplicate) + return { status: "Duplication unsuccessfull" }; + else { + const data = existingCollection.attributes + .filter((attr: any) => !attr.isArchive) + .map((attr: any) => { + const { isArchive, _id, ...rest } = attr.toObject(); + return rest; + }); + NewCollectionDuplicate.attributes = data; + NewCollectionDuplicate.save(); + return { status: "Success" }; + } + } + } + } catch (error: unknown) { + if (error instanceof Error) { + return { + status: error.message, + }; + } else { + return { + status: "An unexpected error occurred", + }; + } + } +}; diff --git a/src/shared/services/projectService.ts b/src/shared/services/projectService.ts index e5f254a..267eda3 100644 --- a/src/shared/services/projectService.ts +++ b/src/shared/services/projectService.ts @@ -10,6 +10,7 @@ interface IProject { projectName: string; userName: string; apiType: string; + application: string; architecture: string; description: string; } @@ -27,6 +28,7 @@ export const projectCreationService = async ( description, userName, apiType, + application, architecture, } = data; try { @@ -45,6 +47,7 @@ export const projectCreationService = async ( useableLanguage, architecture, apiType: apiType, + appType: application, description, }); if (!newProject) return { status: "Project creation unsuccessfull" };