This project is a personal blog website created to document my Software Engineering journey. It features an admin dashboard for managing posts, user authentication, and a responsive design. The blog allows me to share insights, record my learning path, and provide valuable content related to software development and programming.
Features:
- Home Page: Displays recent blog posts and provides navigation links.
- Admin Dashboard: Accessible only after login, it allows managing blog posts with options to create, edit, and delete posts.
- User Authentication: Includes admin login functionality with middleware for checking authentication on protected routes.
- Post Management: Functionality to create new posts, edit existing posts, and delete posts.
- Search Functionality: Allows searching posts by title and body content.
- Responsive Design: Ensures the blog is accessible and usable on various devices with different screen sizes.
- Styled Components: Utilizes custom fonts, colors, and styled buttons and forms for a consistent and attractive appearance.****
BLOG
├── node_modules
├── public
│ ├── css
│ │ └── style.css
│ ├── img
│ │ ├── articles.gif
│ │ ├── blog.png
│ │ ├── blog1.gif
│ │ ├── close.png
│ │ ├── Home.gif
│ │ ├── plus.png
│ │ ├── Search.gif
│ │ └── signout.gif
│ └── js
│ └── script.js
├── server
│ ├── config
│ ├── helpers
│ ├── models
│ └── routes
├── views
│ ├── admin
│ │ ├── add-post.ejs
│ │ ├── dashboard.ejs
│ │ ├── edit-post.ejs
│ │ └── index.ejs
│ ├── layouts
│ │ ├── admin.ejs
│ │ └── main.ejs
│ ├── partials
│ │ ├── footer.ejs
│ │ ├── header_admin.ejs
│ │ ├── header.ejs
│ │ └── search.ejs
│ ├── about.ejs
│ ├── index.ejs
│ ├── post.ejs
│ └── search.ejs
├── .env
├── .gitignore
├── app.js
├── package-lock.json
└── package.json
- The
authMiddleware
function is a crucial part of the application, ensuring that only authenticated users can access certain routes. This middleware checks for a valid JSON Web Token (JWT) in the request cookies and verifies it before allowing access to protected routes.
- Token Retrieval: The middleware first attempts to retrieve the token from the cookies.
- Token Validation: If a token is found, it is verified using the
jsonwebtoken
library and a secret key. - User Identification: If the token is valid, the middleware decodes the token to extract the user ID and attaches it to the request object.
- Access Control: If no token is found or if the token is invalid, the middleware responds with a 401 Unauthorized status, preventing access to the protected route.
-
const jwt = require('jsonwebtoken'); const jwtSecret = process.env.JWT_SECRET; const authMiddleware = (req, res, next) => { const token = req.cookies.token; if (!token) { return res.status(401).redirect('/unauthorized'); } try { const decoded = jwt.verify(token, jwtSecret); req.userId = decoded.userId; next(); } catch (err) { console.error(err); return res.status(401).redirect('/unauthorized'); } };
- View Recent Posts: The home page displays the most recent blog posts.
- Read a Post: Click on any post title to read the full content.
-
Access the Dashboard: Log in with your admin credentials to access the dashboard.
-
Create a New Post:
-
Steps:
- Navigate to the dashboard.
- Click on the "Add Post" button.
- Fill in the title and content of your new post.
- Click "Submit" to publish the post.
-
Code:
// POST /add-post router.post('/add-post', authMiddleware, async (req, res) => { try { const newPost = new Post({ title: req.body.title, body: req.body.body }); await Post.create(newPost); res.redirect('/dashboard'); } catch (error) { console.log(error); } });
-
-
Edit an Existing Post:
-
Steps:
- In the dashboard, find the post you want to edit.
- Click on the "Edit" button next to the post.
- Update the title and content as needed.
- Click "Update" to save the changes.
-
Code:
// PUT /edit-post/:id router.put('/edit-post/:id', authMiddleware, async (req, res) => { try { await Post.findByIdAndUpdate(req.params.id, { title: req.body.title, body: req.body.body, updatedAt: Date.now() }); res.redirect(`/edit-post/${req.params.id}`); } catch (error) { console.log(error); } });
-
-
Delete a Post:
-
Steps:
- In the dashboard, find the post you want to delete.
- Click on the "Delete" button next to the post.
- Confirm the deletion to remove the post.
-
Code:
// DELETE /delete-post/:id router.delete('/delete-post/:id', authMiddleware, async (req, res) => { try { await Post.deleteOne({ _id: req.params.id }); res.redirect('/dashboard'); } catch (error) { console.log(error); } });
-
- Search for Posts:
-
Steps:
- Use the search bar located at the top of the page.
- Enter keywords related to the post titles or content.
- View the search results that match your query.
-
Code:
// POST /search router.post('/search', async (req, res) => { try { const locals = { title: "Nodejs Blog", description: "Simple blog with Nodejs, express & MongoDB" }; let searchTerm = req.body.searchTerm || ""; // Provide a default value const searchNoSpecialCharacters = searchTerm.replace(/[^a-zA-Z0-9]/g, ""); const data = await Post.find({ $or: [ { title: { $regex: new RegExp(searchNoSpecialCharacters, 'i') } }, { body: { $regex: new RegExp(searchNoSpecialCharacters, 'i') } } ] }); res.render('search', { locals, data, currentRoute: '/search' }); } catch (err) { console.error(err); } });
-
- Admin Login:
-
Steps:
- Go to the admin login page.
- Enter your username and password.
- Click "Login" to access the admin dashboard.
-
Code:
// POST /admin router.post('/admin', async (req, res) => { try { const { username, password } = req.body; const user = await User.findOne({ username }); if (!user) { return res.status(401).json({ message: 'Invalid credentials' }); } const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { return res.status(401).json({ message: 'Invalid credentials' }); } const token = jwt.sign({ userId: user._id }, jwtSecret); res.cookie('token', token, { httpOnly: true }); res.redirect('/dashboard'); } catch (error) { console.log(error); } });
-