From 93afeee7ff8b0d849e6b3df2330268c12eb526e2 Mon Sep 17 00:00:00 2001 From: Steph Ponzo Date: Mon, 9 Feb 2026 21:13:47 +0100 Subject: [PATCH] Ajout du module System Notification (Mailer + DB + Repository) --- system_notification/.gitignore | 2 + system_notification/config/db.js | 17 ++ system_notification/package-lock.json | 161 ++++++++++++++++++ system_notification/package.json | 18 ++ .../repositories/MySqlAlertRepository.js | 35 ++++ .../services/alerts/alertServices.js | 0 .../services/channels/discord.js | 0 .../services/channels/mailer.js | 32 ++++ .../services/channels/telegram.js | 0 system_notification/services/channels/web.js | 0 system_notification/test-connection.js | 27 +++ system_notification/test-mailer.js | 43 +++++ 12 files changed, 335 insertions(+) create mode 100644 system_notification/.gitignore create mode 100644 system_notification/config/db.js create mode 100644 system_notification/package-lock.json create mode 100644 system_notification/package.json create mode 100644 system_notification/repositories/MySqlAlertRepository.js create mode 100644 system_notification/services/alerts/alertServices.js create mode 100644 system_notification/services/channels/discord.js create mode 100644 system_notification/services/channels/mailer.js create mode 100644 system_notification/services/channels/telegram.js create mode 100644 system_notification/services/channels/web.js create mode 100644 system_notification/test-connection.js create mode 100644 system_notification/test-mailer.js diff --git a/system_notification/.gitignore b/system_notification/.gitignore new file mode 100644 index 0000000..713d500 --- /dev/null +++ b/system_notification/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.env diff --git a/system_notification/config/db.js b/system_notification/config/db.js new file mode 100644 index 0000000..dd9c680 --- /dev/null +++ b/system_notification/config/db.js @@ -0,0 +1,17 @@ +const mysql = require('mysql2/promise'); +// CORRECTION : On pointe simplement vers le .env à la racine du projet +const path = require('path'); +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); + +const db = mysql.createPool({ + host: process.env.DB_HOST, + port: process.env.DB_PORT, + user: process.env.DB_USER, + password: process.env.DB_PASS, + database: process.env.DB_NAME, + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0 +}); + +module.exports = db; diff --git a/system_notification/package-lock.json b/system_notification/package-lock.json new file mode 100644 index 0000000..d7d9d4b --- /dev/null +++ b/system_notification/package-lock.json @@ -0,0 +1,161 @@ +{ + "name": "system_notification", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "system_notification", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^17.2.4", + "mysql2": "^3.16.3", + "nodemailer": "^8.0.1" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dotenv": { + "version": "17.2.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.4.tgz", + "integrity": "sha512-mudtfb4zRB4bVvdj0xRo+e6duH1csJRM8IukBqfTRvHotn9+LBXB8ynAidP9zHqoRC/fsllXgk4kCKlR21fIhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru.min": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", + "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/mysql2": { + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.16.3.tgz", + "integrity": "sha512-+3XhQEt4FEFuvGV0JjIDj4eP2OT/oIj/54dYvqhblnSzlfcxVOuj+cd15Xz6hsG4HU1a+A5+BA9gm0618C4z7A==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.2", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.2", + "long": "^5.3.2", + "lru.min": "^1.1.3", + "named-placeholders": "^1.1.6", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.3" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", + "license": "MIT", + "dependencies": { + "lru.min": "^1.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nodemailer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.1.tgz", + "integrity": "sha512-5kcldIXmaEjZcHR6F28IKGSgpmZHaF1IXLWFTG+Xh3S+Cce4MiakLtWY+PlBU69fLbRa8HlaGIrC/QolUpHkhg==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + } + } +} diff --git a/system_notification/package.json b/system_notification/package.json new file mode 100644 index 0000000..6dbc23e --- /dev/null +++ b/system_notification/package.json @@ -0,0 +1,18 @@ +{ + "name": "system_notification", + "version": "1.0.0", + "description": "", + "main": "test-connection.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "dotenv": "^17.2.4", + "mysql2": "^3.16.3", + "nodemailer": "^8.0.1" + } +} diff --git a/system_notification/repositories/MySqlAlertRepository.js b/system_notification/repositories/MySqlAlertRepository.js new file mode 100644 index 0000000..e993678 --- /dev/null +++ b/system_notification/repositories/MySqlAlertRepository.js @@ -0,0 +1,35 @@ +// 1. On importe la connexion à la base de données +const db = require('../config/db'); + +const MySqlAlertRepository = { + + /** + * Récupère toutes les règles d'alerte actives avec l'email de l'utilisateur + */ + async findActiveRules() { + try { + // On prépare la requête SQL avec une jointure (JOIN) + // On récupère les colonnes de alert_rules (ar) et l'email de users (u) + const sql = ` + SELECT ar.*, u.email + FROM alert_rules ar + JOIN users u ON ar.user_id = u.user_id + WHERE ar.enabled = 1 + `; + + // On exécute la requête + const [rows] = await db.execute(sql); + + // On retourne les données + return rows; + } catch (error) { + console.error("Erreur dans findActiveRules:", error); + throw error; // On laisse le service gérer l'erreur si besoin + } + } + + +}; + +// 3. On exporte le repository +module.exports = MySqlAlertRepository; diff --git a/system_notification/services/alerts/alertServices.js b/system_notification/services/alerts/alertServices.js new file mode 100644 index 0000000..e69de29 diff --git a/system_notification/services/channels/discord.js b/system_notification/services/channels/discord.js new file mode 100644 index 0000000..e69de29 diff --git a/system_notification/services/channels/mailer.js b/system_notification/services/channels/mailer.js new file mode 100644 index 0000000..6bd8321 --- /dev/null +++ b/system_notification/services/channels/mailer.js @@ -0,0 +1,32 @@ +const nodemailer = require('nodemailer'); + + +async function sendAlertEmail(to, signal) { + const transporter = nodemailer.createTransport({ + host: process.env.MAIL_HOST, + port: parseInt(process.env.MAIL_PORT), + auth: { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASS + } + }); + + try { + const confidencePercent = (parseFloat(signal.confidence) * 100).toFixed(2); + const mailOptions = { + from: `"Wall-e-tte" <${process.env.MAIL_USER}>`, + to: to, + subject: `🚨 Alerte : ${signal.action} sur ${signal.pair}`, + text: `Action : ${signal.action}\nConfiance : ${confidencePercent}%`, + }; + + const info = await transporter.sendMail(mailOptions); + console.log("✅ Email envoyé ! ID:", info.messageId); + return 'SENT'; + } catch (error) { + console.error("❌ Erreur d'envoi mail :", error.message); + return 'FAILED'; + } +} + +module.exports = { sendAlertEmail }; diff --git a/system_notification/services/channels/telegram.js b/system_notification/services/channels/telegram.js new file mode 100644 index 0000000..e69de29 diff --git a/system_notification/services/channels/web.js b/system_notification/services/channels/web.js new file mode 100644 index 0000000..e69de29 diff --git a/system_notification/test-connection.js b/system_notification/test-connection.js new file mode 100644 index 0000000..d7ce0e1 --- /dev/null +++ b/system_notification/test-connection.js @@ -0,0 +1,27 @@ +const repository = require('./repositories/MySqlAlertRepository'); + +async function test() { + console.log("Tentative de connexion à MariaDB..."); + + try { + const rules = await repository.findActiveRules(); + console.log("Connexion réussie !"); + console.log(`Nombre de règles actives trouvées : ${rules.length}`); + + if (rules.length > 0) { + console.log("Détail de la première règle :", rules[0]); + } else { + console.log("La connexion marche, mais la table 'alert_rules' est vide;"); + } + + } catch (error) { + console.error("ÉCHEC du test :"); + console.error("- Vérifie ton fichier .env (User, Password, Host)"); + console.error("- Vérifie que tu es bien connecté au VPN si nécessaire"); + console.error("Détail de l'erreur :", error.message); + } finally { + process.exit(); // On ferme le script proprement + } +} + +test(); diff --git a/system_notification/test-mailer.js b/system_notification/test-mailer.js new file mode 100644 index 0000000..187f324 --- /dev/null +++ b/system_notification/test-mailer.js @@ -0,0 +1,43 @@ +require('dotenv').config(); + +const repository = require('./repositories/MySqlAlertRepository'); +const { sendAlertEmail } = require('./services/channels/mailer'); + +async function runTest() { + console.log("Recherche d'une règle active dans la DB..."); + + try { + const rules = await repository.findActiveRules(); + + if (rules.length === 0) { + console.log("Aucune règle trouvée. Vérifie tes tables SQL."); + return; + } + + const rule = rules[0]; + console.log(`Règle trouvée pour : ${rule.email}`); + + // On simule un signal de test + const fakeSignal = { + action: 'BUY', + pair: 'BTC/EUR', + confidence: 0.85, + severity: 'WARNING' + }; + + console.log("✉️ Tentative d'envoi du mail..."); + const mailerModule = require('./services/channels/mailer'); + console.log("Contenu du module mailer :", mailerModule); // Ajoute cette ligne pour débugger + const status = await sendAlertEmail(rule.email, fakeSignal); + + console.log(`📊 Résultat de l'envoi : ${status}`); + + } catch (error) { + console.error("❌ Erreur pendant le test :", error); + } finally { + process.exit(); + } +} + +runTest(); + -- 2.50.1