import express from 'express'; import path from 'path'; import { fileURLToPath } from 'url'; import mysql from 'mysql2/promise'; import cors from 'cors'; import dotenv from 'dotenv'; dotenv.config(); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const app = express(); const PORT = process.env.PORT || 3000; app.use(cors()); app.use(express.json()); app.use(express.static(path.join(__dirname, 'dist'))); // DB Configuration for internal MySQL const dbConfig = { host: process.env.DB_HOST || 'localhost', user: process.env.DB_USER || 'root', password: process.env.DB_PASSWORD || 'password', database: process.env.DB_NAME || 'email_templates', port: process.env.DB_PORT || 3306, waitForConnections: true, connectionLimit: 10, queueLimit: 0 }; // Debug Log: Print config to console (masking password) console.log('--- Database Configuration ---'); console.log(`Host: ${dbConfig.host}`); console.log(`User: ${dbConfig.user}`); console.log(`Database: ${dbConfig.database}`); console.log(`Port: ${dbConfig.port}`); console.log(`Password: ${dbConfig.password ? '******' : '(Not Set)'}`); console.log('------------------------------'); let pool; // Initialize DB Connection const initDB = async () => { try { pool = mysql.createPool(dbConfig); // Test connection const connection = await pool.getConnection(); console.log('Connected to MySQL database successfully.'); connection.release(); // Create table for MySQL await pool.query(` CREATE TABLE IF NOT EXISTS email_templates ( id VARCHAR(255) PRIMARY KEY, template_key VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, subject VARCHAR(255), header_html TEXT, body_html TEXT, footer_html TEXT, full_html TEXT, required_variables JSON, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); `); console.log('Email templates table ready.'); } catch (err) { console.error('Database initialization failed:', err); process.exit(1); } }; initDB(); // API Routes // GET All Templates app.get('/api/templates', async (req, res) => { try { const [rows] = await pool.query('SELECT * FROM email_templates ORDER BY updated_at DESC'); // Map DB fields back to frontend types const templates = rows.map(row => ({ id: row.id, name: row.name, description: row.description, subject: row.subject, header: row.header_html, body: row.body_html, footer: row.footer_html, variables: typeof row.required_variables === 'string' ? JSON.parse(row.required_variables) : row.required_variables, updatedAt: row.updated_at })); res.json(templates); } catch (err) { console.error(err); res.status(500).json({ error: 'Failed to fetch templates' }); } }); // SAVE (Upsert) Template app.post('/api/templates', async (req, res) => { const t = req.body; // Ensure default values to prevent undefined errors const header = t.header || ''; const body = t.body || ''; const footer = t.footer || ''; const fullHtml = `${header}${body}${footer}`; const templateKey = (t.name || '').trim().toLowerCase().replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, ''); const variablesJson = JSON.stringify(t.variables || []); const params = [ t.id, templateKey, t.name, t.description || '', t.subject || '', header, body, footer, fullHtml, variablesJson ]; try { const query = ` INSERT INTO email_templates (id, template_key, name, description, subject, header_html, body_html, footer_html, full_html, required_variables, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE template_key = VALUES(template_key), name = VALUES(name), description = VALUES(description), subject = VALUES(subject), header_html = VALUES(header_html), body_html = VALUES(body_html), footer_html = VALUES(footer_html), full_html = VALUES(full_html), required_variables = VALUES(required_variables), updated_at = NOW(); `; await pool.query(query, params); res.json({ success: true }); } catch (err) { console.error("Save Template Error:", err); // Return specific error details to help debugging on the client res.status(500).json({ error: 'Failed to save template', details: err.message }); } }); // DELETE Template app.delete('/api/templates/:id', async (req, res) => { try { await pool.query('DELETE FROM email_templates WHERE id = ?', [req.params.id]); res.json({ success: true }); } catch (err) { console.error(err); res.status(500).json({ error: 'Failed to delete template' }); } }); // Handle React Routing app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'dist', 'index.html')); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });