From 44c306c84ad860cd32740377a7d3baa48b3374ed Mon Sep 17 00:00:00 2001 From: vansh Date: Sun, 24 Aug 2025 00:49:44 +0530 Subject: [PATCH 1/6] added api for sending invitation --- .../Controllers/collaboration.controller.js | 77 ++++++++++ backend/Models/collaboration.model.js | 6 + backend/Routes/api/collaboration.routes.js | 11 ++ backend/Routes/index.js | 2 + backend/Schemas/collaboration.schema.js | 35 +++++ backend/config/cloudinary.js | 2 +- backend/config/nodemailer.js | 14 ++ backend/package-lock.json | 145 ++++++++++++++++-- backend/package.json | 5 +- 9 files changed, 285 insertions(+), 12 deletions(-) create mode 100644 backend/Controllers/collaboration.controller.js create mode 100644 backend/Models/collaboration.model.js create mode 100644 backend/Routes/api/collaboration.routes.js create mode 100644 backend/Schemas/collaboration.schema.js create mode 100644 backend/config/nodemailer.js diff --git a/backend/Controllers/collaboration.controller.js b/backend/Controllers/collaboration.controller.js new file mode 100644 index 000000000..a649efca8 --- /dev/null +++ b/backend/Controllers/collaboration.controller.js @@ -0,0 +1,77 @@ +import collaboration from "../Models/collaboration.model.js" +import Project from "../Models/project.model.js"; +import crypto from "crypto"; +import User from "../Models/user.model.js"; +import transporter from "../config/nodemailer.js"; + + +export const invitationToCollaborate = async(req, res)=>{ + const userid = req.user; + const {project_id} = req.body; + + try { + const user = await User.findById(userid); + if(!user) return res.status(404).json({error: "User not found!"}); + const projectToCollaborate = await Project.findOne({project_id: project_id}).populate("author", "personal_info.email"); + if(!projectToCollaborate) return res.status(404).json({error: "Project not found!"}); + + const authorEmail = projectToCollaborate.author.personal_info.email; + const token = crypto.randomBytes(16).toString('hex'); + + const baseUrl = global.publicUrl || `http://localhost:${process.env.PORT || 8000}`; + const acceptLink = `${baseUrl}/api/collaborate/accept/${token}`; + const rejectLink = `${baseUrl}/api/collaborate/reject/${token}`; + const mailOptions = { + from: process.env.EMAIL_USER, + to: authorEmail, + subject: "Collaboration Invitation", + html: `

Hi,

+

${user.personal_info.fullname} has requested to collaborate on your project "${projectToCollaborate.title}".

+

Accept Invitation | Reject Invitation

+

Thank you!

` + + }; + await transporter.sendMail(mailOptions, (error, info)=>{ + if(error){ + console.error("Error sending email:", error); + return res.status(500).json({error: "Failed to send invitation email"}); + } + console.log("Email sent:", info.response); + }) + const collaborationData = new collaboration({ + user_id: userid, + project_id: project_id, + author_id: projectToCollaborate.author, + status: "pending", + token : token + }) + await collaborationData.save(); + return res.status(200).json({message: "Invitation sent successfully!"}); + + } catch (error) { + console.log(error); + return res.status(500).json({error: "Internal Server Error"}); + } +} + +export const acceptInvitation = async(req, res)=>{ + const {token} = req.params; + const userId = req.user; + + try { + const collaborationData = await collaboration.finOne({token: token, author_id:userId, status: "pending"}); + if(!collaborationData) return res.status(404).json({error: "Collaboration request not found!"}); + + collaborationData.status = "accepted"; + + await collaborationData.save(); + return res.status(200).json({message: "Collaboration request accepted!"}); + + } catch (error) { + console.log(error); + return res.status(500).json({error: "Internal Server Error"}); + } +} + + + diff --git a/backend/Models/collaboration.model.js b/backend/Models/collaboration.model.js new file mode 100644 index 000000000..ba5b6c223 --- /dev/null +++ b/backend/Models/collaboration.model.js @@ -0,0 +1,6 @@ +import mongoose from 'mongoose'; +import collaborationSchema from '../Schemas/collaboration.schema.js'; + +const collaboration = mongoose.model('collaborators', collaborationSchema); + +export default collaboration; \ No newline at end of file diff --git a/backend/Routes/api/collaboration.routes.js b/backend/Routes/api/collaboration.routes.js new file mode 100644 index 000000000..3f9ede8bc --- /dev/null +++ b/backend/Routes/api/collaboration.routes.js @@ -0,0 +1,11 @@ +import express from "express"; + +import { authenticateUser } from "../../Middlewares/auth.middleware.js"; + +import {invitationToCollaborate} from "../../Controllers/collaboration.controller.js"; +const collaborationRoutes = express.Router(); + +collaborationRoutes.post("/invite", authenticateUser, invitationToCollaborate); + + +export default collaborationRoutes; \ No newline at end of file diff --git a/backend/Routes/index.js b/backend/Routes/index.js index c80c7b7f2..3dc7dc082 100644 --- a/backend/Routes/index.js +++ b/backend/Routes/index.js @@ -5,6 +5,7 @@ import projectRoutes from './api/project.routes.js'; import userRoutes from './api/user.routes.js'; import notificationRoutes from './api/notification.routes.js'; import subscriberRoutes from './api/subscriber.routes.js'; +import collaborationRoutes from './api/collaboration.routes.js'; const router = express.Router(); @@ -14,5 +15,6 @@ router.use('/media', mediaRoutes); router.use('/project', projectRoutes); router.use('/notification', notificationRoutes); router.use('/subscriber', subscriberRoutes); +router.use('/collaboration', collaborationRoutes); export default router; diff --git a/backend/Schemas/collaboration.schema.js b/backend/Schemas/collaboration.schema.js new file mode 100644 index 000000000..558e15949 --- /dev/null +++ b/backend/Schemas/collaboration.schema.js @@ -0,0 +1,35 @@ +import {Schema} from 'mongoose'; + + +const collaborationSchema = Schema( + { + user_id:{ + type: Schema.Types.ObjectId, + ref:'users', + required: true, + }, + project_id: { + type: String, + ref:'projects', + required: true, + }, + + author_id:{ + type: Schema.Types.ObjectId, + ref:'users', + required: true, + }, + status:{ + type: String, + enum:["pending", "accepted"], + default:"pending", + required: true + }, + token:{ + type: String, + required: true + } + },{timestamps: true} +) + +export default collaborationSchema; \ No newline at end of file diff --git a/backend/config/cloudinary.js b/backend/config/cloudinary.js index 9fd710b0b..437760192 100644 --- a/backend/config/cloudinary.js +++ b/backend/config/cloudinary.js @@ -9,4 +9,4 @@ cloudinary.config({ secure: true }); -export default cloudinary; +export default cloudinary; \ No newline at end of file diff --git a/backend/config/nodemailer.js b/backend/config/nodemailer.js new file mode 100644 index 000000000..12f0a1c08 --- /dev/null +++ b/backend/config/nodemailer.js @@ -0,0 +1,14 @@ +import nodemailer from 'nodemailer'; + + +const transporter = nodemailer.createTransport({ + host:'smtp.gmail.com', + port: 587, + secure: false, // true for 465, false for other ports + auth :{ + user: process.env.EMAIL_USER, // your email address + pass: process.env.EMAIL_PASS // your email password + } +}) + +export default transporter; \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 7a36baeb5..e20806dc1 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -12,13 +12,16 @@ "bcrypt": "^5.1.1", "cloudinary": "^2.5.1", "cors": "^2.8.5", + "crypto": "^1.0.1", "dotenv": "^16.4.7", "express": "^4.21.2", "firebase-admin": "^13.1.0", "jsonwebtoken": "^9.0.2", + "localtunnel": "^2.0.2", "mongoose": "^8.11.0", "multer": "^1.4.5-lts.1", - "nanoid": "^5.1.2" + "nanoid": "^5.1.2", + "nodemailer": "^7.0.5" }, "devDependencies": { "nodemon": "^3.1.9" @@ -619,7 +622,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "optional": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -703,6 +705,15 @@ "license": "MIT", "optional": true }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -964,7 +975,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "optional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -976,8 +986,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", @@ -1113,6 +1122,13 @@ "node": ">= 0.10" } }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", + "license": "ISC" + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -1304,7 +1320,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", - "optional": true, "engines": { "node": ">=6" } @@ -1519,6 +1534,26 @@ "@google-cloud/storage": "^7.14.0" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz", @@ -1724,7 +1759,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", - "optional": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2278,6 +2312,85 @@ "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, + "node_modules/localtunnel": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz", + "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==", + "license": "MIT", + "dependencies": { + "axios": "0.21.4", + "debug": "4.3.2", + "openurl": "1.1.1", + "yargs": "17.1.1" + }, + "bin": { + "lt": "bin/lt.js" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/localtunnel/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/localtunnel/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/localtunnel/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/localtunnel/node_modules/yargs": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", + "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/localtunnel/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2753,6 +2866,15 @@ "node": ">= 6.13.0" } }, + "node_modules/nodemailer": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.5.tgz", + "integrity": "sha512-nsrh2lO3j4GkLLXoeEksAMgAOqxOv6QumNRVQTJwKH4nuiww6iC2y7GyANs9kRAxCexg3+lTWM3PZ91iLlVjfg==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nodemon": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", @@ -2872,6 +2994,12 @@ "wrappy": "1" } }, + "node_modules/openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", + "license": "MIT" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3080,7 +3208,6 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -3682,7 +3809,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", - "optional": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3715,7 +3841,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", - "optional": true, "engines": { "node": ">=10" } diff --git a/backend/package.json b/backend/package.json index ff0c4b6ab..f0f07263e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -16,13 +16,16 @@ "bcrypt": "^5.1.1", "cloudinary": "^2.5.1", "cors": "^2.8.5", + "crypto": "^1.0.1", "dotenv": "^16.4.7", "express": "^4.21.2", "firebase-admin": "^13.1.0", "jsonwebtoken": "^9.0.2", + "localtunnel": "^2.0.2", "mongoose": "^8.11.0", "multer": "^1.4.5-lts.1", - "nanoid": "^5.1.2" + "nanoid": "^5.1.2", + "nodemailer": "^7.0.5" }, "devDependencies": { "nodemon": "^3.1.9" From 6cbec47e9c356be70d7df369a066ed25d5179fd1 Mon Sep 17 00:00:00 2001 From: vansh Date: Sun, 24 Aug 2025 01:02:22 +0530 Subject: [PATCH 2/6] fixed some issues --- backend/Controllers/collaboration.controller.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/backend/Controllers/collaboration.controller.js b/backend/Controllers/collaboration.controller.js index a649efca8..b8aa61f1d 100644 --- a/backend/Controllers/collaboration.controller.js +++ b/backend/Controllers/collaboration.controller.js @@ -54,24 +54,7 @@ export const invitationToCollaborate = async(req, res)=>{ } } -export const acceptInvitation = async(req, res)=>{ - const {token} = req.params; - const userId = req.user; - try { - const collaborationData = await collaboration.finOne({token: token, author_id:userId, status: "pending"}); - if(!collaborationData) return res.status(404).json({error: "Collaboration request not found!"}); - - collaborationData.status = "accepted"; - - await collaborationData.save(); - return res.status(200).json({message: "Collaboration request accepted!"}); - - } catch (error) { - console.log(error); - return res.status(500).json({error: "Internal Server Error"}); - } -} From 237f62c6e824723b15d5d6a7f5c8c440f4148b17 Mon Sep 17 00:00:00 2001 From: vansh Date: Mon, 25 Aug 2025 23:31:09 +0530 Subject: [PATCH 3/6] added-invitation-mail-implementation --- backend/Controllers/collaboration.controller.js | 6 +++++- backend/Schemas/collaboration.schema.js | 2 +- backend/server.js | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/Controllers/collaboration.controller.js b/backend/Controllers/collaboration.controller.js index b8aa61f1d..928fec7d5 100644 --- a/backend/Controllers/collaboration.controller.js +++ b/backend/Controllers/collaboration.controller.js @@ -3,6 +3,7 @@ import Project from "../Models/project.model.js"; import crypto from "crypto"; import User from "../Models/user.model.js"; import transporter from "../config/nodemailer.js"; +import localtunnel from "localtunnel"; export const invitationToCollaborate = async(req, res)=>{ @@ -17,10 +18,13 @@ export const invitationToCollaborate = async(req, res)=>{ const authorEmail = projectToCollaborate.author.personal_info.email; const token = crypto.randomBytes(16).toString('hex'); + + // const baseUrl = global.publicUrl || `http://localhost:${process.env.PORT || 8000}`; + const baseUrl = process.env.PUBLIC_URL; - const baseUrl = global.publicUrl || `http://localhost:${process.env.PORT || 8000}`; const acceptLink = `${baseUrl}/api/collaborate/accept/${token}`; const rejectLink = `${baseUrl}/api/collaborate/reject/${token}`; + console.log(acceptLink, rejectLink); const mailOptions = { from: process.env.EMAIL_USER, to: authorEmail, diff --git a/backend/Schemas/collaboration.schema.js b/backend/Schemas/collaboration.schema.js index 558e15949..0204c06cd 100644 --- a/backend/Schemas/collaboration.schema.js +++ b/backend/Schemas/collaboration.schema.js @@ -21,7 +21,7 @@ const collaborationSchema = Schema( }, status:{ type: String, - enum:["pending", "accepted"], + enum:["pending", "accepted", "rejected"], default:"pending", required: true }, diff --git a/backend/server.js b/backend/server.js index 55b9ac5e5..8ddf702cd 100644 --- a/backend/server.js +++ b/backend/server.js @@ -5,6 +5,7 @@ import dotenv from "dotenv"; import connectDB from "./config/db.js"; import router from "./Routes/index.js"; + dotenv.config(); const server = express(); @@ -21,4 +22,6 @@ connectDB(); server.get("/", (req, res) => res.send("Backend is running...")); server.use("/api", router); -server.listen(PORT, () => console.log(`Server running on port ${PORT}`)); +server.listen(PORT, async () => { + console.log(`Server running on port ${PORT}`); +}); From 064e34f5e1fd05d4a5dc14017f28b47ecdb856e7 Mon Sep 17 00:00:00 2001 From: vansh Date: Tue, 26 Aug 2025 00:01:20 +0530 Subject: [PATCH 4/6] added-env-examples --- backend/.env.example | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/.env.example b/backend/.env.example index b60df6264..3cce5bef9 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -6,4 +6,9 @@ CLOUDINARY_CLOUD_NAME= CLOUDINARY_API_KEY= CLOUDINARY_API_SECRET= +EMAIL_USER= +EMAIL_PASS= + +PUBLIC_URL= + VITE_SERVER_DOMAIN=https://pjt-blog.onrender.com From 2796052dad53d1cc3643e55a326ce079383c665f Mon Sep 17 00:00:00 2001 From: vansh Date: Tue, 26 Aug 2025 00:07:38 +0530 Subject: [PATCH 5/6] reverted the changes in server.js --- backend/server.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/server.js b/backend/server.js index 8ddf702cd..82278c936 100644 --- a/backend/server.js +++ b/backend/server.js @@ -21,7 +21,4 @@ connectDB(); // Routes server.get("/", (req, res) => res.send("Backend is running...")); server.use("/api", router); - -server.listen(PORT, async () => { - console.log(`Server running on port ${PORT}`); -}); +server.listen(PORT, () => console.log(`Server running on port ${PORT}`)); From 40e8f814f48d0ccbcb568102fa8d0a957ecc12a7 Mon Sep 17 00:00:00 2001 From: vansh Date: Tue, 23 Sep 2025 00:51:12 +0530 Subject: [PATCH 6/6] added backend implementation of listing of collaborators in a project --- backend/Controllers/collaboration.controller.js | 14 +++++++++++++- backend/Routes/api/collaboration.routes.js | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/backend/Controllers/collaboration.controller.js b/backend/Controllers/collaboration.controller.js index 928fec7d5..8e8519f90 100644 --- a/backend/Controllers/collaboration.controller.js +++ b/backend/Controllers/collaboration.controller.js @@ -20,7 +20,7 @@ export const invitationToCollaborate = async(req, res)=>{ const token = crypto.randomBytes(16).toString('hex'); // const baseUrl = global.publicUrl || `http://localhost:${process.env.PORT || 8000}`; - const baseUrl = process.env.PUBLIC_URL; + const baseUrl = process.env.COLLABORATION_PUBLIC_URL || `http://localhost:${process.env.PORT || 8000}`; const acceptLink = `${baseUrl}/api/collaborate/accept/${token}`; const rejectLink = `${baseUrl}/api/collaborate/reject/${token}`; @@ -59,6 +59,18 @@ export const invitationToCollaborate = async(req, res)=>{ } +export const getListOfCollaborators = async(req, res)=>{ + const userid = req.user; + const {project_id} = req.params; + try { + const existingCollaborators = await collaboration.find({project_id: project_id, author_id: userid}); + if(!existingCollaborators) return res.status(404).json({error: "No collaborators found!"}); + return res.status(200).json({collaborators: existingCollaborators}); + } catch (error) { + console.log(error); + return res.status(500).json({error: "Internal Server Error"}); + } +} diff --git a/backend/Routes/api/collaboration.routes.js b/backend/Routes/api/collaboration.routes.js index 3f9ede8bc..2a207132d 100644 --- a/backend/Routes/api/collaboration.routes.js +++ b/backend/Routes/api/collaboration.routes.js @@ -2,10 +2,11 @@ import express from "express"; import { authenticateUser } from "../../Middlewares/auth.middleware.js"; -import {invitationToCollaborate} from "../../Controllers/collaboration.controller.js"; +import {invitationToCollaborate,getListOfCollaborators } from "../../Controllers/collaboration.controller.js"; const collaborationRoutes = express.Router(); collaborationRoutes.post("/invite", authenticateUser, invitationToCollaborate); +collaborationRoutes.get("/collaborators/:project_id", authenticateUser, getListOfCollaborators); export default collaborationRoutes; \ No newline at end of file