const express = require('express'); const router = express.Router(); const fs = require('fs'); const path = require('path'); const { db, logAttivita } = require('../activityDb'); const pool = require('../db'); const baseDir = process.pkg ? path.dirname(process.execPath) : path.resolve(__dirname, '..'); const envPath = fs.existsSync(path.resolve(baseDir, '.env')) ? path.resolve(baseDir, '.env') : path.resolve(__dirname, '..', '.env'); // Helper to resolve agent name from DB async function resolveAgentName(agentId) { try { const r = await pool.query( `SELECT first_name, last_name, login FROM users WHERE id = $1`, [agentId] ); if (r.rows.length > 0) { const u = r.rows[0]; return (u.first_name || '') + ' ' + (u.last_name || '') || u.login || `Agent #${agentId}`; } } catch (_) { /* ignore */ } return `Agent #${agentId}`; } // GET /api/config/env — Read current .env file and history router.get('/env', async (req, res) => { try { let content = ''; if (fs.existsSync(envPath)) { content = fs.readFileSync(envPath, 'utf8'); } const history = db.prepare(` SELECT * FROM env_history ORDER BY id DESC LIMIT 100 `).all(); res.json({ content, history }); } catch (err) { console.error('Error reading env config:', err); res.status(500).json({ error: 'Errore durante la lettura del file .env', message: err.message }); } }); // POST /api/config/env — Save updated .env content and create snapshot in SQLite router.post('/env', async (req, res) => { try { const { content, note } = req.body; const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const agentName = await resolveAgentName(operatorId); if (typeof content !== 'string') { return res.status(400).json({ error: 'Il contenuto del file .env è obbligatorio' }); } // If history is empty and current .env exists, create an initial baseline snapshot const countRow = db.prepare('SELECT COUNT(*) AS count FROM env_history').get(); if (countRow.count === 0 && fs.existsSync(envPath)) { const initialContent = fs.readFileSync(envPath, 'utf8'); db.prepare(` INSERT INTO env_history (agent_id, agent_name, content, note) VALUES (?, ?, ?, ?) `).run(operatorId, agentName, initialContent, 'Baseline iniziale preesistente'); } // Write updated content to disk fs.writeFileSync(envPath, content, 'utf8'); try { require('dotenv').config({ path: envPath, override: true }); } catch (_) {} // Save snapshot in history table const info = db.prepare(` INSERT INTO env_history (agent_id, agent_name, content, note) VALUES (?, ?, ?, ?) `).run(operatorId, agentName, content, note || 'Modifica manuale .env'); logAttivita({ agente_id: operatorId, agente_nome: agentName, titolo_azione: 'Modifica .env', azione: { note: note || 'Modifica manuale .env', history_id: info.lastInsertRowid }, esito: 'successo', }); const history = db.prepare(` SELECT * FROM env_history ORDER BY id DESC LIMIT 100 `).all(); res.json({ success: true, message: 'File .env aggiornato e salvato nello storico locale con successo!', history_id: info.lastInsertRowid, history, }); } catch (err) { console.error('Error saving .env config:', err); res.status(500).json({ error: 'Errore durante il salvataggio del file .env', message: err.message }); } }); // POST /api/config/env/restore/:history_id — Restore a previous .env snapshot router.post('/env/restore/:history_id', async (req, res) => { try { const { history_id } = req.params; const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const agentName = await resolveAgentName(operatorId); const record = db.prepare('SELECT * FROM env_history WHERE id = ?').get(history_id); if (!record) { return res.status(404).json({ error: 'Versione di storico non trovata' }); } // Write snapshot content to disk fs.writeFileSync(envPath, record.content, 'utf8'); try { require('dotenv').config({ path: envPath, override: true }); } catch (_) {} // Insert new history record documenting the restore operation const restoreNote = `Ripristinato alla versione #${record.id} del ${record.created_at}`; const info = db.prepare(` INSERT INTO env_history (agent_id, agent_name, content, note) VALUES (?, ?, ?, ?) `).run(operatorId, agentName, record.content, restoreNote); logAttivita({ agente_id: operatorId, agente_nome: agentName, titolo_azione: 'Ripristino .env', azione: { restored_from_id: record.id, new_history_id: info.lastInsertRowid }, esito: 'successo', }); const history = db.prepare(` SELECT * FROM env_history ORDER BY id DESC LIMIT 100 `).all(); res.json({ success: true, message: `Versione #${record.id} ripristinata con successo!`, content: record.content, history, }); } catch (err) { console.error('Error restoring .env version:', err); res.status(500).json({ error: 'Errore durante il ripristino della versione .env', message: err.message }); } }); // Helper handler for deleting a specific .env history entry async function handleDeleteHistory(req, res) { try { const { id } = req.params; const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const agentName = await resolveAgentName(operatorId); const record = db.prepare('SELECT * FROM env_history WHERE id = ?').get(id); if (!record) { return res.status(404).json({ error: 'Versione di storico non trovata' }); } db.prepare('DELETE FROM env_history WHERE id = ?').run(id); logAttivita({ agente_id: operatorId, agente_nome: agentName, titolo_azione: 'Eliminazione Storico .env', azione: { deleted_history_id: id }, esito: 'successo', }); const history = db.prepare(` SELECT * FROM env_history ORDER BY id DESC LIMIT 100 `).all(); res.json({ success: true, message: `Versione #${id} dello storico eliminata con successo!`, history, }); } catch (err) { console.error('Error deleting .env history entry:', err); res.status(500).json({ error: 'Errore durante l\'eliminazione della versione dello storico', message: err.message }); } } // DELETE & POST /api/config/env/history/:id — Delete a specific .env history entry router.delete('/env/history/:id', handleDeleteHistory); router.post('/env/history/:id/delete', handleDeleteHistory); // GET /api/config/user-signatures — Fetch all user signature images router.get('/user-signatures', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const signatures = db.prepare(` SELECT * FROM user_signatures WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json(signatures); } catch (err) { console.error('Error fetching user signatures:', err); res.status(500).json({ error: 'Errore durante il recupero delle firme utente', message: err.message }); } }); // POST /api/config/user-signatures — Add new user signature image router.post('/user-signatures', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const { name, image_data } = req.body; if (!name || !image_data) { return res.status(400).json({ error: 'Nome e dati immagine sono obbligatori' }); } const info = db.prepare(` INSERT INTO user_signatures (agent_id, name, image_data) VALUES (?, ?, ?) `).run(operatorId, name.trim(), image_data); const signatures = db.prepare(` SELECT * FROM user_signatures WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json({ success: true, message: 'Immagine/Firma salvata nel database con successo!', id: info.lastInsertRowid, signatures }); } catch (err) { console.error('Error saving user signature:', err); res.status(500).json({ error: 'Errore durante il salvataggio della firma', message: err.message }); } }); // DELETE /api/config/user-signatures/:id — Delete user signature image router.delete('/user-signatures/:id', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const { id } = req.params; db.prepare(`DELETE FROM user_signatures WHERE id = ? AND agent_id = ?`).run(id, operatorId); const signatures = db.prepare(` SELECT * FROM user_signatures WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json({ success: true, message: 'Firma eliminata con successo!', signatures }); } catch (err) { console.error('Error deleting user signature:', err); res.status(500).json({ error: 'Errore durante l\'eliminazione della firma', message: err.message }); } }); // GET /api/config/user-shapes — List custom user shapes router.get('/user-shapes', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const shapes = db.prepare(` SELECT * FROM user_shapes WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json(shapes); } catch (err) { console.error('Error fetching user shapes:', err); res.status(500).json({ error: 'Errore durante il recupero delle forme utente', message: err.message }); } }); // POST /api/config/user-shapes — Create a new custom shape router.post('/user-shapes', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const { name, shape_type, fill_color, border_color, border_width, is_favorite } = req.body; if (!name) { return res.status(400).json({ error: 'Il nome della forma è obbligatorio' }); } const info = db.prepare(` INSERT INTO user_shapes (agent_id, name, shape_type, fill_color, border_color, border_width, is_favorite) VALUES (?, ?, ?, ?, ?, ?, ?) `).run( operatorId, name.trim(), shape_type || 'rectangle', fill_color || '#3b82f6', border_color || '#1e3a8a', parseInt(border_width || 3, 10), is_favorite !== undefined ? (is_favorite ? 1 : 0) : 1 ); const shapes = db.prepare(` SELECT * FROM user_shapes WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json({ success: true, message: 'Forma salvata nei preferiti con successo!', id: info.lastInsertRowid, shapes }); } catch (err) { console.error('Error saving user shape:', err); res.status(500).json({ error: 'Errore durante il salvataggio della forma', message: err.message }); } }); // PUT /api/config/user-shapes/:id/toggle-favorite — Toggle favorite status router.put('/user-shapes/:id/toggle-favorite', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const { id } = req.params; const shape = db.prepare(`SELECT * FROM user_shapes WHERE id = ? AND agent_id = ?`).get(id, operatorId); if (!shape) { return res.status(404).json({ error: 'Forma non trovata' }); } const newFav = shape.is_favorite ? 0 : 1; db.prepare(`UPDATE user_shapes SET is_favorite = ? WHERE id = ? AND agent_id = ?`).run(newFav, id, operatorId); const shapes = db.prepare(` SELECT * FROM user_shapes WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json({ success: true, shapes }); } catch (err) { console.error('Error toggling shape favorite status:', err); res.status(500).json({ error: 'Errore durante l\'aggiornamento dei preferiti', message: err.message }); } }); // DELETE /api/config/user-shapes/:id — Delete a custom shape router.delete('/user-shapes/:id', (req, res) => { try { const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10); const { id } = req.params; db.prepare(`DELETE FROM user_shapes WHERE id = ? AND agent_id = ?`).run(id, operatorId); const shapes = db.prepare(` SELECT * FROM user_shapes WHERE agent_id = ? ORDER BY id DESC `).all(operatorId); res.json({ success: true, message: 'Forma eliminata con successo!', shapes }); } catch (err) { console.error('Error deleting user shape:', err); res.status(500).json({ error: 'Errore durante l\'eliminazione della forma', message: err.message }); } }); module.exports = router;