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

View File

@@ -1,6 +1,6 @@
import { Request, Response } from "express";
import { AuthenticatedRequest } from "../../shared/utils/token";
import { groupcreation } from "../../shared/services/groupService";
import { groupcreationService, unGrpService } from "../../shared/services/groupService";
export const addGroupController = async (
req: AuthenticatedRequest,
@@ -12,7 +12,7 @@ export const addGroupController = async (
const missing = Object.entries({
organization,
projectId,
position,
// position,
userId,
groupName,
type,
@@ -37,43 +37,107 @@ export const addGroupController = async (
collections,
userId: userId as string,
};
const result = await groupcreation(data);
console.log("result:groupcretate ", result);
const result = await groupcreationService(data);
console.log('result:grp add ', result);
switch (result.status) {
case "User not found":
res.status(404).json({ message: "User not found" });
break;
case "project not found":
res.status(404).json({
message: "project not found",
});
break;
case "Collections already exist in this group":
res.status(200).json({
message: "Collections already exist in this group",
});
break;
case "Collections added to existing group":
res.status(200).json({
message: "Collections added to existing group",
});
break;
case "Success":
res.status(200).json({
message: "Group created successfully",
groupId: result.data,
});
break;
case "Validation Error":
res.status(400).json({ message: result.data || "Validation Error" });
break;
default:
res.status(500).json({
message: "Internal server error",
});
break;
}
// switch (result.status) {
// case "User not found":
// res.status(404).json({ message: "User not found" });
// break;
// case "project not found":
// res.status(404).json({
// message: "project not found",
// });
// break;
// case "CollectionId already exist in this group":
// res.status(200).json({
// message: "CollectionId already exist in this group",
// });
// break;
// case "Collections added to existing group":
// res.status(200).json({
// message: "Collections added to existing group",
// });
// break;
// case "Group already exists":
// res.status(200).json({
// message: "Group already exists",
// });
// break;
// case "Success":
// res.status(200).json({
// message: "Group created successfully",
// groupId: result.data,
// });
// break;
// case "Validation Error":
// res.status(400).json({ message: result.data || "Validation Error" });
// 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) {
res.status(500).json({
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 MainModel from "../connection/connection";
import { IProject } from "./projectmodel";
import { IgroupModel } from "./groupModel";
type IattributeTypes =
| "string"
| "any"
@@ -35,6 +36,7 @@ export interface ICollectionNode extends Document {
parentCollectionNodeId: ICollectionNode["_id"];
isSubCollection: boolean;
attributeparentId: ICollectionNode["_id"];
groupParentId: IgroupModel["_id"];
collectionName: string;
attributes: IAttributes[];
backgroundColor: BackgroundColor;
@@ -114,6 +116,7 @@ const collectionSchema: Schema<ICollectionNode> = new Schema(
projectId: { type: Schema.Types.ObjectId, ref: "Project" },
parentCollectionNodeId: { type: Schema.Types.ObjectId, ref: "Collection" },
attributeparentId: { type: Schema.Types.ObjectId, ref: "Collection" },
groupParentId: { type: Schema.Types.ObjectId, ref: "Collection" },
collectionName: { type: String },
type: { type: String, enum: ["collectionNode", "objectNode"] },
backgroundColor: { type: backgroundColorSchema },

View File

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

View File

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

View File

@@ -22,22 +22,21 @@ interface IgroupNode {
position: {
x: number;
y: number;
zoom: number;
};
}
interface IgroupNodeupdate {
interface IunGrp {
projectId: string;
groupId: string;
userId: string;
groupName: string;
type: string;
organization: string;
position: {
x: number;
y: number;
};
collections: IcollectionsNode[];
}
export const groupcreation = async (data: IgroupNode): Promise<Iresponse> => {
export const groupcreationService = async (
data: IgroupNode
): Promise<Iresponse> => {
const {
organization,
projectId,
@@ -66,78 +65,105 @@ export const groupcreation = async (data: IgroupNode): Promise<Iresponse> => {
isArchive: false,
groupName: groupName,
});
// if (existingGroup) return { status: "Group already exists" };
// else {
// if (collections.length > 0) {
// const newcoln = collections;
// const updatedCollectionsMap = new Map<string, null>();
if (!existingGroup) {
const validCollectionIds: mongoose.Types.ObjectId[] = [];
const invalidIds: string[] = [];
// for (const coln of collections) {
// updatedCollectionsMap.set(coln, 0);
// }
for (const collect of collections) {
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({
groupName,
type,
position,
projectId,
createdBy: userId,
collections: [
...new Set(collectionIds.map((id) => id.toString())),
].map((id) => new mongoose.Types.ObjectId(id)),
collections: validCollectionIds,
});
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) {
@@ -151,52 +177,74 @@ export const groupcreation = async (data: IgroupNode): Promise<Iresponse> => {
}
};
// export const addNodesToGroup = async (data: IgroupNode): Promise<Iresponse> => {
// const { organization, projectId, position, userId, groupId, groups } = data;
// try {
// const ExistingUser = await userModel(organization).findOne({
// _id: userId,
// isArchive: false,
// });
// if (!ExistingUser) return { status: "User not found" };
// const existingProject = await ProjectType(organization).findOne({
// _id: projectId,
// isArchive: false,
// });
// if (!existingProject) {
// return { status: "project not found" };
// } else {
// const existingGroup = await groupModel(organization).findOne({
// projectId: projectId,
// isArchive: false,
// groupId: groupId,
// });
// if (existingGroup) {
// const existingGroup = await groupModel(organization).findOneAndUpdate(
// {
// projectId: projectId,
// isArchive: false,
// groupId: groupId,
// },
// {
// groups: groups,
// },
// { new: true }
// );
// if (existingGroup) {
// return { status: "Group updated successfully" };
// } else {
// return { status: "Group update Unsuccessfully" };
// }
// }
// }
// } 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" };
// }
// }
// };
export const unGrpService = async (data: IunGrp): Promise<Iresponse> => {
const { organization, projectId, userId, groupId, collections } = data;
try {
const ExistingUser = await userModel(organization).findOne({
_id: userId,
isArchive: false,
});
if (!ExistingUser) return { status: "User not found" };
const existingProject = await ProjectType(organization).findOne({
_id: projectId,
isArchive: false,
});
if (!existingProject) {
return { status: "project not found" };
} else {
const existingGroup = await groupModel(organization).findOne({
projectId: projectId,
isArchive: false,
_id: groupId,
});
if (!existingGroup) return { status: "Group not found for this Id" };
if (existingGroup.collections.length === 0) {
return { status: "No collections found to ungroup" };
}
if (collections.length > 0) {
for (const coln of collections) {
const index1 = (
existingGroup.collections as mongoose.Types.ObjectId[]
).findIndex(
(c: object) => c.toString() === coln.collectionNodeId.toString()
);
if (index1 !== -1) {
existingGroup.collections.splice(index1, 1);
await existingGroup.save();
const deleteCollection = await collectionsModel(
organization
).findOne({
_id: coln.collectionNodeId,
projectId,
isArchive: false,
});
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" };
}
}
};