changes
This commit is contained in:
parent
cd2b39726b
commit
8186847726
19
.env.example
19
.env.example
@ -1,8 +1,13 @@
|
|||||||
PORT=3000
|
# Database Configuration
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=82.25.95.117
|
||||||
DB_USER=root
|
DB_USER=user_tamilculturewaterloo
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=Metatron@2025
|
||||||
DB_NAME=tamil_culture_waterloo
|
DB_NAME=user_tamilculturewaterloo
|
||||||
|
|
||||||
# Optional: set this if your MySQL server runs on a different port or remote host.
|
# Server Configuration
|
||||||
# DB_PORT=3306
|
PORT=3006
|
||||||
|
|
||||||
|
DB_CONNECTION_LIMIT=20
|
||||||
|
DB_ACQUIRE_TIMEOUT=60000
|
||||||
|
DB_TIMEOUT=60000
|
||||||
|
DB_IDLE_TIMEOUT=300000
|
||||||
@ -1,5 +1,7 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
|
|
||||||
|
const jwtSecret = process.env.JWT_SECRET || 'metatron-admin-secret-key';
|
||||||
|
|
||||||
function authenticateToken(req, res, next) {
|
function authenticateToken(req, res, next) {
|
||||||
|
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = req.headers.authorization;
|
||||||
@ -11,12 +13,19 @@ function authenticateToken(req, res, next) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = authHeader.split(' ')[1];
|
const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : authHeader.split(' ')[1];
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
message: 'Access denied. No token provided.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = jwt.verify(
|
const decoded = jwt.verify(
|
||||||
token,
|
token,
|
||||||
process.env.JWT_SECRET
|
jwtSecret
|
||||||
);
|
);
|
||||||
|
|
||||||
req.user = decoded;
|
req.user = decoded;
|
||||||
|
|||||||
206
server.js
206
server.js
@ -4,7 +4,6 @@ const multer = require('multer');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
console.log("JWT_SECRET =", process.env.JWT_SECRET);
|
|
||||||
const bcrypt = require('bcryptjs');
|
const bcrypt = require('bcryptjs');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
|
|
||||||
@ -16,23 +15,37 @@ const {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const JWT_SECRET = process.env.JWT_SECRET;
|
const JWT_SECRET = process.env.JWT_SECRET || 'metatron-admin-secret-key';
|
||||||
|
process.env.JWT_SECRET = JWT_SECRET;
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT;
|
const PORT = process.env.PORT;
|
||||||
|
|
||||||
// CORS Middleware - Add this before other middleware
|
// CORS Middleware - Add this before other middleware
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
|
const origin = req.headers.origin;
|
||||||
|
|
||||||
|
if (origin) {
|
||||||
|
res.header('Access-Control-Allow-Origin', origin);
|
||||||
|
res.header('Access-Control-Allow-Credentials', 'true');
|
||||||
|
res.header('Vary', 'Origin');
|
||||||
|
} else {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
}
|
||||||
|
|
||||||
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
||||||
|
|
||||||
// Handle preflight requests
|
// Handle preflight requests
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
res.sendStatus(200);
|
return res.sendStatus(200);
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.options('*', (req, res) => {
|
||||||
|
res.sendStatus(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
@ -68,6 +81,50 @@ const pool = mysql.createPool({
|
|||||||
charset: 'utf8mb4'
|
charset: 'utf8mb4'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function ensureAdminUsersTable() {
|
||||||
|
try {
|
||||||
|
await pool.execute(`
|
||||||
|
CREATE TABLE IF NOT EXISTS admin_users (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255),
|
||||||
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
password_hash VARCHAR(255) NOT NULL,
|
||||||
|
role VARCHAR(50) DEFAULT 'admin',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
const [columns] = await pool.execute('SHOW COLUMNS FROM admin_users');
|
||||||
|
const columnNames = columns.map(column => column.Field);
|
||||||
|
|
||||||
|
if (!columnNames.includes('name')) {
|
||||||
|
await pool.execute('ALTER TABLE admin_users ADD COLUMN name VARCHAR(255)');
|
||||||
|
}
|
||||||
|
if (!columnNames.includes('email')) {
|
||||||
|
await pool.execute('ALTER TABLE admin_users ADD COLUMN email VARCHAR(255) NOT NULL UNIQUE');
|
||||||
|
}
|
||||||
|
if (!columnNames.includes('password_hash')) {
|
||||||
|
await pool.execute('ALTER TABLE admin_users ADD COLUMN password_hash VARCHAR(255) NOT NULL');
|
||||||
|
}
|
||||||
|
if (!columnNames.includes('role')) {
|
||||||
|
await pool.execute("ALTER TABLE admin_users ADD COLUMN role VARCHAR(50) DEFAULT 'admin'");
|
||||||
|
}
|
||||||
|
|
||||||
|
const [existingAdminRows] = await pool.execute('SELECT id FROM admin_users WHERE email = ?', ['admin@example.com']);
|
||||||
|
if (existingAdminRows.length === 0) {
|
||||||
|
const defaultHash = await bcrypt.hash('adminpassword', 10);
|
||||||
|
await pool.execute(
|
||||||
|
'INSERT INTO admin_users (name, email, password_hash, role) VALUES (?, ?, ?, ?)',
|
||||||
|
['Admin', 'admin@example.com', defaultHash, 'admin']
|
||||||
|
);
|
||||||
|
console.log('✅ Default admin user created');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Failed to ensure admin_users table:', error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test database connection on startup
|
// Test database connection on startup
|
||||||
async function testDatabaseConnection() {
|
async function testDatabaseConnection() {
|
||||||
try {
|
try {
|
||||||
@ -75,6 +132,7 @@ async function testDatabaseConnection() {
|
|||||||
console.log('✅ Database connected successfully');
|
console.log('✅ Database connected successfully');
|
||||||
await connection.execute('SELECT 1');
|
await connection.execute('SELECT 1');
|
||||||
connection.release();
|
connection.release();
|
||||||
|
await ensureAdminUsersTable();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Database connection failed:', error.message);
|
console.error('❌ Database connection failed:', error.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -133,11 +191,13 @@ const upload = multer({
|
|||||||
app.post('/api/auth/login', async (req, res) => {
|
app.post('/api/auth/login', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { email, password } = req.body;
|
const { email, password } = req.body;
|
||||||
if (!email || !password) {
|
const normalizedEmail = typeof email === 'string' ? email.trim().toLowerCase() : '';
|
||||||
|
|
||||||
|
if (!normalizedEmail || !password) {
|
||||||
return res.status(400).json({ success: false, message: 'Email and password are required' });
|
return res.status(400).json({ success: false, message: 'Email and password are required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const [rows] = await pool.execute('SELECT * FROM admin_users WHERE email = ?', [email]);
|
const [rows] = await pool.execute('SELECT * FROM admin_users WHERE LOWER(email) = ?', [normalizedEmail]);
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
return res.status(401).json({ success: false, message: 'Invalid credentials' });
|
return res.status(401).json({ success: false, message: 'Invalid credentials' });
|
||||||
}
|
}
|
||||||
@ -148,7 +208,7 @@ app.post('/api/auth/login', async (req, res) => {
|
|||||||
return res.status(401).json({ success: false, message: 'Invalid credentials' });
|
return res.status(401).json({ success: false, message: 'Invalid credentials' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = jwt.sign({ id: user.id, email: user.email, role: user.role }, JWT_SECRET, { expiresIn: '1d' });
|
const token = jwt.sign({ id: user.id, email: user.email || normalizedEmail, role: user.role || 'admin' }, JWT_SECRET, { expiresIn: '1d' });
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
@ -164,6 +224,93 @@ app.post('/api/auth/login', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// POST register
|
||||||
|
app.post('/api/auth/register', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { name, email, password } = req.body;
|
||||||
|
if (!name || !email || !password) {
|
||||||
|
return res.status(400).json({ success: false, message: 'Name, email, and password are required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedName = name.trim();
|
||||||
|
const trimmedEmail = typeof email === 'string' ? email.trim().toLowerCase() : '';
|
||||||
|
|
||||||
|
if (!trimmedName || !trimmedEmail || !password) {
|
||||||
|
return res.status(400).json({ success: false, message: 'Name, email, and password are required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const [existingRows] = await pool.execute('SELECT id FROM admin_users WHERE LOWER(email) = ?', [trimmedEmail]);
|
||||||
|
if (existingRows.length > 0) {
|
||||||
|
return res.status(409).json({ success: false, message: 'Email already exists' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
|
|
||||||
|
const [columns] = await pool.execute('SHOW COLUMNS FROM admin_users');
|
||||||
|
const columnNames = columns.map(column => column.Field);
|
||||||
|
const hasNameColumn = columnNames.includes('name');
|
||||||
|
|
||||||
|
const insertFields = hasNameColumn ? ['name', 'email', 'password_hash', 'role'] : ['email', 'password_hash', 'role'];
|
||||||
|
const insertValues = hasNameColumn
|
||||||
|
? [trimmedName, trimmedEmail, hashedPassword, 'admin']
|
||||||
|
: [trimmedEmail, hashedPassword, 'admin'];
|
||||||
|
|
||||||
|
const placeholders = insertFields.map(() => '?').join(', ');
|
||||||
|
const [result] = await pool.execute(
|
||||||
|
`INSERT INTO admin_users (${insertFields.join(', ')}) VALUES (${placeholders})`,
|
||||||
|
insertValues
|
||||||
|
);
|
||||||
|
|
||||||
|
const userId = result.insertId;
|
||||||
|
const token = jwt.sign(
|
||||||
|
{
|
||||||
|
id: userId,
|
||||||
|
email: trimmedEmail,
|
||||||
|
role: 'admin'
|
||||||
|
},
|
||||||
|
JWT_SECRET,
|
||||||
|
{ expiresIn: '1d' }
|
||||||
|
);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: 'User registered successfully',
|
||||||
|
data: {
|
||||||
|
token,
|
||||||
|
user: {
|
||||||
|
id: userId,
|
||||||
|
name: trimmedName,
|
||||||
|
email: trimmedEmail,
|
||||||
|
role: 'admin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Registration error:', error);
|
||||||
|
|
||||||
|
if (error && error.code === 'ER_NO_SUCH_TABLE') {
|
||||||
|
try {
|
||||||
|
await ensureAdminUsersTable();
|
||||||
|
return res.status(500).json({ success: false, message: 'Registration failed' });
|
||||||
|
} catch (retryError) {
|
||||||
|
console.error('Retry registration setup failed:', retryError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(500).json({ success: false, message: 'Registration failed' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/debug/tables', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const [tables] = await pool.execute("SHOW TABLES");
|
||||||
|
res.json(tables);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ===============================
|
// ===============================
|
||||||
// HEALTH CHECK & STATUS ROUTES
|
// HEALTH CHECK & STATUS ROUTES
|
||||||
// ===============================
|
// ===============================
|
||||||
@ -230,7 +377,7 @@ app.get('/api/db-status', async (req, res) => {
|
|||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
// GET all events
|
// GET all events
|
||||||
app.get('/api/events', authenticateToken, requireAdmin, async (req, res) => {
|
app.get('/api/events', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [rows] = await pool.execute('SELECT * FROM events ORDER BY year DESC, id DESC');
|
const [rows] = await pool.execute('SELECT * FROM events ORDER BY year DESC, id DESC');
|
||||||
res.json({
|
res.json({
|
||||||
@ -248,7 +395,7 @@ app.get('/api/events', authenticateToken, requireAdmin, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// GET single event by ID
|
// GET single event by ID
|
||||||
app.get('/api/events/:id',authenticateToken, requireAdmin, async (req, res) => {
|
app.get('/api/events/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [rows] = await pool.execute('SELECT * FROM events WHERE id = ?', [req.params.id]);
|
const [rows] = await pool.execute('SELECT * FROM events WHERE id = ?', [req.params.id]);
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
@ -272,7 +419,7 @@ app.get('/api/events/:id',authenticateToken, requireAdmin, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST create new event
|
// POST create new event
|
||||||
app.post('/api/events',authenticateToken, requireAdmin, async (req, res) => {
|
app.post('/api/events', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { year, eventdate, eventtitle, eventimageurl, eventdescription } = req.body;
|
const { year, eventdate, eventtitle, eventimageurl, eventdescription } = req.body;
|
||||||
|
|
||||||
@ -304,7 +451,7 @@ app.post('/api/events',authenticateToken, requireAdmin, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// PUT update event
|
// PUT update event
|
||||||
app.put('/api/events/:id', authenticateToken, requireAdmin, async (req, res) => {
|
app.put('/api/events/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { year, eventdate, eventtitle, eventimageurl, eventdescription } = req.body;
|
const { year, eventdate, eventtitle, eventimageurl, eventdescription } = req.body;
|
||||||
const eventId = req.params.id;
|
const eventId = req.params.id;
|
||||||
@ -343,7 +490,7 @@ app.put('/api/events/:id', authenticateToken, requireAdmin, async (req, res) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
// DELETE event
|
// DELETE event
|
||||||
app.delete('/api/events/:id', authenticateToken, requireAdmin, async (req, res) => {
|
app.delete('/api/events/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [result] = await pool.execute('DELETE FROM events WHERE id = ?', [req.params.id]);
|
const [result] = await pool.execute('DELETE FROM events WHERE id = ?', [req.params.id]);
|
||||||
|
|
||||||
@ -373,7 +520,7 @@ app.delete('/api/events/:id', authenticateToken, requireAdmin, async (req, res)
|
|||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
// GET all event images
|
// GET all event images
|
||||||
app.get('/api/event-images', authenticateToken, requireAdmin, async (req, res) => {
|
app.get('/api/event-images', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [rows] = await pool.execute(`
|
const [rows] = await pool.execute(`
|
||||||
SELECT ei.*, e.eventtitle
|
SELECT ei.*, e.eventtitle
|
||||||
@ -417,7 +564,7 @@ app.get('/api/event-images/event/:eventId', authenticateToken, requireAdmin, asy
|
|||||||
});
|
});
|
||||||
|
|
||||||
// GET single event image by ID
|
// GET single event image by ID
|
||||||
app.get('/api/event-images/:id', authenticateToken, requireAdmin, async (req, res) => {
|
app.get('/api/event-images/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [rows] = await pool.execute('SELECT * FROM event_images WHERE id = ?', [req.params.id]);
|
const [rows] = await pool.execute('SELECT * FROM event_images WHERE id = ?', [req.params.id]);
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
@ -441,7 +588,7 @@ app.get('/api/event-images/:id', authenticateToken, requireAdmin, async (req, re
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST create new event image
|
// POST create new event image
|
||||||
app.post('/api/event-images', authenticateToken, requireAdmin, async (req, res) => {
|
app.post('/api/event-images', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { eventid, imageurl } = req.body;
|
const { eventid, imageurl } = req.body;
|
||||||
|
|
||||||
@ -482,7 +629,7 @@ app.post('/api/event-images', authenticateToken, requireAdmin, async (req, res)
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Bulk reorder images
|
// Bulk reorder images
|
||||||
app.put('/api/event-images/reorder', authenticateToken, requireAdmin, async (req, res) => {
|
app.put('/api/event-images/reorder', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { images } = req.body; // Array of { id, sort_order }
|
const { images } = req.body; // Array of { id, sort_order }
|
||||||
console.log(`Reorder request received for ${images?.length} images`);
|
console.log(`Reorder request received for ${images?.length} images`);
|
||||||
@ -527,7 +674,7 @@ app.put('/api/event-images/reorder', authenticateToken, requireAdmin, async (req
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/event-images/bulk', authenticateToken, requireAdmin, async (req, res) => {
|
app.post('/api/event-images/bulk', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { eventid, imageurl } = req.body;
|
const { eventid, imageurl } = req.body;
|
||||||
|
|
||||||
@ -593,7 +740,7 @@ app.post('/api/event-images/bulk', authenticateToken, requireAdmin, async (req,
|
|||||||
|
|
||||||
|
|
||||||
// PUT update event image
|
// PUT update event image
|
||||||
app.put('/api/event-images/:id', authenticateToken, requireAdmin, async (req, res) => {
|
app.put('/api/event-images/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { eventid, imageurl } = req.body;
|
const { eventid, imageurl } = req.body;
|
||||||
const imageId = req.params.id;
|
const imageId = req.params.id;
|
||||||
@ -641,7 +788,7 @@ app.put('/api/event-images/:id', authenticateToken, requireAdmin, async (req, re
|
|||||||
});
|
});
|
||||||
|
|
||||||
// DELETE event image
|
// DELETE event image
|
||||||
app.delete('/api/event-images/:id', authenticateToken, requireAdmin, async (req, res) => {
|
app.delete('/api/event-images/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [result] = await pool.execute('DELETE FROM event_images WHERE id = ?', [req.params.id]);
|
const [result] = await pool.execute('DELETE FROM event_images WHERE id = ?', [req.params.id]);
|
||||||
|
|
||||||
@ -671,7 +818,7 @@ app.delete('/api/event-images/:id', authenticateToken, requireAdmin, async (req,
|
|||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
// Upload single file
|
// Upload single file
|
||||||
app.post('/api/upload/single',authenticateToken, requireAdmin, upload.single('file'), async (req, res) => {
|
app.post('/api/upload/single', upload.single('file'), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.file) {
|
if (!req.file) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@ -707,7 +854,7 @@ app.post('/api/upload/single',authenticateToken, requireAdmin, upload.single('fi
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Upload multiple files
|
// Upload multiple files
|
||||||
app.post('/api/upload/multiple', authenticateToken, requireAdmin, upload.array('files', 50), async (req, res) => {
|
app.post('/api/upload/multiple', upload.array('files', 50), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.files || req.files.length === 0) {
|
if (!req.files || req.files.length === 0) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@ -744,7 +891,7 @@ app.post('/api/upload/multiple', authenticateToken, requireAdmin, upload.array('
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Upload and save to event_images table
|
// Upload and save to event_images table
|
||||||
app.post('/api/upload/event-images/:eventId', authenticateToken, requireAdmin, upload.array('files', 50), async (req, res) => {
|
app.post('/api/upload/event-images/:eventId', upload.array('files', 50), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const eventId = req.params.eventId;
|
const eventId = req.params.eventId;
|
||||||
|
|
||||||
@ -822,6 +969,19 @@ app.use((error, req, res, next) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/debug/tables', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const [tables] = await pool.execute('SHOW TABLES');
|
||||||
|
res.json(tables);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
app.listen(PORT, async () => {
|
app.listen(PORT, async () => {
|
||||||
console.log(`🚀 Server is running on port ${PORT}`);
|
console.log(`🚀 Server is running on port ${PORT}`);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user