diff --git a/.env.example b/.env.example index 7fda342..02cf8e0 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ PORT=3000 DB_HOST=127.0.0.1 DB_USER=root -DB_PASSWORD=your_mysql_password +DB_PASSWORD= DB_NAME=tamil_culture_waterloo # Optional: set this if your MySQL server runs on a different port or remote host. diff --git a/middleware/auth.js b/middleware/auth.js new file mode 100644 index 0000000..11e4c5e --- /dev/null +++ b/middleware/auth.js @@ -0,0 +1,49 @@ +const jwt = require('jsonwebtoken'); + +function authenticateToken(req, res, next) { + + const authHeader = req.headers.authorization; + + if (!authHeader) { + return res.status(401).json({ + success: false, + message: 'Access denied. No token provided.' + }); + } + + const token = authHeader.split(' ')[1]; + + try { + const decoded = jwt.verify( + token, + process.env.JWT_SECRET + ); + + req.user = decoded; + + next(); + + } catch (err) { + + return res.status(403).json({ + success: false, + message: 'Invalid token.' + }); + + } +} +function requireAdmin(req, res, next) { + + if (req.user.role !== 'admin') { + return res.status(403).json({ + success: false, + message: 'Admin access required' + }); + } + + next(); +} + +module.exports = { authenticateToken, requireAdmin }; + + diff --git a/server.js b/server.js index 04444c8..dbdf24d 100644 --- a/server.js +++ b/server.js @@ -4,13 +4,22 @@ const multer = require('multer'); const path = require('path'); const fs = require('fs'); require('dotenv').config(); - +console.log("JWT_SECRET =", process.env.JWT_SECRET); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); -const JWT_SECRET = process.env.JWT_SECRET || 'supersecret_default_key_change_me_in_production'; + + +const { + authenticateToken, + requireAdmin +} = require('./middleware/auth'); + + + +const JWT_SECRET = process.env.JWT_SECRET; const app = express(); -const PORT = process.env.PORT || 3000; +const PORT = process.env.PORT; // CORS Middleware - Add this before other middleware app.use((req, res, next) => { @@ -221,7 +230,7 @@ app.get('/api/db-status', async (req, res) => { // =============================== // GET all events -app.get('/api/events', async (req, res) => { +app.get('/api/events', authenticateToken, requireAdmin, async (req, res) => { try { const [rows] = await pool.execute('SELECT * FROM events ORDER BY year DESC, id DESC'); res.json({ @@ -239,7 +248,7 @@ app.get('/api/events', async (req, res) => { }); // GET single event by ID -app.get('/api/events/:id', async (req, res) => { +app.get('/api/events/:id',authenticateToken, requireAdmin, async (req, res) => { try { const [rows] = await pool.execute('SELECT * FROM events WHERE id = ?', [req.params.id]); if (rows.length === 0) { @@ -263,7 +272,7 @@ app.get('/api/events/:id', async (req, res) => { }); // POST create new event -app.post('/api/events', async (req, res) => { +app.post('/api/events',authenticateToken, requireAdmin, async (req, res) => { try { const { year, eventdate, eventtitle, eventimageurl, eventdescription } = req.body; @@ -295,7 +304,7 @@ app.post('/api/events', async (req, res) => { }); // PUT update event -app.put('/api/events/:id', async (req, res) => { +app.put('/api/events/:id', authenticateToken, requireAdmin, async (req, res) => { try { const { year, eventdate, eventtitle, eventimageurl, eventdescription } = req.body; const eventId = req.params.id; @@ -334,7 +343,7 @@ app.put('/api/events/:id', async (req, res) => { }); // DELETE event -app.delete('/api/events/:id', async (req, res) => { +app.delete('/api/events/:id', authenticateToken, requireAdmin, async (req, res) => { try { const [result] = await pool.execute('DELETE FROM events WHERE id = ?', [req.params.id]); @@ -364,7 +373,7 @@ app.delete('/api/events/:id', async (req, res) => { // =============================== // GET all event images -app.get('/api/event-images', async (req, res) => { +app.get('/api/event-images', authenticateToken, requireAdmin, async (req, res) => { try { const [rows] = await pool.execute(` SELECT ei.*, e.eventtitle @@ -387,7 +396,7 @@ app.get('/api/event-images', async (req, res) => { }); // GET event images by event ID -app.get('/api/event-images/event/:eventId', async (req, res) => { +app.get('/api/event-images/event/:eventId', authenticateToken, requireAdmin, async (req, res) => { try { const [rows] = await pool.execute( 'SELECT * FROM event_images WHERE eventid = ? ORDER BY sort_order ASC, id ASC', @@ -408,7 +417,7 @@ app.get('/api/event-images/event/:eventId', async (req, res) => { }); // GET single event image by ID -app.get('/api/event-images/:id', async (req, res) => { +app.get('/api/event-images/:id', authenticateToken, requireAdmin, async (req, res) => { try { const [rows] = await pool.execute('SELECT * FROM event_images WHERE id = ?', [req.params.id]); if (rows.length === 0) { @@ -432,7 +441,7 @@ app.get('/api/event-images/:id', async (req, res) => { }); // POST create new event image -app.post('/api/event-images', async (req, res) => { +app.post('/api/event-images', authenticateToken, requireAdmin, async (req, res) => { try { const { eventid, imageurl } = req.body; @@ -473,7 +482,7 @@ app.post('/api/event-images', async (req, res) => { }); // Bulk reorder images -app.put('/api/event-images/reorder', async (req, res) => { +app.put('/api/event-images/reorder', authenticateToken, requireAdmin, async (req, res) => { try { const { images } = req.body; // Array of { id, sort_order } console.log(`Reorder request received for ${images?.length} images`); @@ -518,7 +527,7 @@ app.put('/api/event-images/reorder', async (req, res) => { } }); -app.post('/api/event-images/bulk', async (req, res) => { +app.post('/api/event-images/bulk', authenticateToken, requireAdmin, async (req, res) => { try { const { eventid, imageurl } = req.body; @@ -584,7 +593,7 @@ app.post('/api/event-images/bulk', async (req, res) => { // PUT update event image -app.put('/api/event-images/:id', async (req, res) => { +app.put('/api/event-images/:id', authenticateToken, requireAdmin, async (req, res) => { try { const { eventid, imageurl } = req.body; const imageId = req.params.id; @@ -632,7 +641,7 @@ app.put('/api/event-images/:id', async (req, res) => { }); // DELETE event image -app.delete('/api/event-images/:id', async (req, res) => { +app.delete('/api/event-images/:id', authenticateToken, requireAdmin, async (req, res) => { try { const [result] = await pool.execute('DELETE FROM event_images WHERE id = ?', [req.params.id]); @@ -662,7 +671,7 @@ app.delete('/api/event-images/:id', async (req, res) => { // =============================== // Upload single file -app.post('/api/upload/single', upload.single('file'), async (req, res) => { +app.post('/api/upload/single',authenticateToken, requireAdmin, upload.single('file'), async (req, res) => { try { if (!req.file) { return res.status(400).json({ @@ -698,7 +707,7 @@ app.post('/api/upload/single', upload.single('file'), async (req, res) => { }); // Upload multiple files -app.post('/api/upload/multiple', upload.array('files', 50), async (req, res) => { +app.post('/api/upload/multiple', authenticateToken, requireAdmin, upload.array('files', 50), async (req, res) => { try { if (!req.files || req.files.length === 0) { return res.status(400).json({ @@ -735,7 +744,7 @@ app.post('/api/upload/multiple', upload.array('files', 50), async (req, res) => }); // Upload and save to event_images table -app.post('/api/upload/event-images/:eventId', upload.array('files', 50), async (req, res) => { +app.post('/api/upload/event-images/:eventId', authenticateToken, requireAdmin, upload.array('files', 50), async (req, res) => { try { const eventId = req.params.eventId;