Refactor edgeService and socket-server controllers to improve foreign key resolution and event handling

- Updated edgeService to enhance foreign key resolution logic and added detailed logging for debugging.
- Refactored socket-server controllers to replace emitToSenderAndAdmins with emitToRoom for better room-based event handling.
- Removed unnecessary console logs and improved code readability across various services.
- Introduced room management functions (joinRoom, leaveRoom) to streamline socket event handling.
- Cleaned up commented-out code and organized imports for clarity.
This commit is contained in:
2025-11-01 09:30:45 +05:30
parent 9d2e145d4f
commit db884e0b28
14 changed files with 768 additions and 308 deletions

View File

@@ -151,7 +151,7 @@ export const updateCollectionController = async (
position,
};
const result = await updatecollection(data);
console.log('result: ', result);
switch (result.status) {
case "User not found":
res.status(404).json({ message: "User not found" });

View File

@@ -41,7 +41,7 @@ export const edgeCreationController = async (
userId: userId as string,
};
const result = await edgecreation(data);
console.log('result: ', result);
switch (result.status) {
case "User not found":
@@ -117,7 +117,7 @@ export const allEdgesController = async (
userId: userId as string,
};
const result = await Alledges(data);
console.log('result:all edge ', result);
switch (result.status) {
case "User not found":

View File

@@ -64,27 +64,27 @@ export const projectCreationController = async (
architecture,
};
const result = await projectCreationService(data);
if (result.status === "Success") {
const fetchResult = await folderProject(
subBkd,
projectName,
language,
apiProtocol,
application,
architecture
);
if (fetchResult) {
res.status(200).json({
message: "Project creation unsuccessfull",
projectId: result.data,
});
// return { status: "Success", data: fetchResult.data };
} else {
res.status(500).json({
message: "error",
});
}
}
// if (result.status === "Success") {
// const fetchResult = await folderProject(
// subBkd,
// projectName,
// language,
// apiProtocol,
// application,
// architecture
// );
// if (fetchResult) {
// res.status(200).json({
// message: "Project creation unsuccessfull",
// projectId: result.data,
// });
// // return { status: "Success", data: fetchResult.data };
// } else {
// res.status(500).json({
// message: "error",
// });
// }
// }
switch (result.status) {
case "Project Already Exists":
res.status(403).json({
@@ -270,7 +270,7 @@ export const accessAproject = async (
userId: userId as string,
projectId,
});
console.log('result.data: ', result);
switch (result.status) {
case "No project found":
res.status(200).json({});

View File

@@ -22,6 +22,7 @@ interface IAttributes {
isArchive: boolean;
isIdentifier: boolean;
primary?: boolean;
keyType?: string;
key: string;
type: IattributeTypes;
refKey?: object;
@@ -60,7 +61,7 @@ const attributeSchema = new Schema<IAttributes>({
key: { type: String, required: true },
type: {
type: String,
required: true,
// required: true,
enum: [
"string",
"number",
@@ -82,7 +83,8 @@ const attributeSchema = new Schema<IAttributes>({
refKey: { type: Object },
default: { type: Schema.Types.Mixed },
unique: { type: Boolean },
primary: { type: Boolean },
// primary: { type: Boolean },
keyType: { type: String },
index: { type: Boolean },
isArchive: { type: Boolean, default: false },
isIdentifier: { type: Boolean, default: false },

View File

@@ -165,7 +165,7 @@ export const Nodecreation = async (
});
if (existingCollection)
return { status: "CollectionName already exists" };
let attributes = [{ key: "auto_id", type: "string" }];
let attributes = [{ key: "auto_id", type: "string" ,keyType:"primary"}];
const newAttributes = attributes;
const updatedAttributesMap = new Map<string, any>();
@@ -190,10 +190,16 @@ export const Nodecreation = async (
const models = [newCollectionnode.collectionName];
const finalResult = {
collectionNodeId: newCollectionnode._id,
fieldId: (newCollectionnode.attributes[0] as any)._id,
models,
};
console.log("finalResult: ", finalResult);
// fieldId: (newCollectionnode.attributes[0] as any)._id,
// models,
type:newCollectionnode.type,
position:newCollectionnode.position,
data:{
collectionName:newCollectionnode.collectionName,
collectionData:newCollectionnode.attributes,
}
};
// console.log("finalResult: ", finalResult);
const models1 = [
{
name: newCollectionnode.collectionName,
@@ -210,12 +216,12 @@ export const Nodecreation = async (
projectName: existingProject.projectName, // 👈 take from DB
models1,
};
console.log("fileData: ", fileData);
// console.log("fileData: ", fileData);
try {
const fileResponse = await modelNodeFile(fileData);
console.log("📦 File backend response:", fileResponse);
// console.log("📦 File backend response:", fileResponse);
} catch (err) {
console.error("⚠️ File backend error:", err);
// console.error("⚠️ File backend error:", err);
}
return { status: "Success", data: finalResult };
}
@@ -251,7 +257,8 @@ export const updatecollection = async (
collectionName,
userId,
} = data;
console.log("data:node ", data);
console.log('data: nodeupdate', data);
try {
const ExistingUser = await userModel(organization).findOne({
_id: userId,
@@ -276,7 +283,6 @@ export const updatecollection = async (
}
function updateModelName(oldName: string, newBaseName: string): string {
console.log("newBaseName: ", newBaseName);
const [prefix, ...suffixParts] = oldName.split("_");
if (suffixParts.length > 0) {
@@ -287,44 +293,119 @@ export const updatecollection = async (
return newBaseName;
}
const newBaseName = collectionName as string;
const referencedEdges = await collectionsModel(organization).find({
isArchive: false,
projectId,
attributes: {
$elemMatch: {
"refKey.collection_id": new mongoose.Types.ObjectId(
collectionNodeId
),
},
},
});
// const referencedEdges = await collectionsModel(organization).find({
// isArchive: false,
// projectId,
// attributes: {
// $elemMatch: {
// "refKey.collection_id": new mongoose.Types.ObjectId(
// collectionNodeId
// ),
// },
// },
// });
console.log("referencedEdges: ", referencedEdges);
if (referencedEdges.length) {
for (const doc of referencedEdges) {
let updated = false;
// console.log('referencedEdges: ', referencedEdges);
// if (referencedEdges.length) {
// for (const doc of referencedEdges) {
// let updated = false;
for (const attr of doc.attributes) {
const refKey = attr.refKey as any;
if (
refKey?.collection_id?.toString() === collectionNodeId.toString()
) {
const oldName = attr.key;
const newKey = updateModelName(oldName, newBaseName);
console.log("newKey: ", newKey);
attr.key = newKey;
updated = true;
}
}
// for (const attr of doc.attributes) {
// const refKey = attr.refKey as any;
// if (
// refKey?.collection_id?.toString() === collectionNodeId.toString()
// ) {
// const newBaseName = collectionName as string;
// const oldName = attr.key;
// const newKey = updateModelName(oldName, newBaseName);
// attr.key = newKey;
// updated = true;
// }
// }
if (updated) {
await doc.save();
}
}
// if (updated) {
// await doc.save();
// }
// }
// }
async function updateReferencedKeysRecursively(
organization: string,
projectId: string,
collectionNodeId: any,
collectionName: string,
visited = new Set<string>()
): Promise<void> {
if (visited.has(collectionNodeId)) return;
visited.add(collectionNodeId);
const referencedEdges = await collectionsModel(organization).find({
isArchive: false,
projectId,
$or: [
{ "attributes.refKey.collection_id": new mongoose.Types.ObjectId(collectionNodeId) },
{ "attributes.refKey.collection_id": collectionNodeId },
],
});
console.log('referencedEdges: ', referencedEdges);
console.log(
`🔍 Found ${referencedEdges.length} referencing collections for '${collectionName}'`
);
for (const doc of referencedEdges) {
let updated = false;
for (const attr of doc.attributes) {
const refKey = attr.refKey as any;
if (refKey?.collection_id?.toString() === collectionNodeId.toString()) {
const oldName = attr.key;
const newBaseName = collectionName;
const newKey = updateModelName(oldName, newBaseName);
attr.key = newKey;
updated = true;
console.log(
`🔁 Updated key in '${doc.collectionName}': ${oldName}${newKey} (ref to '${collectionName}')`
);
}
}
if (updated) {
await doc.save();
console.log(`✅ Saved changes in '${doc.collectionName}'`);
}
// 🔁 Recursive update if the collection itself has a valid name
if (doc.collectionName) {
await updateReferencedKeysRecursively(
organization,
projectId,
doc._id,
doc.collectionName,
visited
);
} else {
console.warn(`⚠️ Skipped recursion for ${doc._id} (no collectionName)`);
}
}
}
const currentCollectionName =
collectionName || existingCollection.collectionName;
await updateReferencedKeysRecursively(
organization,
projectId,
collectionNodeId,
currentCollectionName
);
const oldName = existingCollection.collectionName;
const newName = collectionName;
const collectionNameupdate = await collectionsModel(
organization
).findOneAndUpdate(
@@ -348,25 +429,25 @@ export const updatecollection = async (
},
{ new: true }
);
// console.log('collectionNameupdate: ', collectionNameupdate);
// console.log('collectionNameupdate: ', collectionNameupdate);
if (collectionNameupdate) {
// ✅ If name changed, trigger file rename
if (collectionNameupdate && oldName !== newName) {
console.log(`Renaming model file from ${oldName}${newName}`);
// if (collectionNameupdate && oldName !== newName) {
// console.log(`Renaming model file from ${oldName} → ${newName}`);
await updateFilename({
projectName: existingProject.projectName,
// await updateFilename({
// projectName: existingProject.projectName,
oldModelName: existingCollection.collectionName,
newModelName: collectionName as string,
});
}
// oldModelName: existingCollection.collectionName,
// newModelName: collectionName as string,
// });
// }
return {
status: "Success",
data: {
collectionNameupdate: collectionNameupdate,
updateFileds: referencedEdges,
// updateFileds: referencedEdges,
},
};
} else {
@@ -699,6 +780,7 @@ export const UpdateAttributes = async (
});
if (!existingCollection) return { status: "Collection not found" };
let referencedEdges;
for (const attr of attributes) {
const fieldId = attr.fieldId;
if (attr.type === "Object") {
@@ -710,7 +792,7 @@ export const UpdateAttributes = async (
attributeparentId: fieldId,
isArchive: false,
});
console.log("existingsubcollection: ", existingsubcollection);
if (!existingsubcollection) {
const fieldnamefind = await collectionsModel(organization).findOne(
{
@@ -742,70 +824,100 @@ export const UpdateAttributes = async (
};
}
}
const referencedEdges = await collectionsModel(organization).find({
isArchive: false,
projectId,
attributes: {
$elemMatch: {
"refKey.collection_id": new mongoose.Types.ObjectId(
collectionNodeId
),
"refKey.fieldId": new mongoose.Types.ObjectId(fieldId),
},
},
});
console.log("referencedEdges: ", referencedEdges);
if (referencedEdges.length) {
for (const doc of referencedEdges) {
let updated = false;
if (attr.type) {
referencedEdges = await collectionsModel(organization)
.find({
isArchive: false,
projectId,
attributes: {
$elemMatch: {
"refKey.collection_id": new mongoose.Types.ObjectId(
collectionNodeId
),
"refKey.fieldId": new mongoose.Types.ObjectId(fieldId),
},
},
})
.select("attributes projectId collectionName type");
// for (const oldattr of doc.attributes) {
// console.log("oldattr: ", oldattr);
// const refKey = oldattr.refKey as any;
// if (
// refKey?.collection_id?.toString() ===
// collectionNodeId.toString() &&
// refKey?.fieldId?.toString() === fieldId.toString()
// ) {
// const oldType = oldattr.type;
// const newType = attr.type;
if (referencedEdges.length) {
for (const doc of referencedEdges) {
let updated = false;
try {
for (const oldattr of doc.attributes) {
const refKey = oldattr.refKey as any;
if (
refKey?.collection_id?.toString() ===
collectionNodeId.toString() &&
refKey?.fieldId?.toString() === fieldId.toString()
) {
const oldType = oldattr.type;
const newType = attr.type;
oldattr.type = newType as any;
updated = true;
}
}
// console.log("oldType:", oldType, "→ newType:", newType);
if (updated) {
doc.markModified("attributes");
await doc.save();
}
} catch (err: any) {
return { status: "Validation Error", data: err.message };
}
}
}
}
// // ✅ Update directly
// oldattr.type = newType as any;
if (attr.key) {
function updateModelName(
oldName: string,
newBaseName: string
): string {
const firstUnderscoreIndex = oldName.indexOf("_");
// updated = true;
// }
// }
if (firstUnderscoreIndex === -1) {
return newBaseName;
}
// if (updated) {
// doc.markModified("attributes");
// console.log("hi");
// await doc.save();
// console.log("hello");
// console.log("doc: ", doc);
// }
let prefix = oldName.slice(0, firstUnderscoreIndex);
if (!prefix || prefix === "undefined" || prefix === "") {
prefix = existingCollection?.collectionName as string;
// console.log(`⚠️ Prefix invalid, fallback used: ${prefix}`);
}
return `${prefix}_${newBaseName}`;
}
referencedEdges = await collectionsModel(organization)
.find({
isArchive: false,
projectId,
attributes: {
$elemMatch: {
"refKey.fieldId": new mongoose.Types.ObjectId(fieldId),
},
},
})
.select("attributes projectId collectionName type");
if (referencedEdges.length) {
for (const doc of referencedEdges) {
let updated = false;
try {
for (const oldattr of doc.attributes) {
console.log("oldattr: ", oldattr);
const refKey = oldattr.refKey as any;
if (
refKey?.collection_id?.toString() ===
collectionNodeId.toString() &&
refKey?.fieldId?.toString() === fieldId.toString()
) {
const oldType = oldattr.type;
const newType = attr.type;
oldattr.type = newType as any;
if (refKey?.fieldId?.toString() === fieldId.toString()) {
const oldName = oldattr.key;
const updateName = attr.key;
const newKey = updateModelName(oldName, updateName);
oldattr.key = newKey;
updated = true;
}
}
if (updated) {
doc.markModified("attributes");
await doc.save();
}
} catch (err: any) {
@@ -839,9 +951,9 @@ export const UpdateAttributes = async (
{ new: true }
);
console.log("editCollection", editCollection);
// console.log("editCollection", editCollection);
}
return { status: "Success" };
return { status: "Success", data: referencedEdges };
}
} catch (error: unknown) {
if (error instanceof Error) {
@@ -1142,23 +1254,24 @@ export const DuplicateAttributes = async (
(attr: any) => attr.key.toLowerCase() === attrKey.toLowerCase()
);
console.log("existingAttr: ", existingAttr);
if (existingAttr) {
let counter = 1;
let newKey = `${attrKey}(${counter})`;
console.log("attrKey: ", attrKey);
console.log("newKey: ", newKey);
while (
existingCollection.attributes.some(
(attr: any) => attr.key === newKey
)
) {
console.log("hi");
counter++;
newKey = `${attrKey}(${counter})`;
console.log("newKey: ", newKey);
}
// existingCollection.attributes.push({
// key: newKey,
// type: existingAttr.type,
// isArchive: false,
// });
} else {
return { status: "Attribute doesnot match" };
}
@@ -1230,7 +1343,6 @@ export const DelAttributes = async (
data: IAttributesDel
): Promise<Iresponse> => {
const { organization, userId, projectId, collectionNodeId, fieldId } = data;
console.log("data: ", data);
try {
const existingUser = await userModel(organization).findOne({
@@ -1251,7 +1363,6 @@ export const DelAttributes = async (
isArchive: false,
"attributes._id": new mongoose.Types.ObjectId(fieldId),
});
console.log("existingCollection: ", existingCollection);
if (!existingCollection) return { status: "Collection not found" };
const attribute = existingCollection.attributes.find(
@@ -1315,7 +1426,6 @@ export const addAttributes = async (
): Promise<Iresponse> => {
const { organization, projectId, userId, collectionNodeId, attributes } =
data;
console.log("data: ", data);
try {
const existingUser = await userModel(organization).findOne({
@@ -1343,7 +1453,6 @@ export const addAttributes = async (
const duplicate = existingAttributes.find(
(exAttr) => exAttr.key === attr.key && !exAttr.isArchive
);
console.log("duplicate: ", duplicate);
if (duplicate) {
return { status: `Attribute "${attr.key}" already exists` };
}

View File

@@ -26,9 +26,11 @@ interface IEdgeDelete {
userId: string;
edgeId: string;
}
interface Attribute {
interface IAttribute {
_id?: string;
key: string;
type: string;
keyType?: string;
isArchive: boolean;
refKey?: {
@@ -38,6 +40,7 @@ interface Attribute {
}
export const edgecreation = async (data: IEdge): Promise<Iresponse> => {
const { organization, projectId, from, to, cardinality, userId } = data;
console.log("data:edge ", data);
try {
const ExistingUser = await userModel(organization).findOne({
@@ -82,49 +85,84 @@ export const edgecreation = async (data: IEdge): Promise<Iresponse> => {
const collectionName = existingFromCollection.collectionName;
const fieldName = from.field;
const newFieldKey = `${collectionName}_${capitalizeFirst(fieldName)}`;
// const newFieldKey = `${collectionName}_${capitalizeFirst(fieldName)}`;
// console.log("newFieldKey: ", newFieldKey);
const fromField = existingFromCollection.attributes.find(
(attr: any) => attr.key === from.field
);
if (!fromField) {
return { status: "From field not found" };
}
const fromFieldId = [fromField].map((attr: any) => attr?._id)[0];
console.log("fromFieldId: ", fromFieldId);
const resolvedKey = await resolveForeignKey(
organization,
existingFromCollection,
fromField as any
);
console.log("resolvedKey: ", resolvedKey);
const newFieldKey = `${resolvedKey.sourceCollectionName}_${capitalizeFirst(
resolvedKey.sourceFieldName
)}`;
console.log('newFieldKey: ', newFieldKey);
const fieldType = normalizeType(fromField?.type);
// console.log("fieldType: ", fieldType);
const fieldExists = existingToCollection.attributes.some(
(attr: any) => attr.key === newFieldKey
);
console.log('fieldExists: ', fieldExists);
// const keyType =
// fromField?.keyType === "primary" ? "foreign" : fromField?.keyType;
// console.log('keyType: ', keyType);
if (!fieldExists) {
const newAttribute: any = {
key: newFieldKey,
type: fieldType,
keyType: resolvedKey.keyType,
refKey: {
collection_id: existingFromCollection._id,
fieldId: fromFieldId,
// collection_id: existingFromCollection._id,
// fieldId: fromFieldId,
collection_id: resolvedKey.sourceCollectionId,
fieldId: resolvedKey.sourceFieldId,
},
};
const fieldExists = existingToCollection.attributes.some(
(attr: any) => attr.key === newFieldKey
);
existingToCollection.attributes.push(newAttribute);
console.log('newAttribute: ', newAttribute);
if (!fieldExists) {
existingToCollection.attributes.push(newAttribute);
await existingToCollection.save();
console.log(
`✅ Added new foreign key '${newFieldKey}' in '${existingToCollection.collectionName}' referencing '${resolvedKey.sourceCollectionName}.${resolvedKey.sourceFieldName}'`
);
} else {
console.log(`⚠️ Field '${newFieldKey}' already exists in '${existingToCollection.collectionName}'`);
}
// existingToCollection.attributes.push(newAttribute);
// existingToCollection.attributes = existingToCollection.attributes.map(
// (attr: any) => ({
// ...attr,
// type: normalizeType(attr.type),
// })
// );
existingToCollection.attributes = existingToCollection.attributes.map(
(attr: any) => ({
...attr,
type: normalizeType(attr.type),
})
// await existingToCollection.save();
console.log("existingToCollection: ", existingToCollection);
const savedToCollection = await collectionsModel(organization).findById(
existingToCollection._id
);
const lastAttr = savedToCollection?.attributes?.at(-1);
await existingToCollection.save();
const savedToCollection = await collectionsModel(organization).findById(existingToCollection._id);
const lastAttr = savedToCollection?.attributes?.at(-1);
const fieldIdTo = (lastAttr as any)?._id;
console.log('fieldIdTo: ', fieldIdTo);
const fieldIdTo = (lastAttr as any)?._id;
// console.log(
// `Field ${newFieldKey} (type: ${fieldType}) added to TO collection with reference to ${existingFromCollection._id}`
@@ -132,8 +170,12 @@ console.log('fieldIdTo: ', fieldIdTo);
const newEdge = {
projectId,
from: { collection_id: existingFromCollection._id, field: from.field,fieldId:fromFieldId },
to: { collection_id: existingToCollection._id ,fieldId:fieldIdTo},
from: {
collection_id: existingFromCollection._id,
field: from.field,
fieldId: fromFieldId,
},
to: { collection_id: existingToCollection._id, fieldId: fieldIdTo },
cardinality,
createdAt: new Date(),
};
@@ -208,7 +250,6 @@ export const Alledges = async (data: IAllEdge): Promise<Iresponse> => {
};
export const deleteEdge = async (data: IEdgeDelete): Promise<Iresponse> => {
const { organization, projectId, edgeId, userId } = data;
console.log('data:edge ', data);
try {
const ExistingUser = await userModel(organization).findOne({
@@ -264,7 +305,6 @@ export const deleteEdge = async (data: IEdgeDelete): Promise<Iresponse> => {
console.log("Matched attribute not found in array");
}
} else {
// console.log('No attribute matches the given collection_id');
return { status: "No deleted in matched Document" };
}
}
@@ -312,3 +352,133 @@ const normalizeType = (type: any): string => {
return "string"; // fallback
};
interface IResolvedKey {
keyType: string;
sourceCollectionName: string;
sourceCollectionId: string;
sourceFieldId: string;
sourceFieldName: string;
}
/**
* Resolves the true origin of a foreign key.
* If "fromField" is a foreign key, it recursively traces back
* to its original primary field and returns its reference info.
*/
// export const resolveForeignKey = async (
// organization: string,
// fromCollection: any,
// fromField: IAttribute
// ): Promise<IResolvedKey> => {
// if (!fromField) {
// return {
// keyType: "normal",
// sourceCollectionName: fromCollection.collectionName,
// sourceCollectionId: fromCollection._id?.toString?.() || "",
// sourceFieldId: "",
// sourceFieldName: "",
// };
// }
// let keyType = fromField?.keyType || "normal";
// let sourceCollectionName = fromCollection.collectionName;
// let sourceCollectionId = fromCollection._id?.toString?.() || "";
// let sourceFieldId = fromField?._id?.toString?.() || "";
// let sourceFieldName = fromField?.key || "";
// // 🔁 If the field is foreign → trace back to original primary
// if (fromField?.keyType === "foreign" && fromField?.refKey) {
// const refCol = await collectionsModel(organization).findById(
// fromField.refKey.collection_id
// );
// if (refCol) {
// const primaryAttr = (refCol.attributes as IAttribute[]).find(
// (attr) => attr?._id?.toString?.() === fromField.refKey?.fieldId
// );
// if (primaryAttr) {
// console.log("🔁 Tracing back to original primary field...");
// // Recursive call to ensure multi-level tracing
// return await resolveForeignKey(organization, refCol, primaryAttr);
// }
// }
// }
// // ✅ If the field is primary, mark the propagated key as foreign
// if (fromField?.keyType === "primary") {
// keyType = "foreign";
// }
// return {
// keyType,
// sourceCollectionName,
// sourceCollectionId,
// sourceFieldId,
// sourceFieldName,
// };
// };
export const resolveForeignKey = async (
organization: string,
fromCollection: any,
fromField?: IAttribute
): Promise<IResolvedKey> => {
if (!fromField || !fromCollection) {
return {
keyType: "normal",
sourceCollectionName: fromCollection?.collectionName || "",
sourceCollectionId: fromCollection?._id?.toString?.() || "",
sourceFieldId: "",
sourceFieldName: "",
};
}
let keyType = fromField.keyType || "normal";
let sourceCollectionName = fromCollection.collectionName;
let sourceCollectionId = fromCollection._id?.toString?.() || "";
let sourceFieldId = fromField._id?.toString?.() || "";
let sourceFieldName = fromField.key || "";
// 🔁 Recursive tracing for both FOREIGN and SECONDARY with refKey
if (
(fromField.keyType === "foreign" || fromField.keyType === "secondary") &&
fromField.refKey
) {
const refCol = await collectionsModel(organization).findById(
fromField.refKey.collection_id
);
if (refCol) {
const refField = (refCol.attributes as IAttribute[]).find(
(attr) => attr?._id?.toString?.() === fromField.refKey?.fieldId
);
if (refField) {
console.log(
`🔁 Tracing ${fromField.keyType} key ${fromField.key}${refCol.collectionName}.${refField.key}`
);
// Recursive call — trace until primary
return await resolveForeignKey(organization, refCol, refField);
} else {
console.warn(
`⚠️ Field not found for refKey.fieldId: ${fromField.refKey?.fieldId}`
);
}
} else {
console.warn(
`⚠️ Collection not found for refKey.collection_id: ${fromField.refKey?.collection_id}`
);
}
}
// ✅ Convert primary to foreign for propagation
if (fromField.keyType === "primary") keyType = "foreign";
return {
keyType,
sourceCollectionName,
sourceCollectionId,
sourceFieldId,
sourceFieldName,
};
};

View File

@@ -32,9 +32,7 @@ export const folderProject = async (
return result;
};
const FILE_BACKEND_URL = process.env.FILE_BACKEND_URL;
console.log('FILE_BACKEND_URL: ', FILE_BACKEND_URL);
export const modelNodeFile = async (data: { projectName: string; models1: any[] }) => {
console.log('data:test ', data);
const FILE_BACKEND_URL = process.env.FILE_BACKEND_URL;
if (!FILE_BACKEND_URL) throw new Error("❌ FILE_BACKEND_URL not set");

View File

@@ -229,7 +229,6 @@ export const projectDatas = async (data: IgetProject): Promise<Iresponse> => {
})
.skip(skipdata)
.limit(limitdata);
console.log('projectDatas: ', projectDatas);
if (!projectDatas) return { status: "No project found" };
// const formattedProjects = projectDatas.map((proj: any) => {

View File

@@ -5,7 +5,7 @@ import {
FinalResponse,
validateFields,
} from "../utils/socketfunctionHelpers";
import { emitToSenderAndAdmins } from "../utils/emitEventResponse";
import { emitToRoom } from "../utils/emitEventResponse";
import { deleteEdge, edgecreation } from "../../shared/services/edgeService";
import {
addAttributes,
@@ -31,14 +31,20 @@ export const CollectionHandleEvent = async (
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionCreateResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionCreateResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await Nodecreation(data);
@@ -63,15 +69,15 @@ export const CollectionHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionCreateResponse,
response,
connectedUsersByOrg
);
if (room) {
console.log('room: ', room);
emitToRoom(io, socket, room, EVENTS.collectionCreateResponse, response);
}
};
export const CollectionUpdateHandleEvent = async (
event: string,
@@ -87,18 +93,24 @@ export const CollectionUpdateHandleEvent = async (
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionUpdateResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionUpdateResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await updatecollection(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
@@ -107,10 +119,9 @@ export const CollectionUpdateHandleEvent = async (
"User not found": { message: "User not found" },
"Collection not found": { message: "Collection not found" },
"Invalid ID": { message: "nvalid ID provided" },
};
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
@@ -119,15 +130,14 @@ export const CollectionUpdateHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data?.projectId;
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionUpdateResponse,
response,
connectedUsersByOrg
);
if (room) {
emitToRoom(io, socket, room, EVENTS.collectionUpdateResponse, response);
}
};
export const CollectioDeleteHandleEvent = async (
@@ -144,14 +154,20 @@ export const CollectioDeleteHandleEvent = async (
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionDeleteResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionDeleteResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await delCollection(data);
@@ -174,15 +190,14 @@ export const CollectioDeleteHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data?.projectId;
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionDeleteResponse,
response,
connectedUsersByOrg
);
if (room) {
emitToRoom(io, socket, room, EVENTS.collectionDeleteResponse, response);
}
};
export const CollectioDuplicateHandleEvent = async (
event: string,
@@ -198,14 +213,20 @@ export const CollectioDuplicateHandleEvent = async (
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionDeleteResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionDeleteResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await DuplicateCollection(data);
@@ -229,15 +250,14 @@ export const CollectioDuplicateHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data?.projectId;
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionDuplicateResponse,
response,
connectedUsersByOrg
);
if (room) {
emitToRoom(io, socket, room, EVENTS.collectionDuplicateResponse, response);
}
};
export const setAttributesHandleEvent = async (
event: string,
@@ -258,14 +278,20 @@ export const setAttributesHandleEvent = async (
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionAttributeSetResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionAttributeSetResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await addAttributes(data);
@@ -288,15 +314,20 @@ export const setAttributesHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data?.projectId;
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionAttributeSetResponse,
response,
connectedUsersByOrg
);
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionAttributeSetResponse,
response
);
}
};
export const AttributesDeleteHandleEvent = async (
event: string,
@@ -317,14 +348,20 @@ export const AttributesDeleteHandleEvent = async (
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionAttributeDeleteResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionAttributeDeleteResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await DelAttributes(data);
@@ -342,9 +379,7 @@ export const AttributesDeleteHandleEvent = async (
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
const result1_Datas =
(status === "Success") && result?.data
? result.data
: undefined;
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
@@ -352,15 +387,20 @@ export const AttributesDeleteHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data?.projectId;
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionAttributeDeleteResponse,
response,
connectedUsersByOrg
);
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionAttributeDeleteResponse,
response
);
}
};
export const AttributesUpdateHandleEvent = async (
event: string,
@@ -372,22 +412,24 @@ export const AttributesUpdateHandleEvent = async (
}
) => {
if (event !== EVENTS.collectionAttributeUpdate || !data?.organization) return;
const requiredFields = [
"collectionNodeId",
"projectId",
"organization",
];
const requiredFields = ["collectionNodeId", "projectId", "organization"];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionAttributeUpdateResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
let room: string | undefined;
if (data?.projectId) {
room = data.projectId.toString();
}
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionAttributeUpdateResponse,
ErrorResponse(missingFields, socket, room)
);
}
return;
}
const result = await UpdateAttributes(data);
@@ -402,9 +444,7 @@ export const AttributesUpdateHandleEvent = async (
const msg = messages[status] || { message: "Internal server error" };
const result_Datas =
(status === "Success") && result?.data
? result.data
: undefined;
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
@@ -412,13 +452,18 @@ export const AttributesUpdateHandleEvent = async (
messages,
result_Datas
);
let room: string | undefined;
if (data?.projectId) {
room = data?.projectId;
}
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.collectionAttributeUpdateResponse,
response,
connectedUsersByOrg
);
if (room) {
emitToRoom(
io,
socket,
room,
EVENTS.collectionAttributeUpdateResponse,
response
);
}
};

View File

@@ -37,7 +37,6 @@ export const edgeHandleEvent = async (
}
const result = await edgecreation(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
@@ -55,7 +54,6 @@ export const edgeHandleEvent = async (
const msg = messages[status] || { message: "Internal server error" };
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
console.log('result_Datas: ', result_Datas);
const response = FinalResponse(
status,
@@ -64,7 +62,6 @@ export const edgeHandleEvent = async (
messages,
result_Datas
);
console.log('response: ', response);
emitToSenderAndAdmins(
io,
@@ -104,7 +101,6 @@ export const deleteEdgeHandleEvent = async (
return;
}
const result = await deleteEdge(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
@@ -122,7 +118,6 @@ export const deleteEdgeHandleEvent = async (
messages,
result_Datas
);
console.log('response: ', response);
emitToSenderAndAdmins(
io,

View File

@@ -48,7 +48,6 @@ export const projectHandleEvent = async (
}
const subBkd = process.env.FILE_BACKEND_URL;
if (!subBkd) {
console.log('!subBkd: ', subBkd);
// res.status(500).json({
// message: "mainBkdUrl not configured",
// });
@@ -186,7 +185,6 @@ export const projectDeleteHandleEvent = async (
return;
}
const result = await DeleteProject(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {

View File

@@ -2,6 +2,7 @@ import { Server, Socket } from "socket.io";
import jwt from "jsonwebtoken";
import { eventHandlerMap } from "../events/eventHandaler";
import { existingUserData } from "../../shared/services/AuthService";
import { joinRoom, leaveRoom } from "../utils/room";
interface UserPayload {
userId: string;
@@ -111,12 +112,30 @@ export const SocketServer = async (io: Server) => {
organization,
});
// console.log(`✅ Connected to namespace ${nspName}: ${socket.id}`);
socket.on("joinRoom", (data) => {
if (!data?.projectId) {
console.warn("❌ joinRoom missing projectId or versionId");
return;
}
joinRoom(io, socket, {
projectId: data.projectId,
// Common event handler
userId,
organization,
});
});
// Group api socket event creation and some bug modification
// ✅ Optional leave room listener
socket.on("leaveRoom", (data) => {
if (!data?.projectId) return;
leaveRoom(io, socket, {
projectId: data.projectId,
organization,
userId,
});
});
socket.onAny((event: string, data: any, callback: any) => {
// console.log("🔥 Incoming socket event:", event);
const handler = eventHandlerMap[event];
// console.log("handler:", handler ? "✅ found" : "❌ undefined");
if (handler) {
handler(event, socket, io, data, connectedUsersByOrg, callback);
} else {

View File

@@ -91,11 +91,11 @@ export const emitToRoom = (
organization: result.organization,
};
console.log("🔥 EMIT TO ROOM:");
console.log("➡️ Event: ", event);
// console.log("🔥 EMIT TO ROOM:");
// console.log("➡️ Event: ", event);
console.log("📦 Full result input: ", result); // 👉 what you passed from observer
console.log("📤 Final payload being emitted: ", payload); // 👉 actual emitted payload
console.log("🏠 Room: ", room);
// console.log("📤 Final payload being emitted: ", payload); // 👉 actual emitted payload
// console.log("🏠 Room: ", room);
socket.to(room).emit(event, payload);

View File

@@ -0,0 +1,125 @@
import { Server, Socket } from "socket.io";
import { emitToRoom } from "./emitEventResponse";
import userModel from "../../shared/model/userModel";
import { EVENTS } from "../events/events";
const userFollowMap = new Map<string, string>(); // socketId -> followingUser
interface JoinRoomInput { projectId: string; userId: string; organization: string; }
interface LeaveRoomInput { projectId: string; userId: string; organization: string; }
// Build room data including followingUser
// export async function buildRoomDatas(socket: Socket, projectId: string, organization: string) {
// let roomDatas: { roomName: string; Users: string[]; UsersDetails: any[] } | null = null;
// const rooms = socket.nsp.adapter.rooms;
// for (const [roomName, socketsSet] of rooms) {
// if (socket.nsp.sockets.get(roomName)) continue; // skip personal room
// // Collect all users in the room
// const roomUsers = [...socketsSet].map(id => {
// const s = socket.nsp.sockets.get(id);
// return {
// userId: s?.data.userId || id,
// socketId: id // store socketId for followUser map lookup
// };
// });
// const userIds = roomUsers.map(u => u.userId);
// const usersFromDB = await userModel(organization).find({ _id: { $in: userIds }, isArchive: false });
// const userdatas = usersFromDB.flatMap(user => {
// const userCams = cameraFromDB.filter(cam => cam.userId.toString() === user._id.toString());
// // find the socketId of this user in the room
// const userSocketId = roomUsers.find(u => u.userId === user._id.toString())?.socketId;
// const followingUser = userSocketId ? userFollowMap.get(userSocketId) || null : null;
// if (userCams.length === 0) {
// return [{
// userId: user._id.toString(),
// userName: user.userName,
// projectId,
// versionId: "",
// camData: { position: { x:0, y:40, z:30 }, rotation: { x:0, y:0, z:0 }, target: { x:0, y:0, z:0 } },
// followingUser
// }];
// }
// return userCams.map(cam => ({
// userId: user._id.toString(),
// userName: user.userName,
// projectId: cam.projectId.toString(),
// versionId: cam.versionId?.toString() || "",
// camData: { position: cam.position, rotation: cam.rotation, target: cam.target },
// followingUser
// }));
// });
// roomDatas = { roomName, Users: roomUsers.map(u => u.userId), UsersDetails: userdatas };
// break; // only process the first room
// }
// return roomDatas || { roomName: projectId, Users: [], UsersDetails: [] };
// }
// Join Room
export const joinRoom = async (io: Server, socket: Socket, data: JoinRoomInput) => {
const { projectId, organization, userId } = data;
socket.data.userId = userId;
const room = `${projectId}`;
await socket.join(room);
// const roomDatas = await buildRoomDatas(socket, projectId, organization);
// emitToRoom(io, socket, room, EVENTS.roomUserData_v1, {
// // data: roomDatas,
// socketId: socket.id
// });
return room;
};
// Leave Room
export const leaveRoom = async (io: Server, socket: Socket, data: LeaveRoomInput) => {
const { projectId, userId, organization } = data;
const room = `${projectId}`;
socket.leave(room);
// const roomDatas = await buildRoomDatas(socket, projectId, organization);
// emitToRoom(io, socket, room, EVENTS.roomUserData_v1, {
// data: roomDatas || { roomName: projectId, Users: [], UsersDetails: [] },
// message: `${userId} left the room`,
// socketId: socket.id
// });
userFollowMap.delete(socket.id);
return room;
};
// Follow User
// export const setupFollowUser = (io: Server, socket: Socket) => {
// socket.on(EVENTS.roomUserData_setV1, async (data: { projectId: string; followingUser: string; organization: string }) => {
// const { projectId, followingUser, organization } = data;
// userFollowMap.set(socket.id, followingUser);
// const roomDatas = await buildRoomDatas(socket, projectId, organization);
// const room = `${projectId}`;
// // emitToRoom(io, socket, room, EVENTS.roomUserData_v1, {
// // data: roomDatas,
// // socketId: socket.id
// // });
// // console.log(`User ${socket.data.userId} followed: ${followingUser}`);
// });
// socket.on("disconnect", () => {
// userFollowMap.delete(socket.id);
// });
// };