diff --git a/backend/config.js b/backend/config.js new file mode 100644 index 0000000..0bb5a8f --- /dev/null +++ b/backend/config.js @@ -0,0 +1 @@ +export const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000'; \ No newline at end of file diff --git a/backend/dist/controllers/postController.js b/backend/dist/controllers/postController.js index deccf31..aa406ba 100644 --- a/backend/dist/controllers/postController.js +++ b/backend/dist/controllers/postController.js @@ -12,24 +12,74 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.createPost = exports.getCommunities = void 0; +exports.searchPosts = exports.unlikePost = exports.postLiked = exports.createComment = exports.fetchSinglePost = exports.likePost = exports.fetchPosts = exports.createPost = exports.getCommunities = void 0; const express_async_handler_1 = __importDefault(require("express-async-handler")); const prisma_1 = __importDefault(require("../lib/prisma")); +const fuse_js_1 = __importDefault(require("fuse.js")); +// @ts-ignore +const searchPosts = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { query } = req.body; + if (!query) { + return res.status(400).json({ message: "Search query is required" }); + } + const posts = yield prisma_1.default.post.findMany({ + select: { + post_id: true, + title: true, + content: true, + College: { + select: { + name: true, + }, + }, + }, + }); + const fuse = new fuse_js_1.default(posts, { + keys: ["title", "content", "College.name"], + threshold: 0.6, + }); + const searchResults = fuse.search(query).map((result) => result.item); + return res.status(200).json({ posts: searchResults }); +})); +exports.searchPosts = searchPosts; // @ts-ignore const getCommunities = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { // @ts-ignore const user_id = req.user.user_id; - // return res.status(200).json({ message: "Communities fetched" }); + // const user_id = "clzfffeey0000e6hx5j16b96c"; const communities = yield prisma_1.default.userCourse.findMany({ where: { user_id: user_id, }, select: { college_id: true, + College: { + select: { + name: true, + }, + }, }, distinct: ["college_id"], }); - return res.status(200).json({ communities }); + // @ts-ignore + const communityIds = communities.map((community) => community.college_id); + // @ts-ignore + if (communityIds.length === 0) { + return res.status(200).json({ communityIds: [] }); + } + let college = []; + for (let i = 0; i < communityIds.length; i++) { + college[i] = yield prisma_1.default.college.findUnique({ + where: { + college_id: communityIds[i], + }, + select: { + college_id: true, + name: true, + }, + }); + } + return res.status(200).json({ college }); })); exports.getCommunities = getCommunities; // @ts-ignore @@ -52,8 +102,192 @@ const createPost = (0, express_async_handler_1.default)((req, res, next) => __aw title, content, user_id, + college_id: collegeId, }, }); return res.status(201).json({ post }); })); exports.createPost = createPost; +// @ts-ignore +const fetchPosts = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { page } = req.body; + const pageNumber = page; + const postsPerPage = 3; + const offset = (pageNumber - 1) * postsPerPage; + const posts = yield prisma_1.default.post.findMany({ + orderBy: { + createdAt: "desc", + }, + select: { + post_id: true, + title: true, + content: true, + likes: true, + College: { + select: { + name: true, + }, + }, + }, + take: postsPerPage, + skip: offset, + }); + const totalPosts = yield prisma_1.default.post.count(); + const isOver = offset + postsPerPage >= totalPosts; + return res.status(200).json({ posts, isOver }); +})); +exports.fetchPosts = fetchPosts; +// @ts-ignore +const likePost = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { postId } = req.body; + // @ts-ignore + const post = yield prisma_1.default.post.findUnique({ + where: { post_id: postId }, + select: { + likes: true, + }, + }); + // @ts-ignore + const user_id = req.user.user_id; + const like = yield prisma_1.default.like.findFirst({ + where: { + post_id: postId, + user_id: user_id, + }, + }); + if (like) { + return res.status(400).json({ message: "Post already liked" }); + } + if (!post) { + return res.status(404).json({ message: "Post not found" }); + } + const likes = post.likes + 1; + const updatedPost = yield prisma_1.default.post.update({ + where: { post_id: postId }, + data: { + likes, + }, + }); + yield prisma_1.default.like.create({ + data: { + post_id: postId, + user_id, + }, + }); + return res.status(200).json({ updatedPost }); +})); +exports.likePost = likePost; +// @ts-ignore +const fetchSinglePost = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const postId = req.params.id; + const post = yield prisma_1.default.post.findUnique({ + where: { post_id: postId }, + select: { + post_id: true, + title: true, + content: true, + likes: true, + College: { + select: { + name: true, + }, + }, + Comments: { + select: { + comment_id: true, + content: true, + user_id: true, + User: { + select: { + name: true, + }, + }, + }, + }, + }, + }); + if (!post) { + return res.status(404).json({ message: "Post not found" }); + } + return res.status(200).json({ post }); +})); +exports.fetchSinglePost = fetchSinglePost; +// @ts-ignore +const createComment = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { postId, content } = req.body; + // @ts-ignore + const user_id = req.user.user_id; + if (!postId || !content) { + return res.status(400).json({ message: "Required fields are missing" }); + } + const user = yield prisma_1.default.user.findUnique({ + where: { user_id }, + }); + if (!user) { + return res.status(404).json({ message: "User not recognized" }); + } + const comment = yield prisma_1.default.comment.create({ + data: { + content, + user_id, + post_id: postId, + }, + }); + return res.status(201).json({ comment }); +})); +exports.createComment = createComment; +// @ts-ignore +const postLiked = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { postId } = req.body; + // @ts-ignore + const user_id = req.user.user_id; + const likes = yield prisma_1.default.like.findFirst({ + where: { + post_id: postId, + user_id: user_id, + }, + }); + if (likes) { + return res.status(200).json({ postLiked: true }); + } + return res.status(200).json({ postLiked: false }); +})); +exports.postLiked = postLiked; +// @ts-ignore +const unlikePost = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { postId } = req.body; + // @ts-ignore + const user_id = req.user.user_id; + const like = yield prisma_1.default.like.findFirst({ + where: { + post_id: postId, + user_id: user_id, + }, + }); + const post = yield prisma_1.default.post.findUnique({ + where: { post_id: postId }, + select: { + likes: true, + }, + }); + if (!like) { + return res.status(400).json({ message: "Post not liked" }); + } + if (!post) { + return res.status(404).json({ message: "Post not found" }); + } + const likes = post.likes - 1; + const updatedPost = yield prisma_1.default.post.update({ + where: { post_id: postId }, + data: { + likes, + }, + }); + yield prisma_1.default.like.delete({ + where: { + like_id: like.like_id, + }, + }); + return res.status(200).json({ updatedPost }); +})); +exports.unlikePost = unlikePost; diff --git a/backend/dist/controllers/userControllers.js b/backend/dist/controllers/userControllers.js index c4c0a65..996a5ea 100644 --- a/backend/dist/controllers/userControllers.js +++ b/backend/dist/controllers/userControllers.js @@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.addCourseToUser = exports.getUserDetailsById = exports.getCurrentUserDetails = exports.verifyUser = exports.loginUser = exports.registerUser = void 0; +exports.googleSignInOrSignUp = exports.addCourseToUser = exports.getUserDetailsById = exports.getCurrentUserDetails = exports.verifyUser = exports.loginUser = exports.registerUser = void 0; const express_async_handler_1 = __importDefault(require("express-async-handler")); const prisma_1 = __importDefault(require("../lib/prisma")); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); @@ -20,6 +20,45 @@ const bcrypt_1 = __importDefault(require("bcrypt")); const sendMail_1 = __importDefault(require("../mail/sendMail")); const academic_email_verifier_1 = require("academic-email-verifier"); const checkAcademic_1 = __importDefault(require("../mail/checkAcademic")); +//@ts-ignore +const googleSignInOrSignUp = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { email, displayName } = req.body; + const user = yield prisma_1.default.user.findUnique({ + where: { + email, + }, + }); + if (!user) { + const user = yield prisma_1.default.user.create({ + // @ts-ignore + data: { + email, + name: displayName, + collegeEmailVerified: false, + emailVerified: true, + }, + }); + const exp = Date.now() + 1000 * 60 * 60 * 24 * 30; + // @ts-ignore + const token = jsonwebtoken_1.default.sign({ sub: user.user_id, exp }, process.env.SECRET); + res.cookie("Authorization", token, { + httpOnly: true, + secure: false, + sameSite: "lax", + }); + return res.status(201).json({ message: "User created" }); + } + const exp = Date.now() + 1000 * 60 * 60 * 24 * 30; + // @ts-ignore + const token = jsonwebtoken_1.default.sign({ sub: user.user_id, exp }, process.env.SECRET); + res.cookie("Authorization", token, { + httpOnly: true, + secure: false, + sameSite: "lax", + }); + res.status(200).json({ message: "User logged in" }); +})); +exports.googleSignInOrSignUp = googleSignInOrSignUp; // @ts-ignore const registerUser = (0, express_async_handler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () { const { email, name, password, collegeName, courseName, isOnline, location } = req.body; @@ -99,10 +138,10 @@ const registerUser = (0, express_async_handler_1.default)((req, res) => __awaite const exp = Date.now() + 1000 * 60 * 5; // @ts-ignore const token = jsonwebtoken_1.default.sign({ sub: user.user_id, exp }, process.env.SECRET); - const url = `https://api-statuscode1.wedevelopers.online/api/user/verify/${token}`; + const url = `${process.env.BACKEND_URL}/api/user/verify/${token}`; const htmlContent = `Verify using this link`; // @ts-ignore - yield (0, sendMail_1.default)(email, htmlContent); + (0, sendMail_1.default)(htmlContent, email); res.status(201).json({ message: "User created" }); } else { @@ -117,10 +156,10 @@ const registerUser = (0, express_async_handler_1.default)((req, res) => __awaite const exp = Date.now() + 1000 * 60 * 5; // @ts-ignore const token = jsonwebtoken_1.default.sign({ sub: user.user_id, exp }, process.env.SECRET); - const url = `https://api-statuscode1.wedevelopers.online/api/user/verify/${token}`; + const url = `${process.env.BACKEND_URL}/api/user/verify/${token}`; const htmlContent = `Verify using this link`; // @ts-ignore - yield (0, sendMail_1.default)(email, htmlContent); + (0, sendMail_1.default)(htmlContent, email); res.status(201).json({ message: "User created" }); } })); @@ -177,6 +216,10 @@ const loginUser = (0, express_async_handler_1.default)((req, res) => __awaiter(v res.status(404).json({ message: "User not found" }); return; } + if (!user.password) { + res.status(401).json({ message: "Logged in with Google Or Github" }); + return; + } const match = yield bcrypt_1.default.compare(password, user.password); if (!match) { res.status(401).json({ message: "Invalid credentials" }); diff --git a/backend/dist/index.js b/backend/dist/index.js index 54897a2..78975dd 100644 --- a/backend/dist/index.js +++ b/backend/dist/index.js @@ -20,6 +20,7 @@ const corsOptions = { origin: [ "http://localhost:3001", "https://app-statuscode1.wedevelopers.online", + "http://localhost:5173", ], credentials: true, }; diff --git a/backend/dist/mail/sendMail.js b/backend/dist/mail/sendMail.js index 3d9ed1e..335107b 100644 --- a/backend/dist/mail/sendMail.js +++ b/backend/dist/mail/sendMail.js @@ -1,38 +1,36 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const nodemailer_1 = __importDefault(require("nodemailer")); -const express_async_handler_1 = __importDefault(require("express-async-handler")); -const transporter = nodemailer_1.default.createTransport({ - // @ts-ignore - host: process.env.BREVO_HOST, - port: process.env.BREVO_PORT, - secure: false, // Use `true` for port 465, `false` for all other ports - auth: { - user: process.env.BREVO_USER, - pass: process.env.BREVO_PASSWORD, - }, -}); -const sendMail = (0, express_async_handler_1.default)((email, url) => __awaiter(void 0, void 0, void 0, function* () { - yield transporter.sendMail({ - from: '"Review" ', - // @ts-ignore - to: email, - subject: "URL/OTP for verification", - text: "Single use URL/OTP", +const sendMail = (htmlContent, receiverEmail) => { + const port = process.env.SMTP_PORT; + const host = process.env.SMTP_HOST; + const senderEmail = process.env.SMTP_EMAIL; + const password = process.env.SMTP_PASSWORD; + let transporter = nodemailer_1.default.createTransport({ // @ts-ignore - html: url, + host: 'smtp.gmail.com', + port: port, + secure: true, + auth: { + user: host, + pass: password, + }, }); -})); + let mailOptions = { + from: `"Campus-Chatter Admin" <${senderEmail}>`, + to: receiverEmail, + subject: 'OTP Verification', + text: htmlContent, + html: htmlContent, + }; + transporter.sendMail(mailOptions, (error, info) => { + if (error) { + return console.log('Error while sending email:', error); + } + console.log('Email sent successfully:', info.response); + }); +}; exports.default = sendMail; diff --git a/backend/dist/routes/postsRoutes.js b/backend/dist/routes/postsRoutes.js index f0e5ac6..0af5759 100644 --- a/backend/dist/routes/postsRoutes.js +++ b/backend/dist/routes/postsRoutes.js @@ -9,4 +9,11 @@ const checkAuth_1 = __importDefault(require("../middleware/checkAuth")); const postsRoutes = express_1.default.Router(); postsRoutes.get("/communities", checkAuth_1.default, postController_1.getCommunities); postsRoutes.post("/create", checkAuth_1.default, postController_1.createPost); +postsRoutes.post("/fetch", checkAuth_1.default, postController_1.fetchPosts); +postsRoutes.post("/like", checkAuth_1.default, postController_1.likePost); +postsRoutes.get("/fetch/:id", checkAuth_1.default, postController_1.fetchSinglePost); +postsRoutes.post("/comment", checkAuth_1.default, postController_1.createComment); +postsRoutes.post("/liked", checkAuth_1.default, postController_1.postLiked); +postsRoutes.post("/unlike", checkAuth_1.default, postController_1.unlikePost); +postsRoutes.post("/search", checkAuth_1.default, postController_1.searchPosts); exports.default = postsRoutes; diff --git a/backend/dist/routes/userRoutes.js b/backend/dist/routes/userRoutes.js index c0ca203..f53ba3c 100644 --- a/backend/dist/routes/userRoutes.js +++ b/backend/dist/routes/userRoutes.js @@ -13,4 +13,5 @@ router.route("/verify/:token").get(userControllers_1.verifyUser); router.get("/me", checkAuth_1.default, userControllers_1.getCurrentUserDetails); // get the user details of the current user router.get("/get/:userId", checkAuth_1.default, userControllers_1.getUserDetailsById); // get the user details of a specific user router.post("/addcourse", checkAuth_1.default, userControllers_1.addCourseToUser); // add a course to the current user +router.post("/google", userControllers_1.googleSignInOrSignUp); // sign in or sign up using google exports.default = router; diff --git a/backend/prisma/migrations/20241006145947_dev/migration.sql b/backend/prisma/migrations/20241006145947_dev/migration.sql new file mode 100644 index 0000000..0b600a7 --- /dev/null +++ b/backend/prisma/migrations/20241006145947_dev/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ALTER COLUMN "password" DROP NOT NULL; diff --git a/backend/src/controllers/userControllers.ts b/backend/src/controllers/userControllers.ts index 2765a54..7bd7f66 100644 --- a/backend/src/controllers/userControllers.ts +++ b/backend/src/controllers/userControllers.ts @@ -7,6 +7,7 @@ import sendMail from "../mail/sendMail"; import { Verifier } from "academic-email-verifier"; import checkCollegeEmail from "../mail/checkAcademic"; + //@ts-ignore const googleSignInOrSignUp = asyncHandler(async (req: Request, res: Response) => { const{email,displayName}=req.body; @@ -17,6 +18,7 @@ const googleSignInOrSignUp = asyncHandler(async (req: Request, res: Response) => }); if (!user) { const user = await prisma.user.create({ + // @ts-ignore data: { email, name:displayName, @@ -128,7 +130,7 @@ const registerUser = asyncHandler(async (req: Request, res: Response) => { const exp = Date.now() + 1000 * 60 * 5; // @ts-ignore const token = jwt.sign({ sub: user.user_id, exp }, process.env.SECRET); - const url = `http://localhost:3000/api/user/verify/${token}`; + const url = `${process.env.BACKEND_URL}/api/user/verify/${token}`; const htmlContent = `Verify using this link`; // @ts-ignore sendMail(htmlContent, email); @@ -145,7 +147,7 @@ const registerUser = asyncHandler(async (req: Request, res: Response) => { const exp = Date.now() + 1000 * 60 * 5; // @ts-ignore const token = jwt.sign({ sub: user.user_id, exp }, process.env.SECRET); - const url = `https://api-statuscode1.wedevelopers.online/api/user/verify/${token}`; + const url = `${process.env.BACKEND_URL}/api/user/verify/${token}`; const htmlContent = `Verify using this link`; // @ts-ignore sendMail(htmlContent, email);