group add and ungroup API completed

This commit is contained in:
2025-10-31 15:50:01 +05:30
parent eda62fcfb6
commit 9d2e145d4f
7 changed files with 319 additions and 203 deletions

View File

@@ -7,6 +7,7 @@ import edgeRoutes from "./routes/edgeRoutes";
import authRoutes from "./routes/authRoutes"; import authRoutes from "./routes/authRoutes";
import homeRoutes from "./routes/homeRoutes"; import homeRoutes from "./routes/homeRoutes";
import dummyRoutes from "./routes/dummyRoutes"; import dummyRoutes from "./routes/dummyRoutes";
import groupRoutes from "./routes/groupRoutes";
dotenv.config(); dotenv.config();
const app = express(); const app = express();
@@ -22,5 +23,6 @@ app.use("/api/v1", collectionNodeRoutes);
app.use("/api/v1", edgeRoutes); app.use("/api/v1", edgeRoutes);
app.use("/api/v1", homeRoutes); app.use("/api/v1", homeRoutes);
app.use("/api/v1", dummyRoutes); app.use("/api/v1", dummyRoutes);
app.use("/api/v1", groupRoutes);
export default app; export default app;

View File

@@ -1,6 +1,6 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { AuthenticatedRequest } from "../../shared/utils/token"; import { AuthenticatedRequest } from "../../shared/utils/token";
import { groupcreation } from "../../shared/services/groupService"; import { groupcreationService, unGrpService } from "../../shared/services/groupService";
export const addGroupController = async ( export const addGroupController = async (
req: AuthenticatedRequest, req: AuthenticatedRequest,
@@ -12,7 +12,7 @@ export const addGroupController = async (
const missing = Object.entries({ const missing = Object.entries({
organization, organization,
projectId, projectId,
position, // position,
userId, userId,
groupName, groupName,
type, type,
@@ -37,43 +37,107 @@ export const addGroupController = async (
collections, collections,
userId: userId as string, userId: userId as string,
}; };
const result = await groupcreation(data); const result = await groupcreationService(data);
console.log("result:groupcretate ", result); console.log('result:grp add ', result);
switch (result.status) { // switch (result.status) {
case "User not found": // case "User not found":
res.status(404).json({ message: "User not found" }); // res.status(404).json({ message: "User not found" });
break; // break;
case "project not found": // case "project not found":
res.status(404).json({ // res.status(404).json({
message: "project not found", // message: "project not found",
}); // });
break; // break;
case "Collections already exist in this group": // case "CollectionId already exist in this group":
res.status(200).json({ // res.status(200).json({
message: "Collections already exist in this group", // message: "CollectionId already exist in this group",
}); // });
break; // break;
case "Collections added to existing group": // case "Collections added to existing group":
res.status(200).json({ // res.status(200).json({
message: "Collections added to existing group", // message: "Collections added to existing group",
}); // });
break; // break;
case "Success": // case "Group already exists":
res.status(200).json({ // res.status(200).json({
message: "Group created successfully", // message: "Group already exists",
groupId: result.data, // });
}); // break;
break; // case "Success":
case "Validation Error": // res.status(200).json({
res.status(400).json({ message: result.data || "Validation Error" }); // message: "Group created successfully",
break; // groupId: result.data,
default: // });
res.status(500).json({ // break;
message: "Internal server error", // case "Validation Error":
}); // res.status(400).json({ message: result.data || "Validation Error" });
break; // break;
} // default:
// res.status(500).json({
// message: "Internal server error",
// });
// break;
// }
if (
result.status === "User not found" ||
result.status === "Project not found"
)
res.status(404).json({ message: result.status });
else if (result.status === "Error")
res.status(500).json({ message: result.data });
else res.status(200).json({ message: result.status, groupId: result.data });
} catch (error) {
res.status(500).json({
message: "Unknown error",
});
}
};
export const unGroupController = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const { organization, userId } = req.user || {};
const { projectId, position, groupId, collections } = req.body;
const missing = Object.entries({
organization,
projectId,
// position,
userId,
groupId,
})
.filter(([_, v]) => !v)
.map(([k]) => k);
if (missing.length) {
res.status(400).json({
message: `Missing field${missing.length > 1 ? "s" : ""}: ${missing.join(
", "
)}`,
});
return;
}
const data = {
organization: organization as string,
projectId,
position,
groupId,
collections,
userId: userId as string,
};
const result = await unGrpService(data);
console.log('result:ungrp ', result);
if (
result.status === "User not found" ||
result.status === "Project not found"
)
res.status(404).json({ message: result.status });
else if (result.status === "Error")
res.status(500).json({ message: result.data });
else res.status(200).json({ message: result.status, groupId: result.data });
} catch (error) { } catch (error) {
res.status(500).json({ res.status(500).json({
message: "Unknown error", message: "Unknown error",

View File

@@ -0,0 +1,8 @@
import express from "express"
import { tokenValidator } from "../../shared/utils/token"
import { addGroupController, unGroupController } from "../controller/groupController"
const groupRoutes = express()
//group create
groupRoutes.post("/groupadd",tokenValidator,addGroupController)
groupRoutes.post("/ungroup",tokenValidator,unGroupController)
export default groupRoutes

View File

@@ -1,6 +1,7 @@
import { Schema, Document } from "mongoose"; import { Schema, Document } from "mongoose";
import MainModel from "../connection/connection"; import MainModel from "../connection/connection";
import { IProject } from "./projectmodel"; import { IProject } from "./projectmodel";
import { IgroupModel } from "./groupModel";
type IattributeTypes = type IattributeTypes =
| "string" | "string"
| "any" | "any"
@@ -35,6 +36,7 @@ export interface ICollectionNode extends Document {
parentCollectionNodeId: ICollectionNode["_id"]; parentCollectionNodeId: ICollectionNode["_id"];
isSubCollection: boolean; isSubCollection: boolean;
attributeparentId: ICollectionNode["_id"]; attributeparentId: ICollectionNode["_id"];
groupParentId: IgroupModel["_id"];
collectionName: string; collectionName: string;
attributes: IAttributes[]; attributes: IAttributes[];
backgroundColor: BackgroundColor; backgroundColor: BackgroundColor;
@@ -114,6 +116,7 @@ const collectionSchema: Schema<ICollectionNode> = new Schema(
projectId: { type: Schema.Types.ObjectId, ref: "Project" }, projectId: { type: Schema.Types.ObjectId, ref: "Project" },
parentCollectionNodeId: { type: Schema.Types.ObjectId, ref: "Collection" }, parentCollectionNodeId: { type: Schema.Types.ObjectId, ref: "Collection" },
attributeparentId: { type: Schema.Types.ObjectId, ref: "Collection" }, attributeparentId: { type: Schema.Types.ObjectId, ref: "Collection" },
groupParentId: { type: Schema.Types.ObjectId, ref: "Collection" },
collectionName: { type: String }, collectionName: { type: String },
type: { type: String, enum: ["collectionNode", "objectNode"] }, type: { type: String, enum: ["collectionNode", "objectNode"] },
backgroundColor: { type: backgroundColorSchema }, backgroundColor: { type: backgroundColorSchema },

View File

@@ -9,6 +9,7 @@ export interface IgroupModel extends Document {
position: { position: {
x: number; x: number;
y: number; y: number;
zoom: number;
}; };
projectId: IProject["_id"]; projectId: IProject["_id"];
collections: ICollectionNode["_id"][]; collections: ICollectionNode["_id"][];
@@ -22,6 +23,7 @@ const GroupSchema = new Schema<IgroupModel>(
position: { position: {
x: { type: Number }, x: { type: Number },
y: { type: Number }, y: { type: Number },
zoom: { type: Number },
}, },
projectId: { type: Schema.Types.ObjectId, ref: "Project", required: true }, projectId: { type: Schema.Types.ObjectId, ref: "Project", required: true },
collections: [{ type: Schema.Types.ObjectId, ref: "Collection" }], collections: [{ type: Schema.Types.ObjectId, ref: "Collection" }],

View File

@@ -5,6 +5,7 @@ import edgeModel from "../model/edgeModel";
import userModel from "../model/userModel"; import userModel from "../model/userModel";
import { modelNodeFile, updateFilename } from "./fileFunctionalityService"; import { modelNodeFile, updateFilename } from "./fileFunctionalityService";
import { IattributeTypes } from "../model/dummycollectionmodel"; import { IattributeTypes } from "../model/dummycollectionmodel";
import groupModel from "../model/groupModel";
interface Iresponse { interface Iresponse {
status: string; status: string;
data?: any; data?: any;
@@ -538,7 +539,7 @@ export const GetNodesInProject = async (
let collectionNodes = await collectionsModel(organization) let collectionNodes = await collectionsModel(organization)
.find({ projectId: projectId, isArchive: false }) .find({ projectId: projectId, isArchive: false })
.select( .select(
"collectionName attributes position _id type parentCollectionNodeId attributeparentId" "collectionName attributes position _id type parentCollectionNodeId attributeparentId groupParentId"
); );
if (!collectionNodes) if (!collectionNodes)
return { status: "No collection Nodes present", data: [] }; return { status: "No collection Nodes present", data: [] };
@@ -580,11 +581,37 @@ export const GetNodesInProject = async (
}; };
}) })
); );
let formattedGroups=[];
const groupDatas = await groupModel(organization).find({
isArchive: false,
projectId:projectId,
});
// let formattedGroups
for (const grpdata of groupDatas) {
const collectionsDatas = await collectionsModel(organization).find({
isArchive: false,
projectId,
groupParentId: grpdata._id,
});
formattedGroups.push({
groupId: grpdata._id,
type: grpdata.type,
position: grpdata.position,
data: {
label: grpdata.groupName,
childrenCount: collectionsDatas.length,
},
});
}
// return formattedGroups
const formattedCollections = collectionNodes.map((collection: any) => { const formattedCollections = collectionNodes.map((collection: any) => {
// console.log("collection: ", collection);
// console.log("collection.groupParentId: ", collection.groupParentId);
const baseData = { const baseData = {
id: collection._id, id: collection._id,
position: collection.position, position: collection.position,
type: collection.type, type: collection.type,
parentGroupNode: `group - ${collection.groupParentId}`|| " ",
data: { data: {
collectionName: collection.collectionName, collectionName: collection.collectionName,
collectionData: collection.attributes collectionData: collection.attributes
@@ -622,11 +649,13 @@ export const GetNodesInProject = async (
} }
return baseData; return baseData;
}); });
console.log("filteredEdges: ", filteredEdges); // console.log("filteredEdges: ", filteredEdges);
const finalResult = { const finalResult = {
nodes: formattedCollections, nodes: formattedCollections,
edges: filteredEdges, edges: filteredEdges,
groups: formattedGroups,
}; };
// console.log("finalResult: ", finalResult);
return { status: "Success", data: finalResult }; return { status: "Success", data: finalResult };
} }
} }
@@ -779,9 +808,8 @@ export const UpdateAttributes = async (
doc.markModified("attributes"); doc.markModified("attributes");
await doc.save(); await doc.save();
} }
} catch (err:any) { } catch (err: any) {
return { status: "Validation Error", data: err.message }; return { status: "Validation Error", data: err.message };
} }
} }
} }
@@ -1131,13 +1159,6 @@ export const DuplicateAttributes = async (
newKey = `${attrKey}(${counter})`; newKey = `${attrKey}(${counter})`;
console.log("newKey: ", newKey); console.log("newKey: ", newKey);
} }
console.log("existingAttr.type: ", existingAttr.type);
// existingCollection.attributes.push({
// key: newKey,
// type: existingAttr.type,
// isArchive: false,
// });
} else { } else {
return { status: "Attribute doesnot match" }; return { status: "Attribute doesnot match" };
} }
@@ -1205,7 +1226,6 @@ export const GetcollectionLists = async (
} }
}; };
// - working
export const DelAttributes = async ( export const DelAttributes = async (
data: IAttributesDel data: IAttributesDel
): Promise<Iresponse> => { ): Promise<Iresponse> => {
@@ -1289,7 +1309,7 @@ export const DelAttributes = async (
return { status: "An unexpected error occurred" }; return { status: "An unexpected error occurred" };
} }
}; };
// - working
export const addAttributes = async ( export const addAttributes = async (
data: IcollectionAttributes data: IcollectionAttributes
): Promise<Iresponse> => { ): Promise<Iresponse> => {
@@ -1298,21 +1318,18 @@ export const addAttributes = async (
console.log("data: ", data); console.log("data: ", data);
try { try {
// 1⃣ Validate User
const existingUser = await userModel(organization).findOne({ const existingUser = await userModel(organization).findOne({
_id: userId, _id: userId,
isArchive: false, isArchive: false,
}); });
if (!existingUser) return { status: "User not found" }; if (!existingUser) return { status: "User not found" };
// 2⃣ Validate Project
const existingProject = await ProjectType(organization).findOne({ const existingProject = await ProjectType(organization).findOne({
_id: projectId, _id: projectId,
isArchive: false, isArchive: false,
}); });
if (!existingProject) return { status: "Project not found" }; if (!existingProject) return { status: "Project not found" };
// 3⃣ Validate Collection
const existingCollection = await collectionsModel(organization).findOne({ const existingCollection = await collectionsModel(organization).findOne({
projectId, projectId,
_id: collectionNodeId, _id: collectionNodeId,
@@ -1322,7 +1339,6 @@ export const addAttributes = async (
const existingAttributes = existingCollection.attributes || []; const existingAttributes = existingCollection.attributes || [];
// 4⃣ Check for duplicates with isArchive: false
for (const attr of attributes) { for (const attr of attributes) {
const duplicate = existingAttributes.find( const duplicate = existingAttributes.find(
(exAttr) => exAttr.key === attr.key && !exAttr.isArchive (exAttr) => exAttr.key === attr.key && !exAttr.isArchive
@@ -1333,10 +1349,8 @@ export const addAttributes = async (
} }
} }
// 5⃣ Merge new attributes
const updatedAttributes = [...existingAttributes, ...attributes]; const updatedAttributes = [...existingAttributes, ...attributes];
// 6⃣ Update collection
const attributesAdded = await collectionsModel( const attributesAdded = await collectionsModel(
organization organization
).findOneAndUpdate( ).findOneAndUpdate(
@@ -1347,7 +1361,6 @@ export const addAttributes = async (
if (!attributesAdded) return { status: "Failed to add attributes" }; if (!attributesAdded) return { status: "Failed to add attributes" };
// 7⃣ Create subcollections for Object type attributes
for (const attr of attributes) { for (const attr of attributes) {
if (attr.type === "Object") { if (attr.type === "Object") {
const existingSubCollection = await collectionsModel( const existingSubCollection = await collectionsModel(
@@ -1376,34 +1389,10 @@ export const addAttributes = async (
await attributesAdded.save(); await attributesAdded.save();
// 8⃣ Return newly added attribute IDs
const newlyAddedAttributes = attributesAdded.attributes.filter((attr) => const newlyAddedAttributes = attributesAdded.attributes.filter((attr) =>
attributes.some((newAttr) => newAttr.key === attr.key) attributes.some((newAttr) => newAttr.key === attr.key)
); );
const addedFieldIds = newlyAddedAttributes.map((attr) => (attr as any)._id); const addedFieldIds = newlyAddedAttributes.map((attr) => (attr as any)._id);
console.log("addedFieldIds: ", addedFieldIds);
// 9⃣ 🧠 Update the model file dynamically
// try {
// const allAttributes = attributesAdded.attributes.reduce((acc, attr) => {
// acc[attr.key] = attr.type;
// return acc;
// }, {} as Record<string, string>);
// const fileData = {
// projectName: existingProject.projectName,
// models1: [
// {
// name: existingCollection.collectionName,
// attributes: allAttributes,
// },
// ],
// };
// const fileResponse = await modelNodeFile(fileData);
// console.log("✅ Model file updated:", fileResponse);
// } catch (fileErr) {
// console.error("⚠️ File backend update failed:", fileErr);
// }
return { return {
status: "Success", status: "Success",
data: addedFieldIds, data: addedFieldIds,

View File

@@ -22,22 +22,21 @@ interface IgroupNode {
position: { position: {
x: number; x: number;
y: number; y: number;
zoom: number;
}; };
} }
interface IgroupNodeupdate { interface IunGrp {
projectId: string; projectId: string;
groupId: string;
userId: string; userId: string;
groupName: string;
type: string;
organization: string; organization: string;
position: { collections: IcollectionsNode[];
x: number;
y: number;
};
} }
export const groupcreation = async (data: IgroupNode): Promise<Iresponse> => { export const groupcreationService = async (
data: IgroupNode
): Promise<Iresponse> => {
const { const {
organization, organization,
projectId, projectId,
@@ -66,78 +65,105 @@ export const groupcreation = async (data: IgroupNode): Promise<Iresponse> => {
isArchive: false, isArchive: false,
groupName: groupName, groupName: groupName,
}); });
// if (existingGroup) return { status: "Group already exists" }; if (!existingGroup) {
// else { const validCollectionIds: mongoose.Types.ObjectId[] = [];
// if (collections.length > 0) { const invalidIds: string[] = [];
// const newcoln = collections;
// const updatedCollectionsMap = new Map<string, null>();
// for (const coln of collections) { for (const collect of collections) {
// updatedCollectionsMap.set(coln, 0); const aliveCollection = await collectionsModel(organization).findOne({
// } _id: collect.collectionNodeId,
isArchive: false,
});
const existingGroupNode = await groupModel(organization).find({
isArchive: false,
projectId,
collections: collect.collectionNodeId,
});
console.log("existingGroupNode: ", existingGroupNode);
if (existingGroupNode.length > 0)
return { status: "collectionId already added to other Group" };
if (aliveCollection && existingGroupNode.length === 0) {
validCollectionIds.push(
new mongoose.Types.ObjectId(collect.collectionNodeId)
);
} else {
invalidIds.push(collect.collectionNodeId);
}
}
// for (const coln of collections) {
// if (!updatedCollectionsMap.has(coln)) {
// updatedCollectionsMap.set(coln);
// }
// }
// const updatedCollections = Array.from(updatedCollectionsMap.values());
// const newGroup = await groupModel(organization).create({
// groupName,
// projectId,
// position,
// createdBy: userId,
// collections: updatedCollections,
// });
// // }
// if (newGroup)
// return {
// status: "NewGroup Created Successfully",
// data: newGroup._id,
// };
// else {
// return {
// status: "Creation Unsuccessfull",
// };
// }
// }
// }
// }
const collectionIds = collections.map(
(c) => new mongoose.Types.ObjectId(c.collectionNodeId)
);
if (existingGroup) {
const existingIds = existingGroup.collections.map((id) =>
(id as any).toString()
);
const newIds = collectionIds.filter(
(id) => !existingIds.includes(id.toString())
);
if (newIds.length === 0)
return { status: "Collections already exist in this group" };
existingGroup.collections.push(...newIds);
await existingGroup.save();
return {
status: "Collections added to existing group",
data: existingGroup._id,
};
} else {
const newGroup = await groupModel(organization).create({ const newGroup = await groupModel(organization).create({
groupName, groupName,
type, type,
position, position,
projectId, projectId,
createdBy: userId, createdBy: userId,
collections: [ collections: validCollectionIds,
...new Set(collectionIds.map((id) => id.toString())),
].map((id) => new mongoose.Types.ObjectId(id)),
}); });
return { status: "Success", data: newGroup._id }; if (validCollectionIds.length > 0) {
await collectionsModel(organization).updateMany(
{ _id: { $in: validCollectionIds } },
{ $set: { groupParentId: newGroup._id } }
);
}
if (invalidIds.length > 0) {
return {
// status: "Partial Success",
status: `Group created. Invalid IDs: ${invalidIds.join(", ")}`,
data: newGroup._id,
};
}
return { status: "Group created successfully", data: newGroup._id };
} else {
const validCollectionIds: mongoose.Types.ObjectId[] = [];
const invalidIds: string[] = [];
for (const collect of collections) {
console.log("collections: ", collections);
const aliveCollection = await collectionsModel(organization).findOne({
_id: collect.collectionNodeId,
isArchive: false,
});
const existingGroupNode = await groupModel(organization).find({
isArchive: false,
projectId,
collections: collect.collectionNodeId,
});
if (existingGroupNode.length > 0)
return { status: "collectionId already added to other Group" };
if (aliveCollection && existingGroupNode.length === 0) {
validCollectionIds.push(
new mongoose.Types.ObjectId(collect.collectionNodeId)
);
} else {
invalidIds.push(collect.collectionNodeId);
}
}
const existingIds = existingGroup.collections.map((id: any) =>
id.toString()
);
const newIds = validCollectionIds.filter(
(id) => !existingIds.includes(id.toString())
);
if (newIds.length > 0) {
existingGroup.collections.push(...newIds);
await existingGroup.save();
await collectionsModel(organization).updateMany(
{ _id: { $in: newIds } },
{ $set: { groupParentId: existingGroup._id } }
);
}
if (newIds.length === 0 && invalidIds.length === 0) {
return { status: "All Collection IDs already exist in this group" };
}
let msg = "";
if (newIds.length) msg += `Added ${newIds.length} new collections. `;
if (invalidIds.length) msg += `Invalid IDs: ${invalidIds.join(", ")}.`;
return { status: msg.trim(), data: existingGroup._id };
} }
} }
} catch (error: unknown) { } catch (error: unknown) {
@@ -151,52 +177,74 @@ export const groupcreation = async (data: IgroupNode): Promise<Iresponse> => {
} }
}; };
// export const addNodesToGroup = async (data: IgroupNode): Promise<Iresponse> => { export const unGrpService = async (data: IunGrp): Promise<Iresponse> => {
// const { organization, projectId, position, userId, groupId, groups } = data; const { organization, projectId, userId, groupId, collections } = data;
// try { try {
// const ExistingUser = await userModel(organization).findOne({ const ExistingUser = await userModel(organization).findOne({
// _id: userId, _id: userId,
// isArchive: false, isArchive: false,
// }); });
// if (!ExistingUser) return { status: "User not found" };
// const existingProject = await ProjectType(organization).findOne({ if (!ExistingUser) return { status: "User not found" };
// _id: projectId, const existingProject = await ProjectType(organization).findOne({
// isArchive: false, _id: projectId,
// }); isArchive: false,
// if (!existingProject) { });
// return { status: "project not found" }; if (!existingProject) {
// } else { return { status: "project not found" };
// const existingGroup = await groupModel(organization).findOne({ } else {
// projectId: projectId, const existingGroup = await groupModel(organization).findOne({
// isArchive: false, projectId: projectId,
// groupId: groupId, isArchive: false,
// }); _id: groupId,
// if (existingGroup) { });
// const existingGroup = await groupModel(organization).findOneAndUpdate( if (!existingGroup) return { status: "Group not found for this Id" };
// {
// projectId: projectId, if (existingGroup.collections.length === 0) {
// isArchive: false, return { status: "No collections found to ungroup" };
// groupId: groupId, }
// },
// { if (collections.length > 0) {
// groups: groups, for (const coln of collections) {
// }, const index1 = (
// { new: true } existingGroup.collections as mongoose.Types.ObjectId[]
// ); ).findIndex(
// if (existingGroup) { (c: object) => c.toString() === coln.collectionNodeId.toString()
// return { status: "Group updated successfully" }; );
// } else {
// return { status: "Group update Unsuccessfully" }; if (index1 !== -1) {
// } existingGroup.collections.splice(index1, 1);
// } await existingGroup.save();
// }
// } catch (error: unknown) { const deleteCollection = await collectionsModel(
// if (error instanceof mongoose.Error.ValidationError) { organization
// return { status: "Validation Error", data: error.message }; ).findOne({
// } else if (error instanceof Error) { _id: coln.collectionNodeId,
// return { status: error.message }; projectId,
// } else { isArchive: false,
// return { status: "An unexpected error occurred" }; });
// }
// } if (deleteCollection) {
// }; deleteCollection.groupParentId = undefined;
await deleteCollection.save();
}
} else {
return { status: "collectionId mismatch" };
}
}
return { status: "Success" };
}
return { status: "No collections provided for ungrouping" };
}
} catch (error: unknown) {
if (error instanceof mongoose.Error.ValidationError) {
return { status: "Validation Error", data: error.message };
} else if (error instanceof Error) {
return { status: error.message };
} else {
return { status: "An unexpected error occurred" };
}
}
};