├── .gitignore ├── db └── db.js ├── utils └── generateAuthToken.js ├── models ├── like.model.js ├── follower.model.js ├── following.model.js ├── comment.model.js ├── user.model.js ├── profile.model.js └── post.model.js ├── package.json ├── middlewares └── auth.middleware.js ├── index.js ├── routes ├── profiles.routes.js ├── followers.routes.js ├── followings.routes.js ├── comments.routes.js ├── auth.routes.js └── posts.routes.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env -------------------------------------------------------------------------------- /db/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | module.exports = async function (url) { 4 | try { 5 | await mongoose.connect(url, { 6 | useNewUrlParser: true, 7 | useUnifiedTopology: true, 8 | }); 9 | console.info("Connected to Probook DB"); 10 | } catch (error) { 11 | console.error("Something went wrong", error); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /utils/generateAuthToken.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const privateKey = process.env.JWT_KEY; 3 | 4 | const generateAuthToken = function (id) { 5 | const token = jwt.sign( 6 | { 7 | _id: id, 8 | }, 9 | privateKey, 10 | { expiresIn: "24h" } 11 | ); 12 | 13 | return token; 14 | }; 15 | 16 | module.exports = generateAuthToken; 17 | -------------------------------------------------------------------------------- /models/like.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const likeSchema = new Schema({ 6 | postId: { 7 | type: Schema.Types.ObjectId, 8 | ref: "Post", 9 | }, 10 | author: { 11 | type: Schema.Types.ObjectId, 12 | ref: "User", 13 | }, 14 | }); 15 | 16 | module.exports = mongoose.model("Like", likeSchema); 17 | -------------------------------------------------------------------------------- /models/follower.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const followerSchema = new Schema({ 6 | userId: { 7 | type: Schema.Types.ObjectId, 8 | ref: "User", 9 | }, 10 | followerId: { 11 | type: Schema.Types.ObjectId, 12 | ref: "User", 13 | }, 14 | }); 15 | 16 | module.exports = mongoose.model("Follower", followerSchema); 17 | -------------------------------------------------------------------------------- /models/following.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const followingSchema = new Schema({ 6 | userId: { 7 | type: Schema.Types.ObjectId, 8 | ref: "User", 9 | }, 10 | followingId: { 11 | type: Schema.Types.ObjectId, 12 | ref: "User", 13 | }, 14 | }); 15 | 16 | module.exports = mongoose.model("Following", followingSchema); 17 | -------------------------------------------------------------------------------- /models/comment.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const commentSchema = new Schema( 6 | { 7 | postId: { 8 | type: Schema.Types.ObjectId, 9 | ref: "Post", 10 | }, 11 | author: { 12 | type: Schema.Types.ObjectId, 13 | ref: "User", 14 | }, 15 | text: { 16 | type: String, 17 | required: true, 18 | }, 19 | }, 20 | { timestamps: true } 21 | ); 22 | 23 | module.exports = mongoose.model("Comment", commentSchema); 24 | -------------------------------------------------------------------------------- /models/user.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const userSchema = new Schema( 6 | { 7 | email: { 8 | type: String, 9 | required: true, 10 | unique: true, 11 | }, 12 | handle: { 13 | type: String, 14 | required: true, 15 | unique: true, 16 | }, 17 | name: { 18 | type: String, 19 | required: true, 20 | }, 21 | password: { 22 | type: String, 23 | required: true, 24 | }, 25 | }, 26 | { timestamps: true } 27 | ); 28 | 29 | module.exports = mongoose.model("User", userSchema); 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "probook-server", 3 | "version": "1.0.0", 4 | "description": "A social media app. ", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js", 9 | "dev": "nodemon index.js" 10 | }, 11 | "keywords": [ 12 | "Twitter", 13 | "facebook", 14 | "social-media" 15 | ], 16 | "author": "Wasif Baliyan", 17 | "license": "ISC", 18 | "dependencies": { 19 | "bcrypt": "^5.0.1", 20 | "cors": "^2.8.5", 21 | "dotenv": "^10.0.0", 22 | "express": "^4.17.1", 23 | "jsonwebtoken": "^8.5.1", 24 | "mongoose": "^6.0.8" 25 | }, 26 | "devDependencies": { 27 | "nodemon": "^2.0.13" 28 | }, 29 | "engines": { 30 | "node": "14.16.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /middlewares/auth.middleware.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const User = require("../models/user.model"); 3 | 4 | const privateKey = process.env.JWT_KEY; 5 | 6 | const verifyAuthentication = async (req, res, next) => { 7 | try { 8 | const bearerToken = req.headers["authorization"]; 9 | const token = bearerToken.split(" ")[1]; 10 | const decoded = jwt.verify(token, privateKey); 11 | const user = await User.findById(decoded._id); 12 | if (!user) { 13 | return res.status(401).json({ 14 | message: "You're not authorized to access this information.", 15 | }); 16 | } 17 | 18 | req.user = user; 19 | next(); 20 | } catch (error) { 21 | console.error(error); 22 | res.status(401).json({ 23 | message: "You're not authorized to acess this information.", 24 | error: error.message, 25 | }); 26 | } 27 | }; 28 | 29 | module.exports = verifyAuthentication; 30 | -------------------------------------------------------------------------------- /models/profile.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const profileSchema = new Schema({ 6 | userId: { 7 | type: Schema.Types.ObjectId, 8 | ref: "User", 9 | }, 10 | posts: [ 11 | { 12 | type: Schema.Types.ObjectId, 13 | ref: "Post", 14 | }, 15 | ], 16 | website: String, 17 | location: { 18 | type: String, 19 | default: "The Universe", 20 | }, 21 | bio: { type: String, default: "This is bio." }, 22 | dob: { 23 | type: Date, 24 | }, 25 | profileImageUrl: { 26 | type: String, 27 | default: 28 | "https://res.cloudinary.com/dnboldv5r/image/upload/v1632958381/probook/avatar_ism2fu.png", 29 | }, 30 | 31 | backgroundImageUrl: { 32 | type: String, 33 | default: 34 | "https://res.cloudinary.com/dnboldv5r/image/upload/v1632958083/probook/i_Ocean-Quote-Twitter-_20Header_full_ap6zgw.jpg", 35 | }, 36 | }); 37 | 38 | module.exports = mongoose.model("Profile", profileSchema); 39 | -------------------------------------------------------------------------------- /models/post.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const { Schema } = mongoose; 4 | 5 | const postSchema = new Schema( 6 | { 7 | text: { 8 | type: String, 9 | required: true, 10 | maxlength: 280, 11 | minlength: 5, 12 | }, 13 | author: { 14 | type: Schema.Types.ObjectId, 15 | ref: "User", 16 | }, 17 | likes: [ 18 | { 19 | type: Schema.Types.ObjectId, 20 | ref: "Like", 21 | }, 22 | ], 23 | comments: [ 24 | { 25 | type: Schema.Types.ObjectId, 26 | ref: "Comment", 27 | }, 28 | ], 29 | isLiked: { 30 | type: Boolean, 31 | default: false, 32 | }, 33 | commentsCount: { 34 | type: Number, 35 | default: 0, 36 | }, 37 | likesCount: { 38 | type: Number, 39 | default: 0, 40 | }, 41 | imageUrl: { 42 | type: String, 43 | }, 44 | }, 45 | { timestamps: true } 46 | ); 47 | 48 | module.exports = mongoose.model("Post", postSchema); 49 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | require("dotenv").config(); 4 | const auth = require("./routes/auth.routes"); 5 | const posts = require("./routes/posts.routes"); 6 | const comments = require("./routes/comments.routes"); 7 | const followings = require("./routes/followings.routes"); 8 | const followers = require("./routes/followers.routes"); 9 | const profiles = require("./routes/profiles.routes"); 10 | 11 | const verifyAuthentication = require("./middlewares/auth.middleware"); 12 | 13 | const app = express(); 14 | const connectToDB = require("./db/db"); 15 | 16 | connectToDB(process.env.DB_URL); 17 | 18 | app.use(cors()); 19 | app.use(express.json()); 20 | 21 | app.get("/", (req, res) => { 22 | res.status(200).json({ 23 | message: "Data fetched successfully.", 24 | response: "Welcome to the Probook API!", 25 | }); 26 | }); 27 | 28 | app.use("/auth", auth); 29 | app.use(verifyAuthentication); 30 | app.use("/api/posts", posts); 31 | app.use("/api/profile", profiles); 32 | app.use("/api/comments", comments); 33 | app.use("/api/followers", followers); 34 | app.use("/api/followings", followings); 35 | 36 | const port = process.env.PORT || 3001; 37 | app.listen(port, () => console.log(`Listening on port ${port}`)); 38 | -------------------------------------------------------------------------------- /routes/profiles.routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const Profile = require("../models/profile.model"); 4 | const Post = require("../models/post.model"); 5 | 6 | router.get("/:userId", async (req, res) => { 7 | try { 8 | const userId = req.params.userId; 9 | const profile = await Profile.findOne({ userId }).populate("userId").exec(); 10 | if (!profile) { 11 | return res.status(404).json({ 12 | message: "Profile does not exist.", 13 | }); 14 | } 15 | const posts = await Post.find({ author: userId }).populate("author").exec(); 16 | profile.posts = posts; 17 | res.status(200).json({ 18 | message: "Profile fetched successfully.", 19 | profile, 20 | }); 21 | } catch (error) { 22 | console.error(error); 23 | res.status(500).json({ 24 | message: "Something went wrong.", 25 | }); 26 | } 27 | }); 28 | 29 | router.put("/:profileId", async (req, res) => { 30 | try { 31 | const profileId = req.params.profileId; 32 | const updatedData = req.body; 33 | const profile = await Profile.findOneAndUpdate( 34 | { _id: profileId }, 35 | { ...updatedData }, 36 | { new: true } 37 | ); 38 | 39 | res.status(200).json({ 40 | message: "Profile updated successfully.", 41 | profile, 42 | }); 43 | } catch (error) { 44 | console.error(error); 45 | res.status(500).json({ 46 | message: "Something went wrong.", 47 | }); 48 | } 49 | }); 50 | 51 | module.exports = router; 52 | -------------------------------------------------------------------------------- /routes/followers.routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const Follower = require("../models/follower.model"); 4 | 5 | router.get("/:id", async (req, res) => { 6 | try { 7 | const userId = req.params.id; 8 | const followers = await Follower.find({ userId }); 9 | res.status(200).json({ 10 | message: "Followers fetched successfully.", 11 | response: { 12 | followers, 13 | }, 14 | }); 15 | } catch (error) { 16 | console.error(error); 17 | res.status(500).json({ 18 | message: "Something went wrong.", 19 | error: error.message, 20 | }); 21 | } 22 | }); 23 | 24 | router.post("/", async (req, res) => { 25 | try { 26 | const userId = req.body.userId; 27 | const follower = await new Follower({ 28 | userId, 29 | followerId: req.body.followerId, 30 | }); 31 | await follower.save(); 32 | res.status(201).json({ 33 | message: "Follower added successfully.", 34 | response: { 35 | follower, 36 | }, 37 | }); 38 | } catch (error) { 39 | console.error(error); 40 | res.status(500).json({ 41 | message: "Something went wrong.", 42 | error: error.message, 43 | }); 44 | } 45 | }); 46 | 47 | router.delete("/:id", async (req, res) => { 48 | try { 49 | const id = req.params.id; 50 | const userId = req.query.userId; 51 | 52 | const follower = await Follower.findOneAndDelete({ 53 | userId, 54 | followerId: id, 55 | }); 56 | if (!follower) { 57 | return res.status(404).json({ 58 | message: "follower does not exist.", 59 | }); 60 | } 61 | 62 | res.status(200).json({ 63 | message: "Follower removed successfully.", 64 | response: { 65 | follower, 66 | }, 67 | }); 68 | } catch (error) { 69 | console.error(error); 70 | res.status(500).json({ 71 | message: "Something went wrong.", 72 | error: error.message, 73 | }); 74 | } 75 | }); 76 | 77 | module.exports = router; 78 | -------------------------------------------------------------------------------- /routes/followings.routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const Following = require("../models/following.model"); 4 | 5 | router.get("/:id", async (req, res) => { 6 | try { 7 | const userId = req.params.id; 8 | const followings = await Following.find({ userId }); 9 | res.status(200).json({ 10 | message: "Followings fetched successfully.", 11 | response: { 12 | followings, 13 | }, 14 | }); 15 | } catch (error) { 16 | console.error(error); 17 | res.status(500).json({ 18 | message: "Something went wrong.", 19 | error: error.message, 20 | }); 21 | } 22 | }); 23 | 24 | router.post("/", async (req, res) => { 25 | try { 26 | const userId = req.body.userId; 27 | const following = await new Following({ 28 | userId, 29 | followingId: req.body.followingId, 30 | }); 31 | await following.save(); 32 | res.status(201).json({ 33 | message: "following added successfully.", 34 | response: { 35 | following, 36 | }, 37 | }); 38 | } catch (error) { 39 | console.error(error); 40 | res.status(500).json({ 41 | message: "Something went wrong.", 42 | error: error.message, 43 | }); 44 | } 45 | }); 46 | 47 | router.delete("/", async (req, res) => { 48 | try { 49 | const id = req.query.followingId; 50 | const userId = req.query.userId; 51 | 52 | const following = await Following.findOneAndDelete({ 53 | userId, 54 | followingId: id, 55 | }); 56 | console.log(following); 57 | if (!following) { 58 | return res.status(404).json({ 59 | message: "following does not exist.", 60 | }); 61 | } 62 | 63 | res.status(200).json({ 64 | message: "following removed successfully.", 65 | response: { 66 | following, 67 | }, 68 | }); 69 | } catch (error) { 70 | console.error(error); 71 | res.status(500).json({ 72 | message: "Something went wrong.", 73 | error: error.message, 74 | }); 75 | } 76 | }); 77 | 78 | module.exports = router; 79 | -------------------------------------------------------------------------------- /routes/comments.routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const Comment = require("../models/comment.model"); 4 | const Post = require("../models/post.model"); 5 | 6 | router.get("/:postId", async (req, res) => { 7 | try { 8 | const post = await Post.findOne({ _id: req.params.postId }); 9 | if (!post) { 10 | return res.status(404).json({ 11 | message: "The post you were looking for is not available.", 12 | }); 13 | } 14 | const comments = await Comment.find({ postId: req.params.postId }) 15 | .populate("author") 16 | .exec(); 17 | res.status(200).json({ 18 | message: "Comments fetched successfully.", 19 | response: { 20 | comments, 21 | }, 22 | }); 23 | } catch (error) { 24 | console.error(error); 25 | res.status(500).json({ 26 | message: "Something went wrong.", 27 | error: error.message, 28 | }); 29 | } 30 | }); 31 | 32 | router.post("/:postId", async (req, res) => { 33 | try { 34 | const postId = req.params.postId; 35 | const author = req.user._id; 36 | const comment = await new Comment({ postId, author, text: req.body.text }); 37 | await comment.save(); 38 | res.status(201).json({ 39 | message: "Comment created successfully.", 40 | response: { 41 | comment, 42 | }, 43 | }); 44 | } catch (error) { 45 | console.error(error); 46 | res.status(500).json({ 47 | message: "Something went wrong.", 48 | error: error.message, 49 | }); 50 | } 51 | }); 52 | 53 | router.delete("/:postId/:commentId", async (req, res) => { 54 | try { 55 | const postId = req.params.postId; 56 | const commentId = req.params.commentId; 57 | const comment = await Comment.findOneAndDelete({ postId, _id: commentId }); 58 | if (!comment) { 59 | return res.status(404).json({ 60 | message: "Comment does not exist.", 61 | }); 62 | } 63 | res.status(200).json({ 64 | message: "Comment deleted successfully.", 65 | response: { 66 | comment, 67 | }, 68 | }); 69 | } catch (error) { 70 | console.error(error); 71 | res.status(500).json({ 72 | message: "Something went wrong.", 73 | error: error.message, 74 | }); 75 | } 76 | }); 77 | 78 | module.exports = router; 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Probook App | A Social Media App 2 | 3 | ![Logo](https://res.cloudinary.com/dnboldv5r/image/upload/v1633739721/probook/Probook_kybzoe.png) 4 | 5 | An social media platform built using ReactJS, Redux Toolkit,Material UI, Node, Express, MongoDB, JWT and Mongoose. 6 | 7 | ## Tech Stack 8 | 9 | **Client:** React, Redux, Material UI and React Router. 10 | 11 | **Server:** Node, Express, MongoDB, Mongoose and JWT. 12 | 13 | ## Screenshots 14 | 15 | ![App Screenshot](https://res.cloudinary.com/dnboldv5r/image/upload/v1633739754/probook/Screenshot_76_e1cack.png) 16 | 17 | ![App Screenshot](https://res.cloudinary.com/dnboldv5r/image/upload/v1633739752/probook/Screenshot_74_snfvxa.png) 18 | 19 | ![App Screenshot](https://res.cloudinary.com/dnboldv5r/image/upload/v1633739753/probook/Screenshot_77_c2vowm.png) 20 | 21 | ## Demo 22 | 23 | Live app link: https://probookhq.netlify.app/ 24 | 25 | ## Run Locally 26 | 27 | Clone the project 28 | 29 | ```bash 30 | git clone https://github.com/wasifbaliyan/probook-server.git 31 | ``` 32 | 33 | Go to the project directory 34 | 35 | ```bash 36 | cd probook-server 37 | ``` 38 | 39 | Install dependencies 40 | 41 | ```bash 42 | npm install 43 | ``` 44 | 45 | Add .env file 46 | 47 | ```bash 48 | DB_URL=your mongodb address 49 | JWT_KEY=set your private jwt key 50 | ``` 51 | 52 | Start probook server at port 3001 53 | 54 | ```bash 55 | npm start 56 | ``` 57 | 58 | ## Authors 59 | 60 | - [@wasifbaliyan](https://www.github.com/wasifbaliyan) 61 | 62 | ## 🚀 About Me 63 | 64 | I'm a full stack Javascript Developer. I Love to build beautiful and scalable web apps. 65 | 66 | ## 🔗 Links 67 | 68 | [![portfolio](https://img.shields.io/badge/my_portfolio-000?style=for-the-badge&logo=ko-fi&logoColor=white)](https://wasifbaliyan.com/) 69 | [![linkedin](https://img.shields.io/badge/linkedin-0A66C2?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/wasifbaliyan) 70 | [![twitter](https://img.shields.io/badge/twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/wasifbaliyan) 71 | 72 | ## Badges 73 | 74 | [![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) 75 | 76 | ## Roadmap 77 | 78 | - Search feature 79 | 80 | - Toast notifications 81 | 82 | - bookmarks 83 | 84 | ## Support 85 | 86 | For support, email hello@wasifbaliyan.com 87 | 88 | ## Feedback 89 | 90 | If you have any feedback, please reach out to me at hello@wasifbaliyan.com 91 | -------------------------------------------------------------------------------- /routes/auth.routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const bcrypt = require("bcrypt"); 3 | const User = require("../models/user.model"); 4 | const generateAuthToken = require("../utils/generateAuthToken"); 5 | const router = express.Router(); 6 | const Profile = require("../models/profile.model"); 7 | const Follower = require("../models/follower.model"); 8 | const Following = require("../models/following.model"); 9 | const verifyAuthentication = require("../middlewares/auth.middleware"); 10 | 11 | router.post("/register", async (req, res) => { 12 | try { 13 | const { email } = req.body; 14 | const foundUser = await User.findOne({ email }); 15 | if (foundUser) { 16 | return res.status(400).json({ 17 | message: "User with this email already exists.", 18 | }); 19 | } else { 20 | let user = await new User(req.body); 21 | const salt = await bcrypt.genSalt(10); 22 | 23 | user.password = await bcrypt.hash(user.password, salt); 24 | user = await user.save(); 25 | 26 | const token = generateAuthToken(user._id); 27 | const profile = await new Profile({ userId: user._id }); 28 | await profile.save(); 29 | return res.status(201).json({ 30 | message: "User created successfully.", 31 | response: { 32 | name: user.name, 33 | email: user.email, 34 | _id: user._id, 35 | token, 36 | }, 37 | }); 38 | } 39 | } catch (error) { 40 | return res.status(500).json({ 41 | message: "Something went wrong!", 42 | error: error.message, 43 | }); 44 | } 45 | }); 46 | 47 | router.get("/users", verifyAuthentication, async (req, res) => { 48 | try { 49 | const users = await User.find(); 50 | res.status(200).json({ 51 | response: { 52 | users, 53 | }, 54 | message: "Users fetched successfully.", 55 | }); 56 | } catch (error) { 57 | return res.status(500).json({ 58 | message: "Something went wrong!", 59 | error: error.message, 60 | }); 61 | } 62 | }); 63 | 64 | router.post("/login", async (req, res) => { 65 | try { 66 | const { email, password } = req.body; 67 | 68 | const foundUser = await User.findOne({ email }); 69 | if (!foundUser) { 70 | return res.status(403).json({ 71 | message: "Incorrect email or password!", 72 | }); 73 | } else { 74 | const isPasswordValid = bcrypt.compare(password, foundUser.password); 75 | if (!isPasswordValid) { 76 | return res.status(403).json({ 77 | message: "Incorrect email or password.", 78 | }); 79 | } 80 | 81 | const token = generateAuthToken(foundUser._id); 82 | 83 | return res.status(200).json({ 84 | message: "Logged in successfully.", 85 | response: { 86 | token, 87 | name: foundUser.name, 88 | email: foundUser.email, 89 | _id: foundUser._id, 90 | }, 91 | }); 92 | } 93 | } catch (error) { 94 | return res.status(500).json({ 95 | message: "Something went wrong!", 96 | error: error.message, 97 | }); 98 | } 99 | }); 100 | 101 | module.exports = router; 102 | -------------------------------------------------------------------------------- /routes/posts.routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const Post = require("../models/post.model"); 4 | const Like = require("../models/like.model"); 5 | 6 | router.get("/", async (req, res) => { 7 | try { 8 | const userId = req.user._id; 9 | const posts = await Post.find() 10 | .sort({ createdAt: -1 }) 11 | .populate("author") 12 | .exec(); 13 | const updatedPosts = posts.map((post) => { 14 | if (post.likes.includes(userId)) { 15 | post.isLiked = true; 16 | } 17 | return post; 18 | }); 19 | res.status(200).json({ 20 | response: { 21 | posts: updatedPosts, 22 | }, 23 | message: "Posts fetched successfully.", 24 | }); 25 | } catch (error) { 26 | console.error(error); 27 | res.status(500).json({ 28 | message: "Something went wrong.", 29 | error: error.message, 30 | }); 31 | } 32 | }); 33 | 34 | router.get("/:id", async (req, res) => { 35 | try { 36 | const userId = req.user._id; 37 | const id = req.params.id; 38 | const post = await Post.findOne({ _id: id }).populate("author").exec(); 39 | if (post.likes.includes(userId)) { 40 | post.isLiked = true; 41 | } 42 | 43 | res.status(200).json({ 44 | response: { 45 | post, 46 | }, 47 | message: "Post fetched successfully.", 48 | }); 49 | } catch (error) { 50 | console.error(error); 51 | res.status(500).json({ 52 | message: "Something went wrong.", 53 | error: error.message, 54 | }); 55 | } 56 | }); 57 | 58 | router.post("/", async (req, res) => { 59 | try { 60 | const author = { 61 | name: req.user.name, 62 | handle: req.user.handle, 63 | _id: req.user._id, 64 | }; 65 | const post = await new Post({ author, ...req.body }); 66 | post.author = author; 67 | await post.save(); 68 | res.status(201).json({ 69 | response: { 70 | post, 71 | }, 72 | message: "Post created successfully.", 73 | }); 74 | } catch (error) { 75 | console.error(error); 76 | res.status(500).json({ 77 | message: "Something went wrong.", 78 | error: error.message, 79 | }); 80 | } 81 | }); 82 | 83 | router.delete("/:id", async (req, res) => { 84 | try { 85 | const userId = req.user._id; 86 | const id = req.params.id; 87 | const post = await Post.findOneAndDelete({ id, author: userId }); 88 | if (!post) { 89 | res.status(404).json({ 90 | message: "Post couldn't be found.", 91 | }); 92 | } 93 | res.json({ 94 | response: { 95 | post, 96 | }, 97 | message: "Post deleted successfully", 98 | }); 99 | } catch (error) { 100 | console.error(error); 101 | res.status(500).json({ 102 | message: "Something went wrong.", 103 | error: error.message, 104 | }); 105 | } 106 | }); 107 | 108 | // like and unlike a post 109 | router.post("/likes", async (req, res) => { 110 | try { 111 | const userId = req.user._id; 112 | const post = await Post.findOne({ _id: req.body.id }); 113 | if (!post) { 114 | return res.status(404).json({ 115 | message: "Post couldn't be found.", 116 | }); 117 | } 118 | const foundLike = await Like.findOne({ postId: post._id, author: userId }); 119 | if (!foundLike) { 120 | post.isLiked = true; 121 | const newLike = await new Like({ postId: post._id, author: userId }); 122 | await newLike.save(); 123 | post.likes.push(newLike); 124 | } else { 125 | post.isLiked = false; 126 | await Like.findOneAndDelete({ postId: post._id, author: userId }); 127 | const foundIndex = post.likes.indexOf(foundLike._id); 128 | post.likes.splice(foundIndex, 1); 129 | } 130 | 131 | await post.save(); 132 | res.status(200).json({ 133 | response: { post }, 134 | message: "Post updated successfully.", 135 | }); 136 | } catch (error) { 137 | console.error(error); 138 | res.status(500).json({ 139 | message: "Something went wrong.", 140 | error: error.message, 141 | }); 142 | } 143 | }); 144 | 145 | module.exports = router; 146 | --------------------------------------------------------------------------------