const express = require('express'); const router = express.Router(); const path = require('path'); const fs = require('fs'); const multer = require('multer'); const http = require('http'); const QS_HOST = process.env.QS_HOST || 'python-quality'; const QS_PORT = parseInt(process.env.QS_PORT || '3002'); const SHARED_UPLOAD_DIR = path.join(__dirname, '..', 'data', 'uploads'); if (!fs.existsSync(SHARED_UPLOAD_DIR)) fs.mkdirSync(SHARED_UPLOAD_DIR, { recursive: true }); const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, SHARED_UPLOAD_DIR), filename: (req, file, cb) => cb(null, Date.now() + '-' + file.originalname) }); const upload = multer({ storage, limits: { fileSize: 100 * 1024 * 1024 } }); function qsApi(path, method, body) { return new Promise((resolve, reject) => { const opts = { hostname: QS_HOST, port: QS_PORT, path, method, headers: { 'Content-Type': 'application/json' }, timeout: 30000 }; const req = http.request(opts, (res) => { let data = ''; res.on('data', c => data += c); res.on('end', () => { if (method === 'GET' && res.statusCode >= 400) return reject(new Error('offline')); try { resolve(JSON.parse(data)); } catch(e) { resolve({ raw: data }); } }); }); req.on('error', (e) => reject(e)); req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); }); if (body) req.write(JSON.stringify(body)); req.end(); }); } router.get('/', async (req, res) => { let files = []; let qsStatus = 'offline'; let services = {}; try { const dirFiles = fs.readdirSync(SHARED_UPLOAD_DIR).filter(f => f !== '.gitkeep'); files = dirFiles.map(f => ({ file_id: f.split('.')[0], filename: f, size: fs.statSync(path.join(SHARED_UPLOAD_DIR, f)).size })); await qsApi('/python-quality/', 'GET'); qsStatus = 'online'; } catch (e) { qsStatus = 'offline'; } try { const { getServicesStatus } = require('../lib/services'); services = await getServicesStatus(); } catch (e) {} const { getDb } = require('../db'); const clients = getDb().prepare('SELECT id, name FROM clients ORDER BY name').all(); const clientId = req.query.client_id || req.session.activeClientId || null; res.render('quality-dashboard', { files, qsStatus, services, clients, clientId, uploaded: null, profile: null, report: null, error: null }); }); router.post('/upload', upload.single('file'), async (req, res) => { if (!req.file) return res.redirect('/quality'); try { const resp = await qsApi('/python-quality/api/profile', 'POST', { file_id: req.file.filename.split('.')[0], shared_path: path.join(SHARED_UPLOAD_DIR, req.file.filename) }); const profile = resp.profile || resp; const uploaded = { file_id: req.file.filename.split('.')[0], original_name: req.file.originalname, rows: profile.rows, columns: profile.columns }; res.render('quality-dashboard', { files: [], qsStatus: 'online', uploaded, profile, report: null, error: null }); } catch (e) { res.render('quality-dashboard', { files: [], qsStatus: 'online', uploaded: null, profile: null, report: null, error: 'Kon bestand niet analyseren: ' + (e.message || 'onbekende fout') }); } }); router.post('/quality-check/:fileId', async (req, res) => { try { const result = await qsApi('/python-quality/api/quality-check', 'POST', { file_id: req.params.fileId, checks: ['completeness', 'uniqueness', 'range', 'type'] }); res.json(result); } catch (e) { res.status(500).json({ error: e.message }); } }); router.get('/profile/:fileId', async (req, res) => { try { const result = await qsApi('/python-quality/api/profile', 'POST', { file_id: req.params.fileId }); res.json(result); } catch (e) { res.status(500).json({ error: e.message }); } }); router.get('/report/:reportId', async (req, res) => { try { const result = await qsApi('/python-quality/api/report/' + req.params.reportId, 'GET'); res.json(result); } catch (e) { res.status(500).json({ error: e.message }); } }); router.post('/dbt/validate', async (req, res) => { try { const result = await qsApi('/python-quality/api/dbt/validate', 'POST', req.body); res.json(result); } catch (e) { res.status(500).json({ error: e.message }); } }); router.post('/dbt/test', async (req, res) => { try { const result = await qsApi('/python-quality/api/dbt/test', 'POST', req.body); res.json(result); } catch (e) { res.status(500).json({ error: e.message }); } }); module.exports = router;