server/routes/static.js (/, /index.html, /index-editorial.html, /favicon.ico, /lia), server/routes/search.js (/api/search, /api/visitors), server/routes/feedback.js (/api/feedback OPTIONS/POST/GET). Verified via node --check, eslint no-undef (only the 3 known pre-existing bugs remain, no new ones), and smoke-test harness (28/28 match). server.js: 3714 -> 3556 lines.
71 lines
2.8 KiB
JavaScript
71 lines
2.8 KiB
JavaScript
const fs = require("fs");
|
|
const { sendFeedbackMail } = require("../../src/backend/services/smtp");
|
|
|
|
const FEEDBACK_TOKEN = process.env.FEEDBACK_TOKEN || "changeme-set-in-env";
|
|
const FEEDBACK_FILE = "/opt/peercortex-app/feedback.json";
|
|
|
|
function handleOptions(req, res) {
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
res.writeHead(204);
|
|
return res.end();
|
|
}
|
|
|
|
// POST /api/feedback — submit feedback entry
|
|
function handlePost(req, res) {
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
let body = '';
|
|
req.on('data', function(chunk) { body += chunk; });
|
|
req.on('end', function() {
|
|
try {
|
|
const data = JSON.parse(body);
|
|
if (!data.message || String(data.message).trim().length < 3) {
|
|
res.writeHead(400);
|
|
return res.end(JSON.stringify({ ok: false, error: 'Message too short' }));
|
|
}
|
|
const entry = {
|
|
id: Date.now() + '-' + Math.random().toString(36).slice(2, 7),
|
|
timestamp: new Date().toISOString(),
|
|
category: String(data.category || 'General').slice(0, 50),
|
|
message: String(data.message || '').slice(0, 2000),
|
|
name: String(data.name || 'Anonymous').slice(0, 100),
|
|
asn: data.asn ? String(data.asn).slice(0, 20) : null,
|
|
ip: req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.socket.remoteAddress || null,
|
|
ua: String(req.headers['user-agent'] || '').slice(0, 200)
|
|
};
|
|
let entries = [];
|
|
try { entries = JSON.parse(fs.readFileSync(FEEDBACK_FILE, 'utf8')); } catch (_e) { /* no file yet */ }
|
|
entries.push(entry);
|
|
fs.writeFileSync(FEEDBACK_FILE, JSON.stringify(entries, null, 2));
|
|
// Send email async — don't block response
|
|
sendFeedbackMail(entry).catch(e => console.error('[MAIL] Failed:', e.message));
|
|
return res.end(JSON.stringify({ ok: true, id: entry.id }));
|
|
} catch (_e) {
|
|
res.writeHead(500);
|
|
return res.end(JSON.stringify({ ok: false, error: 'Server error' }));
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
// GET /api/feedback?token=... — admin: fetch all entries as JSON
|
|
function handleGet(req, res, url) {
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
const token = url.searchParams.get('token');
|
|
if (!token || token !== FEEDBACK_TOKEN) {
|
|
res.writeHead(401);
|
|
return res.end(JSON.stringify({ ok: false, error: 'Unauthorized' }));
|
|
}
|
|
try {
|
|
const entries = JSON.parse(fs.readFileSync(FEEDBACK_FILE, 'utf8'));
|
|
return res.end(JSON.stringify({ ok: true, entries: entries, count: entries.length }));
|
|
} catch (_e) {
|
|
return res.end(JSON.stringify({ ok: true, entries: [], count: 0 }));
|
|
}
|
|
}
|
|
|
|
module.exports = { handleOptions, handlePost, handleGet };
|