Project Create and Get All projects API completed
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import * as express from "express";
|
||||
import { createProjectController } from "../controller/project/projectController.ts";
|
||||
import { createProjectController, GetProjects } from "../controller/project/projectController.ts";
|
||||
|
||||
const projectRouter = express.Router();
|
||||
projectRouter.post("/upsertProject",createProjectController)
|
||||
projectRouter.get("/Projects/:userId/:organization",GetProjects)
|
||||
export default projectRouter
|
||||
@@ -53,7 +53,11 @@ app.use(cors());
|
||||
// },
|
||||
// credentials: true
|
||||
// }));
|
||||
app.use(express.json());
|
||||
|
||||
app.use(express.json({ limit: "50mb" }));
|
||||
app.use(
|
||||
express.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 })
|
||||
);
|
||||
dotenv.config();
|
||||
app.get("/", (req, res) => {
|
||||
res.send("Hello, I am Major-Dwinzo API!");
|
||||
@@ -62,6 +66,7 @@ app.get("/", (req, res) => {
|
||||
app.get("/health", (req, res) => {
|
||||
res.status(200).json({ message: "Server is running" });
|
||||
});
|
||||
|
||||
app.use("/api/v1", cameraRoutes);
|
||||
app.use("/api/v1", environmentsRoutes);
|
||||
app.use("/api/v1", linesRoutes);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Request, Response } from "express";
|
||||
import { createProject } from "../../../shared/services/project/project-Services.ts";
|
||||
import { createProject,GetAllProjects } from "../../../shared/services/project/project-Services.ts";
|
||||
|
||||
export const createProjectController = async (
|
||||
req: Request,
|
||||
@@ -7,7 +7,6 @@ export const createProjectController = async (
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const result = await createProject(req.body);
|
||||
console.log("result: ", result);
|
||||
|
||||
switch (result.status) {
|
||||
case "project_exists":
|
||||
@@ -45,3 +44,40 @@ export const createProjectController = async (
|
||||
});
|
||||
}
|
||||
};
|
||||
export const GetProjects = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { userId, organization } = req.params;
|
||||
const result = await GetAllProjects({ userId, organization});
|
||||
switch (result?.status) {
|
||||
|
||||
case "User not found":
|
||||
res.status(404).json({
|
||||
message: "User not found",
|
||||
});
|
||||
break;
|
||||
|
||||
case "success":
|
||||
res.status(201).json({
|
||||
Projects: result?.Datas,
|
||||
});
|
||||
break;
|
||||
case "All fields are required":
|
||||
res.status(400).json({
|
||||
message: "All fields are required",
|
||||
});
|
||||
break;
|
||||
default:
|
||||
res.status(500).json({
|
||||
message: "Internal server error",
|
||||
});
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
message: "Unknown error",
|
||||
});
|
||||
}
|
||||
};
|
||||
10
src/shared/connect/blobConnection.ts
Normal file
10
src/shared/connect/blobConnection.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Client } from 'minio';
|
||||
const minioClient = new Client({
|
||||
endPoint: process.env.MinIO_URL!,
|
||||
port: parseInt(process.env.MinIO_PORT!, 10),
|
||||
useSSL: false,
|
||||
accessKey: process.env.MinIO_accessKey!,
|
||||
secretKey: process.env.MinIO_secretKey!,
|
||||
});
|
||||
|
||||
export { minioClient}
|
||||
@@ -49,12 +49,6 @@ const MainModel = <T>(
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
export const minioClient = new Client({
|
||||
endPoint: "185.100.212.76", // MinIO server IP or hostname
|
||||
port: 9999, // MinIO server port
|
||||
useSSL: false, // Set to true if SSL is configured
|
||||
accessKey: "sabarinathan", // Access key
|
||||
secretKey: "sabarinathan",
|
||||
});
|
||||
|
||||
|
||||
export default MainModel;
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface Project extends Document {
|
||||
}
|
||||
const projectSchema: Schema = new Schema(
|
||||
{
|
||||
projectUuid: { type: String, required: true },
|
||||
projectUuid: { type: String },
|
||||
projectName: { type: String },
|
||||
thumbnail: { type: String },
|
||||
isArchive: { type: Boolean, default: false },
|
||||
|
||||
67
src/shared/services/blob/blobServices.ts
Normal file
67
src/shared/services/blob/blobServices.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { minioClient } from "../../connect/blobConnection.ts";
|
||||
|
||||
type MulterFile = {
|
||||
fieldname: string;
|
||||
originalname: string;
|
||||
encoding: string;
|
||||
mimetype: string;
|
||||
size: number;
|
||||
buffer: Buffer;
|
||||
};
|
||||
|
||||
const bucketName = "assets-public-bucket";
|
||||
|
||||
// Define public read policy
|
||||
const publicReadPolicy = {
|
||||
Version: "2012-10-17",
|
||||
Statement: [
|
||||
{
|
||||
Effect: "Allow",
|
||||
Principal: { AWS: "*" },
|
||||
Action: ["s3:GetObject"],
|
||||
Resource: [`arn:aws:s3:::${bucketName}/*`],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async function ensureBucketExists() {
|
||||
const exists = await minioClient.bucketExists(bucketName);
|
||||
if (!exists) {
|
||||
await minioClient.makeBucket(bucketName, "local-region");
|
||||
console.log("Bucket created");
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureFolderExists(folderName: string) {
|
||||
const folderPrefix = folderName.endsWith("/") ? folderName : `${folderName}/`;
|
||||
const objects = minioClient.listObjects(bucketName, folderPrefix, true);
|
||||
for await (const _ of objects) return; // Folder exists
|
||||
await minioClient.putObject(bucketName, folderPrefix, Buffer.from(""));
|
||||
}
|
||||
|
||||
async function setPublicPolicy() {
|
||||
await minioClient.setBucketPolicy(bucketName, JSON.stringify(publicReadPolicy));
|
||||
}
|
||||
|
||||
export async function uploadProjectThumbnail(file: MulterFile, folderName: string): Promise<string> {
|
||||
try {
|
||||
const folderName = "models";
|
||||
const objectName = `${folderName}/${Date.now()}_${file.originalname}`;
|
||||
|
||||
|
||||
await ensureBucketExists();
|
||||
await ensureFolderExists(folderName);
|
||||
await minioClient.putObject(bucketName, objectName, file.buffer, file.size, {
|
||||
"Content-Type": file.mimetype,
|
||||
});
|
||||
await setPublicPolicy();
|
||||
|
||||
const encodedName = encodeURIComponent(objectName);
|
||||
const blobUrl = `${process.env.MinIO_USESSL === "true" ? "https" : "http"}://${process.env.MinIO_URL}:${process.env.MINIO_PORT}/${bucketName}/${encodedName}`;
|
||||
|
||||
return blobUrl;
|
||||
} catch (err) {
|
||||
console.error("Upload failed:", err);
|
||||
throw new Error("Thumbnail upload failed");
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import projectModel from "../../model/project/project-model.ts";
|
||||
import userModel from "../../model/user-Model.ts";
|
||||
import { Types } from "mongoose";
|
||||
import versionModel from "../../model/version/versionModel.ts";
|
||||
import { uploadProjectThumbnail } from "../blob/blobServices.ts";
|
||||
|
||||
interface CreateProjectInput {
|
||||
projectName: string;
|
||||
projectUuid: string;
|
||||
@@ -10,7 +12,10 @@ interface CreateProjectInput {
|
||||
sharedUsers?: string[];
|
||||
organization: string;
|
||||
}
|
||||
|
||||
interface GetInterface {
|
||||
userId: string;
|
||||
organization: string;
|
||||
}
|
||||
export const createProject = async (data: CreateProjectInput) => {
|
||||
try {
|
||||
const {
|
||||
@@ -21,9 +26,9 @@ export const createProject = async (data: CreateProjectInput) => {
|
||||
sharedUsers,
|
||||
organization,
|
||||
} = data;
|
||||
|
||||
if (
|
||||
!projectName ||
|
||||
!projectUuid ||
|
||||
!userId ||
|
||||
!thumbnail ||
|
||||
// !sharedUsers ||
|
||||
@@ -36,7 +41,7 @@ export const createProject = async (data: CreateProjectInput) => {
|
||||
status: "user_not_found",
|
||||
};
|
||||
}
|
||||
const projectExisting = await existingProject(projectUuid, organization);
|
||||
const projectExisting = await existingProject(projectName, organization,userId);
|
||||
|
||||
if (projectExisting) {
|
||||
return {
|
||||
@@ -49,17 +54,18 @@ export const createProject = async (data: CreateProjectInput) => {
|
||||
projectName: projectName,
|
||||
projectUuid: projectUuid,
|
||||
createdBy: userId,
|
||||
thumbnail: thumbnail || "",
|
||||
thumbnail: thumbnail,
|
||||
sharedUsers: sharedUsers || [],
|
||||
isArchive: false,
|
||||
});
|
||||
const versionData = previousVersion(project._id, organization);
|
||||
if (!versionData) {
|
||||
await versionModel(organization).create({
|
||||
const versionData = await previousVersion(project._id, organization);
|
||||
if (!versionData || versionData.length === 0) {
|
||||
const newVersion= await versionModel(organization).create({
|
||||
projectId: project._id,
|
||||
createdBy: userId,
|
||||
version: 0.01,
|
||||
});
|
||||
await projectModel(organization).findByIdAndUpdate({_id:project._id,isArchive:false},{total_versions:`v-${newVersion.version.toFixed(2)}`})
|
||||
}
|
||||
return {
|
||||
status: "success",
|
||||
@@ -73,7 +79,7 @@ export const createProject = async (data: CreateProjectInput) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const GetAllProjects = async (data: CreateProjectInput) => {
|
||||
export const GetAllProjects = async (data: GetInterface) => {
|
||||
try {
|
||||
const { userId, organization } = data;
|
||||
await existingUser(userId, organization);
|
||||
@@ -83,18 +89,20 @@ export const GetAllProjects = async (data: CreateProjectInput) => {
|
||||
isArchive: false,
|
||||
})
|
||||
.select("_id projectName createdBy thumbnail");
|
||||
if (projectDatas) return { Datas: projectDatas };
|
||||
if (projectDatas) return {status:"success", Datas: projectDatas };
|
||||
} catch (error: unknown) {
|
||||
return { status: error };
|
||||
}
|
||||
};
|
||||
|
||||
export const existingProject = async (
|
||||
projectUuid: string,
|
||||
organization: string
|
||||
projectName: string,
|
||||
organization: string,
|
||||
userId:string
|
||||
) => {
|
||||
const projectData = await projectModel(organization).findOne({
|
||||
projectUuid: projectUuid,
|
||||
projectName: projectName,
|
||||
createdBy:userId,
|
||||
isArchive: false,
|
||||
});
|
||||
return projectData;
|
||||
@@ -124,12 +132,10 @@ export const archiveProject = async (
|
||||
export const previousVersion = async (
|
||||
projectId: string,
|
||||
organization: string
|
||||
): Promise<void> => {
|
||||
const result = await versionModel(organization)
|
||||
.findOne({
|
||||
projectId: projectId,
|
||||
isArchive: false,
|
||||
})
|
||||
.sort({ version: -1 });
|
||||
)=> {
|
||||
console.log('projectId: ', projectId);
|
||||
const result = await versionModel(organization).findOne({ projectId: projectId, isArchive: false})
|
||||
console.log('result: ', result);
|
||||
// .sort({ version: -1 });
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { Socket } from "socket.io";
|
||||
import { Socket, Server } from "socket.io";
|
||||
import { createProject } from "../../../shared/services/project/project-Services.ts";
|
||||
import { EVENTS } from "../../socket/events.ts";
|
||||
import { emitEventResponse } from "../../utils/emitEventResponse.ts";
|
||||
|
||||
export const projectHandleEvent = async (
|
||||
event: string,
|
||||
socket: Socket,
|
||||
data: any,
|
||||
namespace: any
|
||||
namespace: any,
|
||||
io: Server // Make sure this is passed in from the socket manager
|
||||
) => {
|
||||
if (!data?.organization) {
|
||||
console.warn(`Missing organization in event: ${event}`);
|
||||
console.log(`Missing organization in event: ${event}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,29 +20,29 @@ export const projectHandleEvent = async (
|
||||
switch (event) {
|
||||
case EVENTS.addProject: {
|
||||
result = await createProject(data);
|
||||
|
||||
// Create response object
|
||||
console.log('result: ', result);
|
||||
const isSuccess = result.status === "success";
|
||||
// ✅ Build response object
|
||||
const response = {
|
||||
success: result.status === "success",
|
||||
message:
|
||||
result.status === "project_exists"
|
||||
? "Project already exists"
|
||||
: result.status === "user_not_found"
|
||||
? "User not found"
|
||||
: result.status === "invalid_user_id"
|
||||
? "Invalid User ID"
|
||||
: result.status === "success"
|
||||
? "Project created successfully"
|
||||
: "Something went wrong",
|
||||
data: result.project || null,
|
||||
status: result.status,
|
||||
? "User not found"
|
||||
: result.status === "invalid_user_id"
|
||||
? "Invalid User ID"
|
||||
: isSuccess
|
||||
? "Project created successfully"
|
||||
: "Something went wrong",
|
||||
...(isSuccess ? { data: result.project } : {}),
|
||||
status: String(result.status),
|
||||
socketId: socket.id,
|
||||
organization: data.organization,
|
||||
};
|
||||
|
||||
// Emit response to the organization room
|
||||
|
||||
|
||||
// ✅ Emit response
|
||||
emitEventResponse(socket, data.organization, EVENTS.projectResponse, response);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import dotenv from "dotenv"; // Import dotenv
|
||||
dotenv.config();
|
||||
|
||||
import { initSocketServer } from "./socket/socketManager.ts";
|
||||
|
||||
import { SocketServer } from "./manager/manager.ts";
|
||||
const app = express();
|
||||
const PORT = process.env.SOCKET_PORT;
|
||||
const server = http.createServer(app);
|
||||
@@ -15,8 +15,8 @@ const server = http.createServer(app);
|
||||
app.get('/', (req: Request, res: Response) => {
|
||||
res.send('Hello, I am Major-Dwinzo RealTime!');
|
||||
});
|
||||
|
||||
initSocketServer(server);
|
||||
// SocketServer(server)
|
||||
server.listen(PORT, () => {
|
||||
console.log(`socket-Server is running on http://localhost:${PORT}`);
|
||||
});
|
||||
|
||||
78
src/socket-server/manager/manager.ts
Normal file
78
src/socket-server/manager/manager.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import { projectHandleEvent } from '../controllers/project/projectController.ts';
|
||||
|
||||
export const SocketServer = (httpServer: any) => {
|
||||
const io = new Server(httpServer, {
|
||||
cors: {
|
||||
origin: '*', // Allow CORS for all origins (adjust in production)
|
||||
methods: ['GET', 'POST'],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
const namespaces = {
|
||||
|
||||
project: io.of('/project'),
|
||||
|
||||
};
|
||||
|
||||
// const onlineUsers = new Map<string, Set<string>>();
|
||||
const onlineUsers: { [organization: string]: Set<string> } = {};
|
||||
|
||||
|
||||
const handleNamespace = ( namespace: any, ...eventHandlers: Function[]) => {
|
||||
|
||||
namespace.on("connection", (socket: Socket) => {
|
||||
console.log(`✅ Client connected to ${namespace.name}: ${socket.id}`);
|
||||
// Extract organization from query parameters
|
||||
|
||||
const organization = socket.handshake.query.organization as string;
|
||||
const email = socket.handshake.query.email as string;
|
||||
// const {organization,email} = socket.handshake.auth
|
||||
console.log(`🔍 Received organization: ${organization}`);
|
||||
|
||||
if (organization) {
|
||||
socket.join(organization);
|
||||
// console.log(`🔹 Socket ${socket.id} joined room: ${organization}`);
|
||||
}
|
||||
// Handle all events
|
||||
if (organization && email) {
|
||||
if (!onlineUsers[organization]) {
|
||||
onlineUsers[organization] = new Set();
|
||||
}
|
||||
onlineUsers[organization].add(socket.id);
|
||||
|
||||
}
|
||||
|
||||
// userStatus(EVENTS.connection, socket, socket.handshake.auth, socket);
|
||||
|
||||
socket.onAny((event: string, data: any ,callback:any) => {
|
||||
eventHandlers.forEach(handler => handler(event, socket, data, namespace,io,callback));
|
||||
});
|
||||
|
||||
// Handle disconnection
|
||||
socket.on("disconnect", () => {
|
||||
onlineUsers[organization]?.delete(socket.id);
|
||||
if (onlineUsers[organization]?.size === 0) delete onlineUsers[organization];
|
||||
// userStatus(EVENTS.disconnect, socket, socket.handshake.auth, socket);
|
||||
|
||||
});
|
||||
|
||||
// Handle reconnection (Auto rejoin)
|
||||
socket.on("reconnect", (attempt: number) => {
|
||||
|
||||
if (organization) {
|
||||
socket.join(organization);
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
handleNamespace(namespaces.project,projectHandleEvent)
|
||||
return io;
|
||||
};
|
||||
@@ -101,5 +101,5 @@ export const EVENTS = {
|
||||
|
||||
//PROJECT
|
||||
addProject:"v1:project:add",
|
||||
projectResponse:"v1-project:response:update:",
|
||||
projectResponse:"v1-project:response:update",
|
||||
}
|
||||
36
src/socket-server/utils/emitEventResponse.ts
Normal file
36
src/socket-server/utils/emitEventResponse.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Socket } from "socket.io";
|
||||
|
||||
interface EmitOptions {
|
||||
success: boolean;
|
||||
message: string;
|
||||
data?: any;
|
||||
error?: any;
|
||||
organization: string;
|
||||
socketId: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a structured socket event response to a specific organization room.
|
||||
*/
|
||||
export const emitEventResponse = (
|
||||
socket: Socket,
|
||||
organization: string,
|
||||
event: string,
|
||||
result: EmitOptions
|
||||
) => {
|
||||
console.log(`📤 emitEventResponse called for event: ${event}, organization: ${organization}`);
|
||||
if (!organization) {
|
||||
console.log(`Organization missing in response for event: ${event}`);
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit(event, {
|
||||
success: result.success,
|
||||
message: result.message,
|
||||
data: result.data ,
|
||||
error: result.error ?? null,
|
||||
socketId: result.socketId,
|
||||
organization,
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user