cineasthesia-landing/server.js

121 lines
4.4 KiB
JavaScript

const http = require('http');
const fs = require('fs');
const path = require('path');
const nodemailer = require('nodemailer');
const PORT = 80;
const STATIC_DIR = path.join(__dirname, 'public');
const SMTP_HOST = process.env.SMTP_HOST || 'mail.rmail.online';
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '587');
const SMTP_USER = process.env.SMTP_USER;
const SMTP_PASS = process.env.SMTP_PASS;
const SMTP_FROM = process.env.SMTP_FROM || SMTP_USER;
const CONTACT_TO = process.env.CONTACT_TO || 'noire.michelle@gmail.com';
const transporter = nodemailer.createTransport({
host: SMTP_HOST,
port: SMTP_PORT,
secure: false,
auth: { user: SMTP_USER, pass: SMTP_PASS },
tls: { rejectUnauthorized: false }
});
const MIME = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon',
'.webp': 'image/webp',
'.woff2': 'font/woff2',
'.woff': 'font/woff',
};
function serveStatic(req, res) {
let filePath = path.join(STATIC_DIR, req.url === '/' ? 'index.html' : req.url);
filePath = path.normalize(filePath);
if (!filePath.startsWith(STATIC_DIR)) {
res.writeHead(403);
res.end();
return;
}
const ext = path.extname(filePath).toLowerCase();
const contentType = MIME[ext] || 'application/octet-stream';
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not found');
return;
}
res.writeHead(200, {
'Content-Type': contentType,
'Cache-Control': ext === '.html' ? 'no-cache' : 'public, max-age=86400'
});
res.end(data);
});
}
function handleContact(req, res) {
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end', async () => {
try {
const { name, email, subject, message } = JSON.parse(body);
if (!name || !email || !message) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Name, email, and message are required' }));
return;
}
await transporter.sendMail({
from: `"Cineasthesia Contact" <${SMTP_FROM}>`,
replyTo: `"${name}" <${email}>`,
to: CONTACT_TO,
subject: `[Cineasthesia] ${subject || 'Contact Form Message'}`,
text: `Name: ${name}\nEmail: ${email}\nSubject: ${subject || '(none)'}\n\nMessage:\n${message}`,
html: `
<div style="font-family: sans-serif; max-width: 600px;">
<h2 style="color: #3C2415; border-bottom: 2px solid #C68B3F; padding-bottom: 8px;">New Contact Form Message</h2>
<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> <a href="mailto:${email}">${email}</a></p>
<p><strong>Subject:</strong> ${subject || '(none)'}</p>
<hr style="border: none; border-top: 1px solid #E8DBC8; margin: 16px 0;">
<p style="white-space: pre-wrap;">${message}</p>
<hr style="border: none; border-top: 1px solid #E8DBC8; margin: 16px 0;">
<p style="font-size: 12px; color: #7a6f64;">Sent from cineasthesia.com contact form</p>
</div>
`
});
console.log(`Contact form sent: ${name} <${email}> — ${subject || '(no subject)'}`);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ ok: true }));
} catch (err) {
console.error('Contact form error:', err.message);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Failed to send message' }));
}
});
}
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/api/contact') {
handleContact(req, res);
} else {
serveStatic(req, res);
}
});
server.listen(PORT, () => {
console.log(`Cineasthesia server running on port ${PORT}`);
console.log(`Contact emails → ${CONTACT_TO}`);
});