Update event handling and improve project and collection management logic

This commit is contained in:
2025-10-25 16:03:36 +05:30
parent e86a6609b0
commit 09c88c3396
10 changed files with 291 additions and 76 deletions

2
.env
View File

@@ -1,4 +1,4 @@
MONGO_URI=mongodb://192.168.0.212/
MONGO_URI=mongodb://192.168.0.213/
MONGO_USER=mydata
MONGO_PASSWORD=mongodb@hexr2002
MONGO_AUTH_DB=admin

View File

@@ -167,7 +167,7 @@ export const updateCollectionController = async (
break;
case "Success":
res.status(200).json({
message: "collection name updated",
message: "collection updated successfully",
});
break;
default:

View File

@@ -373,11 +373,6 @@ export const updateProjectController = async (
case "Project not found":
res.status(404).json({ message: "Project not found" });
break;
case "No access granted to delete this project":
res
.status(200)
.json({ message: "No access granted to update this project" });
break;
case "Project update unsuccessfull":
res.status(200).json({ message: "Project update unsuccessfull" });
break;

View File

@@ -1401,6 +1401,7 @@ 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({
@@ -1421,6 +1422,7 @@ 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(

View File

@@ -164,7 +164,7 @@ export const projectCreationService = async (
}
);
}
return { status: "Success", data: newProject._id };
return { status: "Success", data: newProject };
} else {
return {
status: "Already MVC architecture assigned to this projectId",
@@ -181,7 +181,7 @@ export const projectCreationService = async (
description,
});
if (!newProject) return { status: "Project creation unsuccessfull" };
return { status: "Success", data: newProject._id };
return { status: "Success", data: newProject };
}
}
} catch (error: unknown) {
@@ -466,7 +466,7 @@ export const projectModification = async (
{ new: true }
);
if (!updateProject) return { status: "Project updated unsuccessfull" };
return { status: "Success" };
return { status: "Success" ,data:updateProject};
} catch (error: unknown) {
if (error instanceof Error) {
return {

View File

@@ -13,8 +13,8 @@ import {
delCollection,
DuplicateCollection,
Nodecreation,
SetCollectionName,
UpdateAttributes,
updatecollection,
} from "../../shared/services/collectionService";
export const CollectionHandleEvent = async (
@@ -76,7 +76,7 @@ export const CollectionHandleEvent = async (
connectedUsersByOrg
);
};
export const CollectioNamenHandleEvent = async (
export const CollectionUpdateHandleEvent = async (
event: string,
socket: Socket,
io: Server,
@@ -85,13 +85,8 @@ export const CollectioNamenHandleEvent = async (
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.collectionNameSet || !data?.organization) return;
const requiredFields = [
"collectionName",
"collectionNodeId",
"projectId",
"organization",
];
if (event !== EVENTS.collectionUpdate || !data?.organization) return;
const requiredFields = ["collectionNodeId", "projectId", "organization"];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
@@ -99,23 +94,24 @@ export const CollectioNamenHandleEvent = async (
io,
socket,
data.organization,
EVENTS.collectionNameSetResponse,
EVENTS.collectionUpdateResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await SetCollectionName(data);
const result = await updatecollection(data);
console.log("result: ", result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "collection name updated" },
"Collection not found": { message: "Collection not found" },
Success: { message: "collection updated successfully" },
"Project not found": { message: "Project not found" },
};
"User not found": { message: "User not found" },
"Collection not found": { message: "Collection not found" },
"Invalid ID": { message: "nvalid ID provided" },
const msg = messages[status] || { message: "Internal server error" };
};
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
console.log("result_Datas: ", result_Datas);
@@ -133,11 +129,12 @@ export const CollectioNamenHandleEvent = async (
io,
socket,
data.organization,
EVENTS.collectionNameSetResponse,
EVENTS.collectionUpdateResponse,
response,
connectedUsersByOrg
);
};
export const CollectioDeleteHandleEvent = async (
event: string,
socket: Socket,
@@ -350,7 +347,9 @@ export const AttributesDeleteHandleEvent = async (
const messages: Record<string, { message: string }> = {
Success: { message: "Field deleted successfully" },
"User not found": { message: "User not found" },
"Project not found": { message: "Project not found" },
"Attribute not found": { message: "field not found" },
"Collection not found": { message: "Collection not found" },
};
@@ -358,7 +357,11 @@ export const AttributesDeleteHandleEvent = async (
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
console.log("result_Datas: ", result_Datas);
const result1_Datas =
(status === "Success") && result?.data
? result.data
: undefined;
console.log('result1_Datas: ', result1_Datas);
const response = FinalResponse(
status,
socket,
@@ -388,7 +391,6 @@ export const AttributesUpdateHandleEvent = async (
) => {
if (event !== EVENTS.collectionAttributeUpdate || !data?.organization) return;
const requiredFields = [
"fieldId",
"collectionNodeId",
"projectId",
"organization",
@@ -417,10 +419,11 @@ export const AttributesUpdateHandleEvent = 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 result_Datas =
(status === "Success") && result?.data
? result.data
: undefined;
const response = FinalResponse(
status,
socket,

View File

@@ -6,7 +6,13 @@ import {
validateFields,
} from "../utils/socketfunctionHelpers";
import { emitToSenderAndAdmins } from "../utils/emitEventResponse";
import { projectCreationService } from "../../shared/services/projectService";
import {
DeleteProject,
projectClear,
projectCreationService,
projectModification,
} from "../../shared/services/projectService";
import { updateProjectController } from "../../api-server/controller/projectController";
export const projectHandleEvent = async (
event: string,
@@ -72,3 +78,166 @@ export const projectHandleEvent = async (
connectedUsersByOrg
);
};
export const projectUpdateHandleEvent = async (
event: string,
socket: Socket,
io: Server,
data: any,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.projectUpdate || !data?.organization) return;
const requiredFields = ["projectId", "organization"];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.projectUpdateResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await projectModification(data);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "Project updated successfully" },
"Project not found": { message: "Project not found" },
"Project update unsuccessfull": {
message: "Project update unsuccessfull",
},
"User not found": { message: "User not found" },
};
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
data.organization,
messages,
result_Datas
);
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.projectUpdateResponse,
response,
connectedUsersByOrg
);
};
export const projectDeleteHandleEvent = async (
event: string,
socket: Socket,
io: Server,
data: any,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.projectDelete || !data?.organization) return;
const requiredFields = ["projectId", "organization"];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.projectDeleteResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await DeleteProject(data);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "Project deleted successfully" },
"Project not found": { message: "Project not found" },
"User not found": { message: "User not found" },
"No access granted to delete this project": {
message: "No access granted to delete this project",
},
"Project Delete unsuccessfull": {
message: "Project Delete unsuccessfull",
},
};
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
data.organization,
messages,
result_Datas
);
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.projectDeleteResponse,
response,
connectedUsersByOrg
);
};
export const projectClearHandleEvent = async (
event: string,
socket: Socket,
io: Server,
data: any,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.projectClear || !data?.organization) return;
const requiredFields = ["projectId", "organization"];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.projectClearResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await projectClear(data);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "Datas cleared successfully" },
"Project not found": { message: "Project not found" },
"User not found": { message: "User not found" },
"Validation Error": { message: "Validation Error" },
};
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
data.organization,
messages,
result_Datas
);
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.projectClearResponse,
response,
connectedUsersByOrg
);
};

View File

@@ -1,17 +1,35 @@
import { AttributesDeleteHandleEvent, AttributesUpdateHandleEvent, CollectioDeleteHandleEvent, CollectioDuplicateHandleEvent, CollectioNamenHandleEvent, CollectionHandleEvent, setAttributesHandleEvent } from "../controllers/collectionNodeController";
import { edgeHandleEvent } from "../controllers/edgeController";
import { projectHandleEvent } from "../controllers/projectController";
import {
AttributesDeleteHandleEvent,
AttributesUpdateHandleEvent,
CollectioDeleteHandleEvent,
CollectioDuplicateHandleEvent,
CollectionHandleEvent,
CollectionUpdateHandleEvent,
setAttributesHandleEvent,
} from "../controllers/collectionNodeController";
import { deleteEdgeHandleEvent, edgeHandleEvent } from "../controllers/edgeController";
import {
projectClearHandleEvent,
projectDeleteHandleEvent,
projectHandleEvent,
projectUpdateHandleEvent,
} from "../controllers/projectController";
import { EVENTS } from "./events";
export const eventHandlerMap: Record<string, Function> = {
[EVENTS.edgeConnect]: edgeHandleEvent,
[EVENTS.projectCreate]: projectHandleEvent,
[EVENTS.projectCreate]: projectHandleEvent,
[EVENTS.projectUpdate]: projectUpdateHandleEvent,
[EVENTS.projectDelete]: projectDeleteHandleEvent,
[EVENTS.projectClear]: projectClearHandleEvent,
[EVENTS.collectionCreate]: CollectionHandleEvent,
[EVENTS.collectionNameSet]: CollectioNamenHandleEvent,
[EVENTS.collectionDelete]: CollectioDeleteHandleEvent,
[EVENTS.collectionDuplicate]: CollectioDuplicateHandleEvent,
[EVENTS.collectionAttributeSet]: setAttributesHandleEvent,
[EVENTS.collectionAttributeDelete]: AttributesDeleteHandleEvent,
[EVENTS.collectionAttributeUpdate]: AttributesUpdateHandleEvent,
[EVENTS.collectionCreate]: CollectionHandleEvent,
[EVENTS.collectionUpdate]: CollectionUpdateHandleEvent,
[EVENTS.collectionDelete]: CollectioDeleteHandleEvent,
[EVENTS.collectionDuplicate]: CollectioDuplicateHandleEvent,
[EVENTS.collectionAttributeSet]: setAttributesHandleEvent,
[EVENTS.collectionAttributeDelete]: AttributesDeleteHandleEvent,
[EVENTS.collectionAttributeUpdate]: AttributesUpdateHandleEvent,
[EVENTS.edgeConnect]: edgeHandleEvent,
[EVENTS.deleteEdgeConnect]: deleteEdgeHandleEvent,
};

View File

@@ -12,21 +12,30 @@ export const EVENTS = {
projectCreate: "v1:project:create",
projectCreateResponse: "v1:response:project:create",
projectUpdate: "v1:project:update",
projectUpdateResponse: "v1:response:project:update",
projectDelete: "v1:project:delete",
projectDeleteResponse: "v1:response:project:delete",
projectClear: "v1:project:clear",
projectClearResponse: "v1:response:project:clear",
collectionCreate: "v1:collection:create",
collectionCreateResponse: "v1:response:collection:create",
collectionNameSet: "v1:collection:setName",
collectionNameSetResponse: "v1:response:collection:setName",
collectionDelete: "v1:collection:delete",
collectionDeleteResponse: "v1:response:collection:delete",
collectionDuplicate: "v1:collection:duplicate",
collectionDuplicateResponse: "v1:response:collection:duplicate",
collectionAttributeSet: "v1:collection:attributeSet",
collectionAttributeSetResponse: "v1:response:collection:attributeSet",
collectionAttributeUpdate: "v1:collection:attributeUpdate",
collectionAttributeUpdateResponse: "v1:response:collection:attributeUpdate",
collectionAttributeDelete: "v1:collection:attributeDelete",
collectionAttributeDeleteResponse: "v1:response:collection:attributeDelete",
collectionCreate: "v1:collection-node:create",
collectionCreateResponse: "v1:response:collection-node:create",
collectionUpdate: "v1:collection-node:update",
collectionUpdateResponse: "v1:response:collection-node:update",
collectionNameSet: "v1:collection-node:setName",
collectionNameSetResponse: "v1:response:collection-node:setName",
collectionDelete: "v1:collection-node:delete",
collectionDeleteResponse: "v1:response:collection-node:delete",
collectionDuplicate: "v1:collection-node:duplicate",
collectionDuplicateResponse: "v1:response:collection-node:duplicate",
collectionAttributeSet: "v1:collection-node:attributeSet",
collectionAttributeSetResponse: "v1:response:collection-node:attributeSet",
collectionAttributeUpdate: "v1:collection-node:attributeUpdate",
collectionAttributeUpdateResponse: "v1:response:collection-node:attributeUpdate",
collectionAttributeDelete: "v1:collection-node:attributeDelete",
collectionAttributeDeleteResponse: "v1:response:collection-node:attributeDelete",
edgeConnect: "v1:edge:connect",
edgeConnectResponse: "v1:response:edge:connect",

View File

@@ -18,42 +18,53 @@ interface UserSocketInfo {
const connectedUsersByOrg: { [organization: string]: UserSocketInfo[] } = {};
export const SocketServer = async (io: Server) => {
const namespaceNames = ["/edge", "/project", "/collection"];
const onlineUsers: { [organization: string]: Set<string> } = {};
namespaceNames.forEach((nspName) => {
const namespace = io.of(nspName);
namespace.use(async (socket: Socket, next) => {
try {
const accessToken = socket.handshake.auth.accessToken as string;
const refreshToken = socket.handshake.auth.refreshToken as string;
const accessToken =
socket.handshake.auth?.accessToken ||
socket.handshake.headers?.accesstoken;
const refreshToken =
socket.handshake.auth?.refreshToken ||
socket.handshake.headers?.refreshToken;
if (!accessToken) return next(new Error("No access token provided"));
const jwt_secret = process.env.JWT_SECRET as string;
try {
const decoded = jwt.verify(accessToken, jwt_secret) as UserPayload;
const mailExistance = await existingUserData(decoded.email, decoded.organization);
const mailExistance = await existingUserData(
decoded.email,
decoded.organization
);
if (!mailExistance) {
return next(new Error("Unauthorized user - not in system"));
}
(socket as any).user = decoded;
return next();
} catch (err: any) {
if (err.name === "TokenExpiredError") {
if (!refreshToken) {
return next(new Error("Token expired and no refresh token provided"));
return next(
new Error("Token expired and no refresh token provided")
);
}
try {
const refreshSecret = process.env.REFRESH_JWT_SECRET as string;
const decodedRefresh = jwt.verify(refreshToken, refreshSecret) as UserPayload;
const mailExistance = await existingUserData(decodedRefresh.email, decodedRefresh.organization);
const decodedRefresh = jwt.verify(
refreshToken,
refreshSecret
) as UserPayload;
const mailExistance = await existingUserData(
decodedRefresh.email,
decodedRefresh.organization
);
if (!mailExistance) {
return next(new Error("Unauthorized user - not in system"));
@@ -61,9 +72,12 @@ export const SocketServer = async (io: Server) => {
// Generate new access token
const newAccessToken = jwt.sign(
{ email: decodedRefresh.email, organization: decodedRefresh.organization },
{
email: decodedRefresh.email,
organization: decodedRefresh.organization,
},
jwt_secret,
{ expiresIn: "3h" } // adjust expiry
{ expiresIn: "3h" } // adjust expiry
);
socket.emit("newAccessToken", newAccessToken);
@@ -88,8 +102,13 @@ export const SocketServer = async (io: Server) => {
if (!onlineUsers[organization]) onlineUsers[organization] = new Set();
onlineUsers[organization].add(socket.id);
if (!connectedUsersByOrg[organization]) connectedUsersByOrg[organization] = [];
connectedUsersByOrg[organization].push({ socketId: socket.id, userId, organization });
if (!connectedUsersByOrg[organization])
connectedUsersByOrg[organization] = [];
connectedUsersByOrg[organization].push({
socketId: socket.id,
userId,
organization,
});
console.log(`✅ Connected to namespace ${nspName}: ${socket.id}`);
// Common event handler
@@ -107,9 +126,9 @@ export const SocketServer = async (io: Server) => {
if (onlineUsers[organization]?.size === 0) {
delete onlineUsers[organization];
}
connectedUsersByOrg[organization] = connectedUsersByOrg[organization]?.filter(
(u) => u.socketId !== socket.id
);
connectedUsersByOrg[organization] = connectedUsersByOrg[
organization
]?.filter((u) => u.socketId !== socket.id);
});
});
});