From 1abd426b794368af597e31d8390c5766cd4c6799 Mon Sep 17 00:00:00 2001 From: fcarraUniSa Date: Tue, 17 Feb 2026 09:52:33 +0100 Subject: [PATCH] Update index.js --- backend/index.js | 261 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 243 insertions(+), 18 deletions(-) diff --git a/backend/index.js b/backend/index.js index 1e71a9e..9d9316c 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,6 +1,7 @@ import express from 'express'; import cors from 'cors'; import { checkConnection, query, initDb } from './db.js'; +import { randomUUID } from 'crypto'; const app = express(); const PORT = process.env.PORT || 3000; @@ -8,46 +9,270 @@ const PORT = process.env.PORT || 3000; app.use(cors()); app.use(express.json()); -// Health Check & DB Init trigger -app.get('/api/health', async (req, res) => { - const dbStatus = await checkConnection(); - res.json({ - status: 'ok', - database: dbStatus ? 'connected' : 'disconnected', - timestamp: new Date().toISOString() - }); -}); +// --- HELPER FUNCTIONS --- +const formatDate = (date) => new Date(date).toISOString(); -// --- API ENDPOINTS EXAMPLES (To replace Mock Data) --- +// --- AUTH ENDPOINTS --- -// Get All Agents -app.get('/api/agents', async (req, res) => { +app.post('/api/auth/login', async (req, res) => { + const { email, password } = req.body; + try { - const agents = await query('SELECT * FROM agents'); - res.json(agents); + // 1. Check Agents + const agents = await query('SELECT * FROM agents WHERE email = ? AND password = ?', [email, password]); + if (agents.length > 0) { + const agent = agents[0]; + // Parse JSON fields + agent.queues = typeof agent.queues === 'string' ? JSON.parse(agent.queues) : agent.queues; + agent.skills = typeof agent.skills === 'string' ? JSON.parse(agent.skills) : agent.skills; + agent.avatarConfig = typeof agent.avatar_config === 'string' ? JSON.parse(agent.avatar_config) : agent.avatar_config; + return res.json({ user: agent, role: agent.role }); + } + + // 2. Check Clients + const clients = await query('SELECT * FROM client_users WHERE email = ? AND password = ?', [email, password]); + if (clients.length > 0) { + const client = clients[0]; + return res.json({ user: client, role: 'client' }); + } + + res.status(401).json({ error: 'Credenziali non valide' }); } catch (e) { + console.error(e); res.status(500).json({ error: e.message }); } }); -// Get Tickets +app.post('/api/auth/register', async (req, res) => { + const { name, email, password, company } = req.body; + const id = randomUUID(); + try { + await query( + 'INSERT INTO client_users (id, name, email, password, company, status) VALUES (?, ?, ?, ?, ?, ?)', + [id, name, email, password, company || null, 'active'] + ); + res.json({ success: true, user: { id, name, email, company, status: 'active' } }); + } catch (e) { + res.status(500).json({ error: 'Errore registrazione. Email potrebbe essere già in uso.' }); + } +}); + +// --- DATA FETCHING ENDPOINTS --- + +app.get('/api/initial-data', async (req, res) => { + try { + // Fetch Agents + const agents = await query('SELECT * FROM agents'); + const parsedAgents = agents.map(a => ({ + ...a, + queues: typeof a.queues === 'string' ? JSON.parse(a.queues) : a.queues, + skills: typeof a.skills === 'string' ? JSON.parse(a.skills) : a.skills, + avatarConfig: typeof a.avatar_config === 'string' ? JSON.parse(a.avatar_config) : a.avatar_config + })); + + // Fetch Client Users + const clientUsers = await query('SELECT * FROM client_users'); + + // Fetch Queues + const queues = await query('SELECT * FROM queues'); + + // Fetch KB Articles + const articles = await query('SELECT * FROM kb_articles ORDER BY last_updated DESC'); + + // Fetch Surveys + const surveys = await query('SELECT * FROM survey_results ORDER BY timestamp DESC'); + + res.json({ + agents: parsedAgents, + clientUsers, + queues, + articles, + surveys + }); + } catch (e) { + console.error(e); + res.status(500).json({ error: e.message }); + } +}); + +// --- TICKET ENDPOINTS --- + app.get('/api/tickets', async (req, res) => { try { - const tickets = await query('SELECT * FROM tickets ORDER BY created_at DESC'); + // Complex query to get tickets + messages + attachments + // Note: We use a subquery or JSON_ARRAYAGG to bundle messages + const sql = ` + SELECT + t.*, + t.assigned_agent_id as assignedAgentId, + t.customer_name as customerName, + t.created_at as createdAt, + ( + SELECT JSON_ARRAYAGG( + JSON_OBJECT( + 'id', m.id, + 'role', m.role, + 'content', m.content, + 'timestamp', m.timestamp + ) + ) + FROM ticket_messages m + WHERE m.ticket_id = t.id + ) as messages + FROM tickets t + ORDER BY t.created_at DESC + `; + + const rows = await query(sql); + + const tickets = rows.map(t => ({ + ...t, + attachments: typeof t.attachments === 'string' ? JSON.parse(t.attachments || '[]') : t.attachments, + messages: typeof t.messages === 'string' ? JSON.parse(t.messages || '[]') : (t.messages || []) + })); + res.json(tickets); + } catch (e) { + console.error(e); + res.status(500).json({ error: e.message }); + } +}); + +app.post('/api/tickets', async (req, res) => { + const { subject, description, priority, queue, customerName, attachments } = req.body; + const id = `T-${Date.now()}`; // Generate a simple ID or UUID + + try { + await query( + 'INSERT INTO tickets (id, subject, description, status, priority, customer_name, queue, attachments) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', + [id, subject, description, 'APERTO', priority, customerName, queue, JSON.stringify(attachments || [])] + ); + + // Fetch the created ticket to return it + const newTicket = { + id, + subject, + description, + status: 'APERTO', + priority, + customerName, + queue, + attachments: attachments || [], + messages: [], + createdAt: new Date().toISOString() + }; + + res.json(newTicket); + } catch (e) { + console.error(e); + res.status(500).json({ error: e.message }); + } +}); + +app.patch('/api/tickets/:id', async (req, res) => { + const { id } = req.params; + const updates = req.body; + + const fields = []; + const values = []; + + if (updates.status) { fields.push('status = ?'); values.push(updates.status); } + if (updates.priority) { fields.push('priority = ?'); values.push(updates.priority); } + if (updates.assignedAgentId !== undefined) { fields.push('assigned_agent_id = ?'); values.push(updates.assignedAgentId || null); } + if (updates.queue) { fields.push('queue = ?'); values.push(updates.queue); } + + if (fields.length === 0) return res.json({ success: true }); // Nothing to update + + values.push(id); + + try { + await query(`UPDATE tickets SET ${fields.join(', ')} WHERE id = ?`, values); + res.json({ success: true }); } catch (e) { res.status(500).json({ error: e.message }); } }); +// --- MESSAGING ENDPOINTS --- + +app.post('/api/tickets/:id/messages', async (req, res) => { + const { id } = req.params; // Ticket ID + const { role, content } = req.body; + const messageId = `m-${Date.now()}`; + + try { + await query( + 'INSERT INTO ticket_messages (id, ticket_id, role, content) VALUES (?, ?, ?, ?)', + [messageId, id, role, content] + ); + + // Se il messaggio è dell'utente e il ticket era risolto, riapriamolo + if (role === 'user') { + await query("UPDATE tickets SET status = 'APERTO' WHERE id = ? AND status = 'RISOLTO'", [id]); + } + + res.json({ + id: messageId, + role, + content, + timestamp: new Date().toISOString() + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +// --- SURVEY ENDPOINTS --- +app.post('/api/surveys', async (req, res) => { + const { rating, comment, source, referenceId } = req.body; + const id = randomUUID(); + try { + await query( + 'INSERT INTO survey_results (id, rating, comment, source, reference_id) VALUES (?, ?, ?, ?, ?)', + [id, rating, comment, source, referenceId || null] + ); + res.json({ success: true, id }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +// --- KB ENDPOINTS --- +app.post('/api/articles', async (req, res) => { + const { title, content, category, type, url, source } = req.body; + const id = `kb-${Date.now()}`; + try { + await query( + 'INSERT INTO kb_articles (id, title, content, category, type, url, source) VALUES (?, ?, ?, ?, ?, ?, ?)', + [id, title, content, category, type, url, source] + ); + res.json({ success: true, id, lastUpdated: new Date().toISOString() }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +app.patch('/api/articles/:id', async (req, res) => { + const { id } = req.params; + const { title, content, category, type, url } = req.body; + try { + await query( + 'UPDATE kb_articles SET title=?, content=?, category=?, type=?, url=? WHERE id=?', + [title, content, category, type, url, id] + ); + res.json({ success: true }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + // Avvio del server const startServer = async () => { - // Attendi inizializzazione DB (creazione tabelle se necessario) await initDb(); app.listen(PORT, () => { console.log(`🚀 Backend Server running on port ${PORT}`); - checkConnection(); // Initial check + checkConnection(); }); };