const express = require('express'); const https = require('https'); const fs = require('fs'); const path = require('path'); const app = express(); app.use(express.json()); const PORT = parseInt(process.env.PORT || '3060'); const BASE = (process.env.BASE_PATH || '/feedback-tool').replace(/\/$/, ''); const FT_TOKEN = process.env.FT_TOKEN || fs.readFileSync('/root/feedback-tool.env','utf8').match(/FT_TOKEN=(.*)/)?.[1]?.trim(); const GITEA_HOST = '127.0.0.1'; const GITEA_PORT = 3040; // CORS for widget app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type'); res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); if (req.method === 'OPTIONS') return res.sendStatus(200); next(); }); // Serve widget.js — public, no auth app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { const SELF = `https://dev.bl.pixeldev.eu${BASE}`; res.setHeader('Content-Type', 'application/javascript'); res.setHeader('Cache-Control', 'no-cache'); res.send(` (function() { var FEEDBACK_URL = '${SELF}/api/feedback'; var cfg = (function() { var s = document.currentScript || document.querySelector('script[data-repo]'); return { repo: s && s.getAttribute('data-repo'), label: s && s.getAttribute('data-label') || 'Feedback' }; })(); var style = document.createElement('style'); style.textContent = \` #_fb-fab { position:fixed; bottom:1.5rem; right:1.5rem; width:52px; height:52px; border-radius:50%; background:#7c9ef5; color:#fff; font-size:22px; border:none; cursor:pointer; box-shadow:0 4px 16px rgba(0,0,0,.4); z-index:99998; display:flex; align-items:center; justify-content:center; transition:transform .15s; } #_fb-fab:hover { transform:scale(1.1); } #_fb-panel { position:fixed; bottom:5.5rem; right:1.5rem; width:320px; background:#1a1a1a; border:1px solid #333; border-radius:14px; padding:1.2rem; z-index:99999; box-shadow:0 8px 32px rgba(0,0,0,.5); font-family:'Segoe UI',system-ui,sans-serif; display:none; flex-direction:column; gap:.75rem; } #_fb-panel.open { display:flex; } #_fb-panel h3 { color:#fff; font-size:.95rem; margin:0; } #_fb-panel input, #_fb-panel textarea { background:#111; border:1px solid #333; border-radius:6px; padding:.5rem .7rem; color:#e0e0e0; font-size:.85rem; width:100%; font-family:inherit; outline:none; resize:vertical; } #_fb-panel input:focus, #_fb-panel textarea:focus { border-color:#7c9ef5; } #_fb-panel textarea { min-height:80px; } #_fb-submit { background:#7c9ef5; color:#fff; border:none; border-radius:6px; padding:.55rem 1rem; font-size:.85rem; font-weight:600; cursor:pointer; width:100%; transition:opacity .15s; } #_fb-submit:hover { opacity:.85; } #_fb-submit:disabled { opacity:.5; cursor:default; } #_fb-status { font-size:.78rem; text-align:center; min-height:1rem; } #_fb-close { position:absolute; top:.75rem; right:.9rem; background:none; border:none; color:#555; cursor:pointer; font-size:1rem; line-height:1; } #_fb-close:hover { color:#aaa; } \`; document.head.appendChild(style); var fab = document.createElement('button'); fab.id = '_fb-fab'; fab.innerHTML = '💬'; fab.title = 'Feedback'; document.body.appendChild(fab); var panel = document.createElement('div'); panel.id = '_fb-panel'; panel.style.position = 'fixed'; panel.innerHTML = \`