feat: funzione per l'invio della posta elettronica da otrs-turbo. fix: corretta consuntivazione automatica. feat: aggiunto link apri in otrs anche nel numero del ticket in cima
This commit is contained in:
+216
@@ -0,0 +1,216 @@
|
||||
'use strict';
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const pool = require('../db');
|
||||
const { db } = require('../activityDb');
|
||||
const { sendMail } = require('../utils/mailer');
|
||||
|
||||
// ─── SIGNATURES ────────────────────────────────────────────────────────────────
|
||||
|
||||
// GET /api/email/signatures — list signatures for a given agent
|
||||
router.get('/signatures', (req, res) => {
|
||||
try {
|
||||
const { agent_id } = req.query;
|
||||
if (!agent_id) return res.status(400).json({ error: 'agent_id è obbligatorio' });
|
||||
|
||||
const rows = db.prepare(`
|
||||
SELECT id, name, body_html, is_default, created_at, updated_at
|
||||
FROM email_signatures
|
||||
WHERE agent_id = ?
|
||||
ORDER BY is_default DESC, name ASC
|
||||
`).all(parseInt(agent_id, 10));
|
||||
|
||||
res.json(rows);
|
||||
} catch (err) {
|
||||
console.error('[Email] Error listing signatures:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/email/signatures — create a new signature
|
||||
router.post('/signatures', (req, res) => {
|
||||
try {
|
||||
const { agent_id, name, body_html, is_default = 0 } = req.body;
|
||||
if (!agent_id || !name) return res.status(400).json({ error: 'agent_id e name sono obbligatori' });
|
||||
|
||||
// If new signature is default, reset others for this agent
|
||||
if (is_default) {
|
||||
db.prepare(`UPDATE email_signatures SET is_default = 0 WHERE agent_id = ?`).run(parseInt(agent_id, 10));
|
||||
}
|
||||
|
||||
const result = db.prepare(`
|
||||
INSERT INTO email_signatures (agent_id, name, body_html, is_default)
|
||||
VALUES (?, ?, ?, ?)
|
||||
`).run(parseInt(agent_id, 10), name, body_html || '', is_default ? 1 : 0);
|
||||
|
||||
res.json({ id: result.lastInsertRowid, agent_id, name, body_html, is_default });
|
||||
} catch (err) {
|
||||
console.error('[Email] Error creating signature:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /api/email/signatures/:id — update a signature
|
||||
router.put('/signatures/:id', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { agent_id, name, body_html, is_default } = req.body;
|
||||
|
||||
// If new signature is default, reset others for this agent
|
||||
if (is_default && agent_id) {
|
||||
db.prepare(`UPDATE email_signatures SET is_default = 0 WHERE agent_id = ?`).run(parseInt(agent_id, 10));
|
||||
}
|
||||
|
||||
db.prepare(`
|
||||
UPDATE email_signatures
|
||||
SET name = ?, body_html = ?, is_default = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
||||
WHERE id = ?
|
||||
`).run(name, body_html || '', is_default ? 1 : 0, parseInt(id, 10));
|
||||
|
||||
const updated = db.prepare(`SELECT * FROM email_signatures WHERE id = ?`).get(parseInt(id, 10));
|
||||
res.json(updated);
|
||||
} catch (err) {
|
||||
console.error('[Email] Error updating signature:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// PATCH /api/email/signatures/:id/default — set a signature as default
|
||||
router.patch('/signatures/:id/default', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { agent_id } = req.body;
|
||||
|
||||
if (agent_id) {
|
||||
db.prepare(`UPDATE email_signatures SET is_default = 0 WHERE agent_id = ?`).run(parseInt(agent_id, 10));
|
||||
}
|
||||
|
||||
db.prepare(`
|
||||
UPDATE email_signatures SET is_default = 1, updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
||||
WHERE id = ?
|
||||
`).run(parseInt(id, 10));
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
console.error('[Email] Error setting default signature:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/email/signatures/:id — delete a signature
|
||||
router.delete('/signatures/:id', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
db.prepare(`DELETE FROM email_signatures WHERE id = ?`).run(parseInt(id, 10));
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
console.error('[Email] Error deleting signature:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// ─── SEND EMAIL ───────────────────────────────────────────────────────────────
|
||||
|
||||
// POST /api/email/send — send an email for a ticket
|
||||
router.post('/send', async (req, res) => {
|
||||
const {
|
||||
ticketId,
|
||||
to,
|
||||
cc = [],
|
||||
subject: customSubject,
|
||||
bodyHtml,
|
||||
attachments = [],
|
||||
inlineImages = [],
|
||||
agentId,
|
||||
agentName = 'Agente',
|
||||
keepHelpdeskCopy = true,
|
||||
} = req.body;
|
||||
|
||||
if (!ticketId) return res.status(400).json({ error: 'ticketId è obbligatorio' });
|
||||
if (!to || !to.length) return res.status(400).json({ error: 'Il campo "to" è obbligatorio' });
|
||||
if (!bodyHtml) return res.status(400).json({ error: 'Il corpo della email è obbligatorio' });
|
||||
|
||||
try {
|
||||
// 1. Fetch ticket number and title for subject
|
||||
const ticketResult = await pool.query(
|
||||
`SELECT tn, title FROM ticket WHERE id = $1`,
|
||||
[ticketId]
|
||||
);
|
||||
if (!ticketResult.rows.length) return res.status(404).json({ error: 'Ticket non trovato' });
|
||||
|
||||
const { tn, title } = ticketResult.rows[0];
|
||||
const subject = customSubject || `Re: [Ticket#${tn}] ${title}`;
|
||||
|
||||
// 2. Build BCC list (include OTRS system mailbox if keepHelpdeskCopy is true)
|
||||
const bcc = [];
|
||||
if (keepHelpdeskCopy) {
|
||||
const otrsBcc = process.env.OTRS_MAIL_BCC;
|
||||
if (otrsBcc) bcc.push(otrsBcc);
|
||||
}
|
||||
|
||||
// 3. Send via configured mailer (Graph API or SMTP)
|
||||
await sendMail({ to, cc, bcc, subject, bodyHtml, attachments, inlineImages });
|
||||
|
||||
// 4. Log internal note in OTRS ticket via DB (email sent record)
|
||||
try {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const agentLoginResult = agentId
|
||||
? await pool.query(`SELECT login, first_name, last_name FROM users WHERE id = $1`, [agentId])
|
||||
: { rows: [] };
|
||||
|
||||
const agentUser = agentLoginResult.rows[0];
|
||||
let agentEmail = 'agent@localhost';
|
||||
if (agentId) {
|
||||
const prefRes = await pool.query(
|
||||
`SELECT preferences_value FROM user_preferences WHERE user_id = $1 AND preferences_key = 'UserEmail'`,
|
||||
[agentId]
|
||||
);
|
||||
if (prefRes.rows.length > 0 && prefRes.rows[0].preferences_value) {
|
||||
agentEmail = prefRes.rows[0].preferences_value;
|
||||
}
|
||||
}
|
||||
|
||||
const aFrom = agentUser
|
||||
? `"${agentUser.first_name} ${agentUser.last_name}" <${agentEmail}>`
|
||||
: agentName;
|
||||
|
||||
const toList = to.join(', ');
|
||||
const noteBody = `Email inviata a: ${toList}${cc.length ? `\nCC: ${cc.join(', ')}` : ''}`;
|
||||
|
||||
// Insert article via DB (internal note to log email dispatch)
|
||||
const artInsert = await pool.query(`
|
||||
INSERT INTO article (
|
||||
ticket_id, article_sender_type_id, communication_channel_id,
|
||||
is_visible_for_customer, a_from, a_to, a_subject, a_body,
|
||||
content_path, incoming_time, create_time, create_by, change_time, change_by
|
||||
) VALUES (
|
||||
$1, 1, 2, 0, $2, $3, $4, $5,
|
||||
'/', $6, NOW(), $7, NOW(), $7
|
||||
) RETURNING id`,
|
||||
[ticketId, aFrom, toList, `[Email inviata] ${subject}`, noteBody, now, agentId || 1]
|
||||
);
|
||||
|
||||
const articleId = artInsert.rows[0]?.id;
|
||||
|
||||
if (articleId) {
|
||||
await pool.query(`
|
||||
INSERT INTO article_data_mime (article_id, a_from, a_to, a_cc, a_subject, a_body, a_content_type, incoming_time, create_time, create_by, change_time, change_by)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, 'text/plain; charset=utf-8', $7, NOW(), $8, NOW(), $8)`,
|
||||
[articleId, aFrom, toList, cc.join(', '), subject, noteBody, now, agentId || 1]
|
||||
);
|
||||
}
|
||||
} catch (noteErr) {
|
||||
console.warn('[Email] Nota interna OTRS non inserita (non bloccante):', noteErr.message);
|
||||
}
|
||||
|
||||
console.log(`[Email] ✅ Email inviata per ticket #${tn} a: ${to.join(', ')}`);
|
||||
res.json({ success: true, subject, to });
|
||||
|
||||
} catch (err) {
|
||||
console.error('[Email] ❌ Errore invio email:', err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user