├── .gitignore ├── config └── mongoConfig.js ├── docs └── basicInfo.js ├── routes ├── apidocs.js ├── users.js ├── auth.js └── blogs.js ├── models ├── userSchema.js └── blogSchema.js ├── middleware └── authMiddleware ├── package.json ├── server.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | node_nodules/ 3 | .env -------------------------------------------------------------------------------- /config/mongoConfig.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | 4 | 5 | module.exports = async() => { 6 | try { 7 | await mongoose.connect(process.env.MONGODB_URI) //makes the request 8 | mongoose.connection // checks if we havve a connection 9 | console.log('MongoBD Connected!'); 10 | } catch (error) { 11 | console.error(error) 12 | } 13 | } -------------------------------------------------------------------------------- /docs/basicInfo.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | openapi: "3.0.3", // present supported openapi version 3 | info: { 4 | title: "Blog API", // short title. 5 | description: "A Blog API, with full CRUD using NodeJS, Express, Mongoose, and MongoDB. ", 6 | version: "1.0.0", // version number 7 | contact: { 8 | name: "Jason Mui", // your name 9 | email: "jason@web.com", 10 | url: "https://jmui-blog.herokuapp.com", // your website 11 | }, 12 | }, 13 | }; -------------------------------------------------------------------------------- /routes/apidocs.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | const swaggerUi = require('swagger-ui-express'); 3 | const swaggerDocument = require('../docs/basicInfo'); 4 | // display basic info about project 5 | router.use('/', swaggerUi.serve); // Launches Swagger UI 6 | router.get('/', swaggerUi.setup(swaggerDocument)); // endpoint to display basic API info in web browser 7 | router.get('/swagger.json', (request, response) => response.json(swaggerDocument)) // Response is JSON object 8 | module.exports = router -------------------------------------------------------------------------------- /models/userSchema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const userSchema = mongoose.Schema({ 4 | username: { 5 | type: String, 6 | required: true 7 | }, 8 | 9 | email: { 10 | type: String, 11 | required: true, 12 | unique: true 13 | }, 14 | 15 | birthday: { 16 | type: Date, 17 | required: true 18 | }, 19 | 20 | age: { 21 | type: Number 22 | }, 23 | 24 | password: { 25 | type: String, 26 | required: true 27 | } 28 | }) 29 | 30 | module.exports = mongoose.model('User', userSchema) -------------------------------------------------------------------------------- /middleware/authMiddleware: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | 3 | module.exports = (req,res,next) => { 4 | // get the token from the headers object 5 | const token = req.header('x-auth-token') 6 | // If NO token 7 | if (!token) { 8 | return res.json('No Token Acces denied') 9 | } 10 | //If we have a token 11 | try{ 12 | const decoded =jwt.verify(token, process.env.SECRET_KEY,{ expired: "2 Days"}) 13 | req.user=decoded //save user token which can then be used in other routes 14 | next() 15 | } catch (error) { 16 | console.log(error); 17 | res.status(400).json('Token not valid') 18 | } 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blogapi", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/jsnmui/blogapi.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/jsnmui/blogapi/issues" 19 | }, 20 | "homepage": "https://github.com/jsnmui/blogapi#readme", 21 | "dependencies": { 22 | "bcrypt": "^5.0.1", 23 | "dotenv": "^16.0.1", 24 | "express": "^4.18.1", 25 | "express-validator": "^6.14.1", 26 | "helmet": "^5.1.0", 27 | "jsonwebtoken": "^8.5.1", 28 | "mongoose": "^6.3.8", 29 | "morgan": "^1.10.0", 30 | "swagger-ui-express": "^4.4.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | require('dotenv').config() // init dotenv 3 | const morgan = require('morgan') 4 | const helmet = require('helmet') 5 | 6 | const mongoConfig =require('./config/mongoConfig') 7 | const blogs = require('./routes/blogs') 8 | const users = require('./routes/users') 9 | const auth = require('./routes/auth') 10 | const apidocs = require('./routes/apidocs') 11 | 12 | const app = express() 13 | const PORT = process.env.PORT || 5000 14 | 15 | app.use(express.json()) //parse into json file read from req.body data coming in 16 | app.use(morgan('dev')) 17 | app.use(helmet()) 18 | 19 | 20 | // * Routers 21 | app.use('/blogs', blogs) //handles blog requests 22 | app.use('/users', users) //requests on user accounts 23 | app.use('/auth', auth) // login an registration requests 24 | app.use('/apidocs', apidocs) // basic info about api for swagger 25 | 26 | //* Root route for the APP 27 | app.get('/', (req, res) => { 28 | res.status(200).json('Welcome to my API') 29 | }) 30 | 31 | 32 | 33 | app.listen(PORT, () => { 34 | console.log(`Server is running on port: ${PORT}`); 35 | mongoConfig() 36 | }) -------------------------------------------------------------------------------- /models/blogSchema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | 4 | const blogSchema = mongoose.Schema({ 5 | creator_id:{ 6 | type: mongoose.Schema.Types.ObjectId, // links the blog to user 7 | ref: 'user' , // refers to the user model 8 | required: true 9 | }, 10 | 11 | created_by: { 12 | type: String, 13 | required: true 14 | }, 15 | 16 | created_at: { 17 | type: Date, 18 | required: true, 19 | default: Date.now() 20 | }, 21 | 22 | blog_title: { 23 | type: String, 24 | required: true 25 | }, 26 | 27 | blog_content: { 28 | type: String, 29 | required: true 30 | }, 31 | 32 | comments: [{ 33 | 34 | creator_id: { 35 | type: mongoose.Schema.Types.ObjectId, // links the comment to user 36 | ref: 'user' // refers to the user model 37 | }, 38 | 39 | created_at: { 40 | type: Date, 41 | default: Date.now() 42 | }, 43 | 44 | comment: { 45 | type: String 46 | 47 | } 48 | 49 | }], 50 | 51 | likesHistory:[{ //tracks who liked this blog post 52 | 53 | user_id: { 54 | type: mongoose.Schema.Types.ObjectId, // links the like to user 55 | ref: 'user', 56 | required: true // refers to the user model 57 | }, 58 | 59 | like: { 60 | type: Boolean 61 | } 62 | }], 63 | 64 | likes:{ // likes counter 65 | type: Number, 66 | default: 0 67 | }, 68 | 69 | private: { 70 | type: Boolean, 71 | required: true 72 | }, 73 | 74 | }) 75 | 76 | module.exports = mongoose.model('blog', blogSchema) 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const UserModel = require('../models/userSchema') 3 | const authMiddleware = require('../middleware/authMiddleware') 4 | // * Create a Router 5 | const router = express.Router() 6 | 7 | // Get all users 8 | router.get('/',authMiddleware,async (req,res) => { 9 | 10 | try { 11 | const users = await UserModel.find() 12 | res.status(200).json(users) 13 | } catch (error) { 14 | console.log(error) 15 | } 16 | 17 | 18 | }) 19 | 20 | //GET User BY ID 21 | router.get('/:id', authMiddleware, async (req, res) => { 22 | const id = req.params.id 23 | 24 | try { 25 | const user = await UserModel.findById(id) 26 | res.status(200).json(user) 27 | } catch (error) { 28 | console.error(error) 29 | res.status(400).json({ 30 | msg: 'Id not found' 31 | }) 32 | } 33 | }) 34 | 35 | 36 | 37 | //* UPDATE USER BY ID 38 | router.put('/:id',authMiddleware ,async (req, res) => { 39 | const id = req.params.id 40 | const newUserData = req.body 41 | try { 42 | 43 | const usertoUpdate = await UserModel.findById(id) 44 | 45 | if (usertoUpdate._id.toString() !== req.user.id ) { 46 | return res.status(400).json({msg: 'Not Authorized ! '}) // check to see if user logged in is the owner of the account 47 | } 48 | 49 | //* find the user by the id 50 | const user = await UserModel.findByIdAndUpdate(id, newUserData, {new: true}) 51 | res.status(202).json(user) 52 | } catch (error) { 53 | console.log(error) 54 | res.status(400).json({ 55 | msg: 'Id not found' 56 | }) 57 | } 58 | }) 59 | 60 | //! DELETE A USER 61 | router.delete('/:id', authMiddleware,async (req, res) => { 62 | const id = req.params.id 63 | 64 | try { 65 | 66 | const usertoDelete = await UserModel.findById(id) 67 | 68 | if (usertoDelete._id.toString() !== req.user.id ) { 69 | return res.status(400).json({msg: 'Not Authorized ! '}) // check to see if user logged in is the owner of the account 70 | } 71 | 72 | const user= await UserModel.findByIdAndDelete(id) 73 | res.status(200).json( {msg: `User # ${id} was deleted`}) 74 | } catch (error) { 75 | console.log(error); 76 | res.status(400).json({ 77 | msg: 'Id not found' 78 | }) 79 | } 80 | }) 81 | 82 | 83 | 84 | module.exports = router -------------------------------------------------------------------------------- /routes/auth.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | // pulls out the two function we nee from express validator 3 | const {check, validationResult} = require('express-validator') 4 | const bcrypt = require('bcrypt') 5 | const jwt = require('jsonwebtoken') 6 | const UserModel = require('../models/userSchema') 7 | 8 | const router = express.Router() 9 | 10 | 11 | //* Create or Register a new User 12 | router.post('/registration', [ 13 | check('username',"Username is required from Middleware!").notEmpty(), 14 | check("email", "Please use a valid email! from middleware").isEmail(), 15 | check("password","Please enter a password").notEmpty(), 16 | check("password","Please enter a password with six or more characters").isLength({min:6}) 17 | ] ,async (req, res) => { 18 | const userData = req.body 19 | const errors = validationResult(req) 20 | 21 | //checks for validation errors 22 | if(!errors.isEmpty()){ 23 | return res.json(errors.array()) 24 | } 25 | 26 | try { 27 | //checking if there is an user this email in the db 28 | const userExist = await UserModel.findOne({email: userData.email}) 29 | // if user exists we return 30 | if (userExist){ 31 | return res.json({msg:"User already exist!"}) 32 | } 33 | 34 | //* ==== Create New User 35 | //1 Create the salt 36 | const SALT = await bcrypt.genSalt(10) 37 | // 2 use the salt to create a hash with the user's password 38 | const hashedPassword = await bcrypt.hash(userData.password, SALT) 39 | // 3 assign the hashed password to the new userData 40 | console.log(hashedPassword) 41 | userData.password = hashedPassword 42 | //write the user to the db 43 | const user = await UserModel.create(userData) 44 | 45 | //*create a new JWT Token 46 | 47 | const payload = { 48 | id: user._id, 49 | email: user.email 50 | } 51 | 52 | 53 | 54 | const TOKEN = jwt.sign(payload, process.env.SECRET_KEY) 55 | 56 | res.status(201).json({ 57 | user: user, 58 | token: TOKEN 59 | }) 60 | 61 | 62 | } catch (error) { 63 | console.log(error) 64 | res.status(400).json('Bad request!!!!!') 65 | } 66 | }) 67 | 68 | 69 | 70 | 71 | //* User Login 72 | router.post('/login',[ 73 | check("email", "Please provide a valid email").isEmail(), 74 | check("password", "Check your password!").notEmpty() 75 | ] , async (req, res) => { 76 | const userData = req.body 77 | 78 | const errors = validationResult(req) 79 | // Checks for validation errors 80 | if (!errors.isEmpty()){ 81 | return res.json(errors.array()) 82 | } 83 | 84 | try { 85 | // Find the user with the provided email 86 | const user = await UserModel.findOne({email: userData.email}) 87 | 88 | if (!user){ 89 | return res.json('User not found!') 90 | } 91 | 92 | // Compare the plain text password to hashed password 93 | const isMatch = await bcrypt.compare(userData.password, user.password) 94 | 95 | if (!isMatch){ 96 | return res.json('Password is not a match!') 97 | } 98 | 99 | 100 | 101 | //* Create a new JWT Token 102 | 103 | const payload = { 104 | id: user._id, 105 | email: user.email 106 | } 107 | 108 | const TOKEN = jwt.sign(payload, process.env.SECRET_KEY) 109 | 110 | res.status(201).json({ 111 | user: user, 112 | token: TOKEN 113 | }) 114 | 115 | 116 | } catch (error) { 117 | console.log(error); 118 | res.status(500).json('Server Error') 119 | } 120 | 121 | 122 | 123 | }) 124 | 125 | 126 | 127 | 128 | 129 | module.exports = router -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # A Blog API 3 | ## About the app 4 | A Blog API, with full CRUD using NodeJS, Express, Mongoose, and MongoDB. Allows user to register though the auth route, where the user receives a token. With the token the user can view and create blogs. The user can update and create the user's own blogs. The user can also add comments and like a blog. 5 | This app is deployed on Heroku at [BlogAPI](https://jmui-blog.herokuapp.com/ "BlogAPI") 6 | 7 | 8 | ## Technologies Used 9 | ### Server 10 | * Node.js - an open source asynchronous event-driven server environment that executes JavaScript code outside a web browser. 11 | * Express - a back end web application framework for Node.js 12 | * Nodemon - a tool that automatically restarts a node application when file changes in the directory are detected. 13 | 14 | ### Database 15 | * MongoDB - a non-relational document database that stores data in a format similar to Javascript Object Notation. 16 | * Mongoose - a JavaScript library that creates a connection between MongoDB and the Express web application framework. 17 | 18 | ### Middleware 19 | * MORGAN - an Express middleware to log HTTP requests and errors, and simplifies the process. 20 | * HELMET - an Express middleware that helps secure HTTP headers returned by an Express apps. 21 | * Express-Validator - an express middleware that provides validation and sanitization functions 22 | 23 | ### Encryption 24 | * Bcrypt - a library to help you hash passwords. 25 | 26 | ### Tokens 27 | * jsonwebtoken - an implementation of JSON Web Token (JWT), which is a standard for sharing security information between a client and a server. Each JWT contains encoded data that is cryptographically signed with a secret value that can act like a "key". It can be sent to a client as proof of authenticity and sent back to the server on subsequent requests as proof of the client's authenticity. 28 | 29 | ### Loading Environmental Variables 30 | * dotenv - module that loads environment variables from a .env file into process.env 31 | 32 | ### Testing the API 33 | * Postman - an API platform for developers to design, build, test and iterate their APIs. 34 | 35 | ## Environmental Variables 36 | These variables are needed in the .env file 37 | * MONGODB_URI 38 | * SECRET_KEY 39 | 40 | ## Installation Instructions to Run Locally 41 | 42 | ### Clone the project 43 | 1. Create a folder for project on your local machine. 44 | 2. Open a bash shell. 45 | 3. cd into folder that was created in step 1 46 | 3. In the terminal type: git clone https://github.com/jsnmui/blogapi.git 47 | 48 | ### Node.js 49 | 1. Go to https://nodejs.org/en/download/ 50 | 2. Download the correct installer for your system. 51 | 3. Run the installer. 52 | 53 | ### MongoDB 54 | 1. Create account on https://www.mongodb.com/ 55 | 2. Create a new cluster. 56 | 3. Click connect to get connection string, 57 | 4. Add connection string to MONGODB_URI in .env file. 58 | 59 | ### Install dependencies 60 | 1. In Git Bash terminal, type npm init -y 61 | 2. Type 'npm install' before each of the following: 62 | * express 63 | * mongoose 64 | * bcrypt 65 | * dotenv 66 | * jsonwebtoken 67 | * morgan 68 | * helmet 69 | * express-validator 70 | 71 | ## Endpoints, Parameters, Schema 72 | ### Routes 73 | In server.js, root route for app.get(/) returns "Welcome to my API" 74 | 75 | #### auth route for login and registration 76 | * post('/registration') - Register new users. userSchema is used. Password hasehd with bcrypt.hash. Token generated with jwt.sign. 77 | * post('/login') - Login with user's email and password. Token generated with jwt.sign 78 | 79 | #### users route 80 | * get('/') - Must be a registered user with a valid token to get all users. 81 | * get('/:id') - Get a user by setting parameter id to the user's id. Must be a registered user with a valid token. 82 | * put('/:id') - Updates a user. Must be a registered user with a valid token. Check id parameter to see if the user is owner of the account and updates user information. 83 | * delete('/:id') - Deletes a user. Protected with token. Check id parameter to see if the user is owner of the account and deletes user account. 84 | 85 | 86 | #### blogs route 87 | * get('/') - Retrieves all blogs. User must be registered and have a valid token. Sorted by date in descending order. 88 | * get('/nonprivate') - Gets public blogs. Doesn't require registration token. 89 | * post('/') - Creates a new blog post. User needs to be registered and have a valid token. 90 | * get('/:id') - Get a blogs by sending the blog id as the parameter. User needs to be registered and have a valid token. 91 | * put('/:id') - Update a blog by sending the blog id as the parameter. User needs to be registered and have a valid token. 92 | * delete('/:id') - Delete a blog by sending the blog id as the parameter. User needs to be registered and have a valid token. 93 | * put('/like/:blogid') - Allows a registered user to like a blog post and increase the like counter for a post. Each user can like a post only once. Takes the blog id as the parameter. A user can like a post by sending the id. A user can remove the same like by sending the id again. 94 | * get('/likedby/:userid') - Allows a registered user to find all blog posts liked by another user. Takes a user id as a parameter. 95 | * put('/addcomment/:id') - Allows a registered user to add a comment to a post. Needs a blog id as a parameter. 96 | 97 | ### Schemas 98 | #### userSchema 99 | * username: type: String, required: true 100 | * email: type: String, required: true, unique: true 101 | * birthday: type: Date, required: true 102 | * age: type: Number 103 | * password: type: String, required: true 104 | 105 | #### blogSchema 106 | * creator_id: type: mongoose.Schema.Types.ObjectId, ref: 'user', required: true 107 | * created_by: type: String, required: true 108 | * created_at: type: Date, required: true, default: Date.now() 109 | * blog_title: type: String,required: true 110 | * blog_content: type: String,required: true 111 | * comments: [creator_id: type: mongoose.Schema.Types.ObjectId, ref:'user', created_at: type: Date, default: Date.now(), comment: type: String] 112 | * likesHistory:[user_id: type: mongoose.Schema.Types.ObjectId, ref: 'user', like: type: Boolean] 113 | * likes: type: Number, default: 0 114 | * private: type: Boolean, required: true 115 | 116 | ## authMiddleware 117 | * Token taken from req.header('x-auth-token'). In Postman, x-auth-token was set to the token generated at users/login or users/registration routes. 118 | * Token is verified using the jwt.verify method and the unique SECRET_KEY. 119 | * Decoded data that is returned from jwt.verify is saved in req.user to be used in other routes. 120 | 121 | -------------------------------------------------------------------------------- /routes/blogs.js: -------------------------------------------------------------------------------- 1 | 2 | const express = require('express') 3 | const blogModel =require('../models/blogSchema') 4 | const authMiddleware = require('../middleware/authMiddleware') 5 | //* Create a Router 6 | const router = express.Router() 7 | 8 | //* Get Blogs 9 | router.get('/', authMiddleware,async (req,res) => { 10 | try { 11 | const blogs = await blogModel.find().sort({"created_at": -1}) // retrieves all blogs sorted by creation date in decending order. 12 | res.status(200).json(blogs) 13 | } catch (error) { 14 | console.log(error) 15 | } 16 | }) 17 | 18 | 19 | //* Get NONPRIVATE Blogs 20 | router.get('/nonprivate', async (req,res) => { 21 | try { 22 | const blogs = await blogModel.find({ private: false }).sort({"created_at": -1}) // retrieves all public blogs sorted by creation date in decending order. 23 | res.status(200).json(blogs) 24 | } catch (error) { 25 | console.log(error) 26 | } 27 | }) 28 | 29 | //* CREATE BLOGS 30 | router.post('/',authMiddleware, async (req, res) => { 31 | const blogData = req.body // gets the data from the request 32 | blogData.creator_id = req.user.id // insert creator id into body 33 | 34 | try { 35 | const blog = await blogModel.create(blogData) // create the blog in the db 36 | // send back the response 37 | res.status(201).json(blog) 38 | 39 | } catch (error) { 40 | console.error(error) 41 | res.status(400).json('Bad request!!!!!') 42 | } 43 | }) 44 | 45 | //* GET BLOG BY ID 46 | router.get('/:id', authMiddleware,async (req, res) => { 47 | const id = req.params.id 48 | 49 | try { 50 | const blog = await blogModel.findById(id) 51 | res.status(200).json(blog) 52 | } catch (error) { 53 | console.error(error) 54 | res.status(400).json({ 55 | msg: 'Id not found' 56 | }) 57 | } 58 | }) 59 | 60 | 61 | //* UPDATE BLOG BY ID 62 | router.put('/:id',authMiddleware ,async (req, res) => { 63 | const id = req.params.id 64 | const newBlogData = req.body 65 | 66 | 67 | try { 68 | const blogtoUpdate = await blogModel.findById(id) 69 | 70 | if (blogtoUpdate.creator_id.toString() !== req.user.id ) { 71 | return res.status(400).json({msg: 'Not Authorized ! '}) // check to see if user logged in is the author of the blog 72 | } 73 | 74 | //* find the BLOG by the id 75 | const blog = await blogModel.findByIdAndUpdate(id, newBlogData, {new:true}) 76 | res.status(202).json(blog) 77 | } catch (error) { 78 | console.log(error) 79 | res.status(400).json({ 80 | msg: 'Id not found' 81 | }) 82 | } 83 | }) 84 | 85 | //! DELETE A BLOG 86 | router.delete('/:id', authMiddleware,async (req, res) => { 87 | const id = req.params.id 88 | 89 | try { 90 | const blogtoUpdate = await blogModel.findById(id) 91 | 92 | if (blogtoUpdate.creator_id.toString() !== req.user.id ) { 93 | return res.status(400).json({msg: 'Not Authorized ! '}) 94 | } 95 | 96 | const blog= await blogModel.findByIdAndDelete(id) 97 | res.status(200).json( {msg: `Blog # ${id} was deleted`}) 98 | } catch (error) { 99 | console.log(error); 100 | res.status(400).json({ 101 | msg: 'Id not found' 102 | }) 103 | } 104 | }) 105 | 106 | // Like a blog post 107 | router.put('/like/:blogid', authMiddleware,async (req,res) => { 108 | const id = req.params.blogid 109 | 110 | try { 111 | //* find the BLOG by the id 112 | //* allow user to like a blog post only once 113 | let blog = await blogModel.findById(id)// find the blog 114 | let found = false 115 | let msg = "" 116 | blog.likesHistory.forEach(element => { // search like history to determine is user already liked post 117 | if(element.user_id.toString() === req.user.id){ 118 | found = true 119 | if (element.like === true) { //toggle 120 | element.like = false 121 | blog.likes-- 122 | msg = `Blog #${id} was unliked by user ${req.user.id}.` 123 | } else { 124 | element.like = true 125 | blog.likes++ 126 | msg = `Blog #${id} was liked by user ${req.user.id}.` 127 | } 128 | } 129 | }) 130 | 131 | if (found === false ) { 132 | let like = { "user_id" : req.user.id, "like": true } 133 | blog.likesHistory.push(like) 134 | blog.likes++ 135 | msg = `Blog #${id} was liked by user ${req.user.id}.` 136 | } 137 | 138 | blog.save() // save update to database 139 | res.status(202).json({ 140 | blog: blog, 141 | msg: msg 142 | }) 143 | 144 | } catch (error) { 145 | console.log(error) 146 | res.status(400).json({ 147 | msg: 'Id not found' 148 | }) 149 | } 150 | 151 | }) 152 | 153 | // Find all posts liked by a user 154 | router.get('/likedby/:userid', authMiddleware,async (req,res) => { 155 | 156 | try { 157 | //* find the blogs liked by user in id parameter 158 | 159 | let blog = await blogModel.find({ "likesHistory.user_id": req.params.userid, "likesHistory.like": true })// find the blogs like by a user 160 | 161 | if (blog.length === 0) { 162 | return res.status(400).json({ 163 | msg: 'No blogs found' 164 | }) 165 | } 166 | 167 | res.status(202).json(blog) 168 | 169 | } catch (error) { 170 | console.log(error) 171 | res.status(400).json({ 172 | msg: 'Id not found' 173 | }) 174 | } 175 | 176 | }) 177 | 178 | 179 | // Add a comment to a blog post 180 | 181 | router.put('/addcomment/:id', authMiddleware,async (req,res) => { 182 | const id = req.params.id 183 | const newComment= req.body 184 | newComment.creator_id = req.user.id 185 | try { 186 | //* find the BLOG by the id 187 | //* allow user to like a blog post only once 188 | let blog = await blogModel.findById(id)// find the blog 189 | blog.comments.push(newComment) 190 | blog.save() // save update to database 191 | res.status(202).json(blog) 192 | 193 | } catch (error) { 194 | console.log(error) 195 | res.status(400).json({ 196 | msg: 'Id not found' 197 | }) 198 | } 199 | 200 | }) 201 | 202 | 203 | module.exports = router --------------------------------------------------------------------------------