const express = require('express'); const path = require('path'); require('dotenv').config(); const { checkConnection } = require('./src/db'); const q = require('./src/queries'); const app = express(); const PORT = process.env.PORT || 3000; const DEV = process.env.DEV_MODE === 'true'; app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); app.use(express.static(path.join(__dirname, 'public'))); app.use(express.urlencoded({ extended: true })); // ── Auth middleware ── app.use((req, res, next) => { if (DEV) { req.user = { email: 'dev@test.local', clientId: 'WZ01325', companyId: null, companyName: 'DEV' }; return next(); } const auth = req.headers.authorization || ''; try { const payload = JSON.parse(Buffer.from(auth.replace('Bearer ', '').split('.')[1], 'base64').toString()); req.user = { email: payload.email || 'unknown', clientId: payload.ClientID, companyId: payload.company_id, companyName: payload.company_name || payload.ClientID, }; } catch { req.user = {}; } next(); }); // ── Health ── app.get('/healthz', (req, res) => res.send('OK')); // ── Главная ── app.get('/', async (req, res) => { const { clientId, companyName } = req.user; try { const company = await q.getOrCreateCompany(clientId, companyName); const limit = await q.getLimit(company); const entries = await q.listEntries(company.id); res.render('index', { entries, limit, used: entries.length, user: req.user, error: null, message: null, wasNormalized: false }); } catch (e) { res.render('index', { entries: [], limit: 15, used: 0, user: req.user, error: e.message, message: null, wasNormalized: false }); } }); // ── Создать ── app.post('/add', async (req, res) => { const { value, comment } = req.body; const { clientId, companyName, email } = req.user; try { const company = await q.getOrCreateCompany(clientId, companyName); const result = await q.createEntry(company.id, value, comment, email); const limit = await q.getLimit(company); const entries = await q.listEntries(company.id); res.render('index', { entries, limit, used: entries.length, user: req.user, message: result.wasNormalized ? `Адрес нормализован в ${result.entry.value_cidr}` : 'Добавлено', error: null, wasNormalized: result.wasNormalized, }); } catch (e) { const company = await q.getOrCreateCompany(clientId, companyName).catch(() => null); const entries = company ? await q.listEntries(company.id).catch(() => []) : []; const limit = company ? await q.getLimit(company).catch(() => 15) : 15; res.render('index', { entries, limit, used: entries.length, user: req.user, error: e.message, message: null, wasNormalized: false }); } }); // ── Удалить (soft) ── app.post('/delete/:id', async (req, res) => { const { clientId, companyName, email } = req.user; try { const company = await q.getOrCreateCompany(clientId, companyName); await q.deleteEntry(req.params.id, company.id, email); res.redirect('/'); } catch (e) { res.redirect('/?error=' + encodeURIComponent(e.message)); } }); // ── Экспорт ── app.get('/export', async (req, res) => { try { const cidrs = await q.getExportCIDRs(); res.setHeader('Content-Type', 'text/plain; charset=utf-8'); res.send(cidrs.join('\n') + '\n'); } catch (e) { res.status(500).send('Export error'); } }); // ── Старт ── checkConnection() .then(() => console.log('DB connected')) .catch(e => console.error('DB not ready:', e.message)); app.listen(PORT, () => console.log(`Server on port ${PORT}`));