diff --git a/README.md b/README.md index f4e33503707b22e897065144b7d9d03b9ea3b23e..61990cdcb80a1f29b0148ce46996271518cedfb1 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,8 @@ Plug-in réalisé dans le cadre du projet [Lex:gaMe](https://aslan.universite-ly - Ouvrir Firefox et accéder aux modules complémentaires (Ctrl + Shift + A (Windows/Linux) ou Cmd + Shift + A (Mac)) - Cliquer sur l'icône en haut à droite puis sur "Déboguer des modules" - Cliquer sur "Charger un module complémentaire temporaire" -- Sélectionner le fichier 'manifest.json' \ No newline at end of file +- Sélectionner le fichier 'manifest.json' + +## Connexion/Déconnexion de l'utilisateur via le menu de l'extension +Via un bouton de connexion/déconnexion dans le menu de l'extension, l'utilisateur accède à la page d'authentification de [Prisms](https://prisms.lezinter.net/fr/login), complète ses informations de connexion et doit cliquer sur "Se connecter avec BaLex". Le script récupère ensuite le token d'authentification et le stocke dans le LocalStorage. +Si l'utilisateur clique sur le bouton "Se déconnecter" de l'extension, le token est supprimé. \ No newline at end of file diff --git a/menu_extension/background.js b/menu_extension/background.js index 2c13d9651ffc0f112c557d5aa77f49a451d08740..88538aa4409de3f11f4a7986afb6969a6063fe7a 100644 --- a/menu_extension/background.js +++ b/menu_extension/background.js @@ -3,10 +3,19 @@ let areStatsActive = false; console.log("ff2BaLex est chargé."); +// === 1. Installation de l'extension === browser.runtime.onInstalled.addListener(() => { console.log("ff2BaLex est installé."); + + // Création d'un bouton unique de connexion/déconnexion + browser.contextMenus.create({ + id: "toggle_connection", + title: "Se connecter à la base lexicale", + contexts: ["all"] + }); }); +// === 2. Suivi des changements de paramètres === browser.storage.onChanged.addListener((changes) => { if (changes.extensionActive) { isExtensionActive = changes.extensionActive.newValue; @@ -18,3 +27,96 @@ browser.storage.onChanged.addListener((changes) => { console.log("Statistiques activées :", areStatsActive); } }); + +// === 3. Gestion des messages provenant du bouton Connexion/Déconnexion === +browser.runtime.onMessage.addListener(async (message) => { + if (message.action === "toggleConnection") { + const isConnected = await isUserConnected(); + if (isConnected) { + disconnectFromLexicalDB(); + } else { + openLoginPage(); + } + } +}); + +// === 4. Ouvrir la page de connexion Prisms === +function openLoginPage() { + const authUrl = "https://prisms.lezinter.net/fr/login"; + browser.tabs.create({ url: authUrl }); +} + +// === 5. Suivi du parcours de connexion et récupération du token === +browser.webNavigation.onCompleted.addListener(async (details) => { + const url = new URL(details.url); + + // Si connecté, rediriger vers la page BaLex dans Prisms + if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") { + console.log("Connecté à Prisms, veuillez cliquer sur 'Se connecter avec BaLex'..."); + } + + // Une fois sur la page du tableau de bord BaLex, récupérer le token + if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") { + console.log("Tentative de récupération du token depuis Prisms..."); + + try { + await new Promise(resolve => setTimeout(resolve, 3000)); // Pause pour chargement complet + await browser.tabs.executeScript(details.tabId, { + code: ` + (function() { + const tokenElement = document.getElementById("accesToken"); + console.log("Token détecté :", tokenElement ? tokenElement.innerText : "Non trouvé"); + return tokenElement ? tokenElement.innerText.trim() : null; + })(); + ` + }).then(async (results) => { + const token = results[0]; + if (token) { + await browser.storage.local.set({ accessToken: token }); + console.log("Token récupéré et stocké :", token); + alert("Connexion réussie !"); + updateContextMenu(); + } else { + console.error("Token non trouvé sur la page Prisms."); + } + }); + } catch (error) { + console.error("Erreur lors de la récupération du token :", error); + } + } +}, { url: [{ hostContains: "prisms.lezinter.net" }] }); + +// === 6. Déconnexion === +async function disconnectFromLexicalDB() { + await browser.storage.local.remove("accessToken"); + console.log("Token supprimé, déconnexion réussie."); + alert("Déconnexion réussie."); + updateContextMenu(); +} + +// === 7. Vérifier si l'utilisateur est connecté === +async function isUserConnected() { + const result = await browser.storage.local.get("accessToken"); + return result.accessToken !== undefined; +} + +// === 8. Mise à jour dynamique du menu contextuel === +browser.runtime.onStartup.addListener(() => { + updateContextMenu(); +}); + +async function updateContextMenu() { + const isConnected = await isUserConnected(); + browser.contextMenus.update("toggle_connection", { + title: isConnected ? "Se déconnecter de la base lexicale" : "Se connecter à la base lexicale" + }); +} + +// === 9. Rafraîchissement périodique du token (désactivé) === +function refreshToken() { + console.warn("Aucune API de rafraîchissement disponible. Rafraîchissement désactivé."); +} + +setInterval(() => { + refreshToken(); +}, 15 * 60 * 1000); // Désactivé faute d'API de rafraîchissement diff --git a/menu_extension/login.html b/menu_extension/login.html new file mode 100644 index 0000000000000000000000000000000000000000..1f537473fb5d30a313f9da4f237993aa9450cdd5 --- /dev/null +++ b/menu_extension/login.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="UTF-8"> + <title>Connexion à BaLex</title> + <style> + body { + background-color: #323046; + color: white; + font-family: Arial, sans-serif; + text-align: center; + padding-top: 50px; + } + input { + width: 80%; + padding: 10px; + margin: 10px 0; + } + button { + padding: 10px 20px; + background-color: #94608a; + color: white; + border: none; + cursor: pointer; + } + </style> +</head> +<body> + <h2>Connexion à BaLex</h2> + <input type="text" id="username" placeholder="Nom d'utilisateur"><br> + <input type="password" id="password" placeholder="Mot de passe"><br> + <button id="loginButton">Se connecter</button> + + <script src="login.js"></script> +</body> +</html> diff --git a/menu_extension/login.js b/menu_extension/login.js new file mode 100644 index 0000000000000000000000000000000000000000..04a877695d80c75da55a033587f2aac5bfc3cf7c --- /dev/null +++ b/menu_extension/login.js @@ -0,0 +1,36 @@ +document.getElementById('loginButton').addEventListener('click', async () => { + const username = document.getElementById('username').value; + const password = document.getElementById('password').value; + + if (username && password) { + const apiUrl = "https://babalex.lezinter.net/login"; + + try { + const response = await fetch(apiUrl, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ username, password }) + }); + + const data = await response.json(); + if (data.accessToken && data.refreshToken) { + await browser.storage.local.set({ + accessToken: data.accessToken, + refreshToken: data.refreshToken + }); + alert("Connexion réussie !"); + window.close(); // Ferme la fenêtre de connexion + } else { + alert("Identifiants incorrects."); + } + } catch (error) { + console.error("Erreur lors de la connexion :", error); + alert("Erreur de connexion."); + } + } else { + alert("Veuillez remplir tous les champs."); + } + }); + \ No newline at end of file diff --git a/menu_extension/manifest.json b/menu_extension/manifest.json index 7be7bf3f75914108f260cc275db29310448cec70..b36ec6cbc65f6a2aa18394ccb1b7de2835223131 100644 --- a/menu_extension/manifest.json +++ b/menu_extension/manifest.json @@ -2,12 +2,16 @@ "manifest_version": 2, "name": "ff2BaLex", "version": "1.0", - "description": "Extension Firefox avec barre latérale.", + "description": "Extension Firefox avec paramètres personnalisés.", "permissions": [ - "storage", - "activeTab", - "https://fr.wiktionary.org/*" - ], + "storage", + "activeTab", + "tabs", + "contextMenus", + "webNavigation", + "scripting", + "*://babalex.lezinter.net/*", + "*://prisms.lezinter.net/*"], "background": { "scripts": ["menu_extension/background.js"], "persistent": true diff --git a/menu_extension/options.js b/menu_extension/options.js index e80617fb5ca83a8a6b9919124fe95147d4dbf3aa..cbfd4cfcb2274d8f74445918a52f9184b23e093a 100644 --- a/menu_extension/options.js +++ b/menu_extension/options.js @@ -1,18 +1,23 @@ -document.getElementById("connectBtn").addEventListener("click", () => { - alert("Fonctionnalité de connexion non encore implémentée."); - }); - - document.getElementById("toggleExtensionBtn").addEventListener("click", async () => { - const { extensionActive } = await browser.storage.local.get("extensionActive"); - const newState = !extensionActive; - await browser.storage.local.set({ extensionActive: newState }); - alert(`Extension ${newState ? "activée" : "désactivée"}.`); - }); - - document.getElementById("toggleStatsBtn").addEventListener("click", async () => { - const { statsActive } = await browser.storage.local.get("statsActive"); - const newState = !statsActive; - await browser.storage.local.set({ statsActive: newState }); - alert(`Statistiques ${newState ? "activées" : "désactivées"}.`); - }); +document.getElementById('connectBtn').addEventListener('click', () => { + browser.runtime.sendMessage({ action: "openLoginPage" }); +}); + +document.getElementById('disconnectBtn').addEventListener('click', async () => { + await browser.storage.local.remove(["accessToken", "refreshToken"]); + alert("Déconnexion réussie."); +}); +document.getElementById("toggleExtensionBtn").addEventListener("click", async () => { + const { extensionActive } = await browser.storage.local.get("extensionActive"); + const newState = !extensionActive; + await browser.storage.local.set({ extensionActive: newState }); + alert(`Extension ${newState ? "activée" : "désactivée"}.`); +}); + +document.getElementById("toggleStatsBtn").addEventListener("click", async () => { + const { statsActive } = await browser.storage.local.get("statsActive"); + const newState = !statsActive; + await browser.storage.local.set({ statsActive: newState }); + alert(`Statistiques ${newState ? "activées" : "désactivées"}.`); +}); + diff --git a/menu_extension/popup.js b/menu_extension/popup.js index e80617fb5ca83a8a6b9919124fe95147d4dbf3aa..458e207b3e38b0c452426cdee2e3f93100c03ec4 100644 --- a/menu_extension/popup.js +++ b/menu_extension/popup.js @@ -1,18 +1,58 @@ +// === 1. Gestion du bouton unique Connexion/Déconnexion === +async function updateConnectionButton() { + const { accessToken } = await browser.storage.local.get("accessToken"); + const button = document.getElementById("connectBtn"); + + button.textContent = accessToken ? "Se déconnecter" : "Se connecter"; +} + +// Action au clic du bouton Connexion/Déconnexion document.getElementById("connectBtn").addEventListener("click", () => { - alert("Fonctionnalité de connexion non encore implémentée."); - }); - - document.getElementById("toggleExtensionBtn").addEventListener("click", async () => { - const { extensionActive } = await browser.storage.local.get("extensionActive"); - const newState = !extensionActive; - await browser.storage.local.set({ extensionActive: newState }); - alert(`Extension ${newState ? "activée" : "désactivée"}.`); - }); - - document.getElementById("toggleStatsBtn").addEventListener("click", async () => { - const { statsActive } = await browser.storage.local.get("statsActive"); - const newState = !statsActive; - await browser.storage.local.set({ statsActive: newState }); - alert(`Statistiques ${newState ? "activées" : "désactivées"}.`); - }); - + console.log("Redirection vers la page de connexion..."); + browser.runtime.sendMessage({ action: "connectToBaLex" }); +}); + +browser.runtime.onMessage.addListener((message) => { + if (message.action === "tokenSaved") { + alert("Connexion réussie !"); + } +}); + +// === 2. Activer/Désactiver l'extension === +document.getElementById("toggleExtensionBtn").addEventListener("click", async () => { + const { extensionActive } = await browser.storage.local.get("extensionActive"); + const newState = !extensionActive; + await browser.storage.local.set({ extensionActive: newState }); + alert(`Extension ${newState ? "activée" : "désactivée"}.`); +}); + +// === 3. Activer/Désactiver les statistiques === +document.getElementById("toggleStatsBtn").addEventListener("click", async () => { + const { statsActive } = await browser.storage.local.get("statsActive"); + const newState = !statsActive; + await browser.storage.local.set({ statsActive: newState }); + alert(`Statistiques ${newState ? "activées" : "désactivées"}.`); +}); + +// === 4. Mise à jour initiale du bouton Connexion/Déconnexion === +updateConnectionButton(); + +// Vérification pour le bouton de connexion +document.addEventListener("DOMContentLoaded", () => { + const connectBtn = document.getElementById("connectBtn"); + + if (connectBtn) { + connectBtn.addEventListener("click", async () => { + console.log("Clic détecté sur le bouton Connexion"); + try { + await browser.runtime.sendMessage({ action: "toggleConnection" }); + console.log("Message envoyé au background."); + } catch (error) { + console.error("Erreur lors de l'envoi du message :", error); + } + }); + } else { + console.error("Le bouton de connexion n'a pas été trouvé."); + } +}); + diff --git "a/s\303\251lection_recherche/.gitkeep" "b/s\303\251lection_recherche/.gitkeep" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/s\303\251lection_recherche/icons/border-48.png" "b/s\303\251lection_recherche/icons/border-48.png" new file mode 100644 index 0000000000000000000000000000000000000000..90687de26d71e91b7c82565772a7df470ae277a6 Binary files /dev/null and "b/s\303\251lection_recherche/icons/border-48.png" differ diff --git "a/s\303\251lection_recherche/icons/loupe-256.png" "b/s\303\251lection_recherche/icons/loupe-256.png" new file mode 100644 index 0000000000000000000000000000000000000000..a34fc08ba086b2dcd791fe7962ffb74e6b17203b Binary files /dev/null and "b/s\303\251lection_recherche/icons/loupe-256.png" differ diff --git "a/s\303\251lection_recherche/main.js" "b/s\303\251lection_recherche/main.js" new file mode 100644 index 0000000000000000000000000000000000000000..aaa3124a34ddde087bcf340311212be0f6c878cb --- /dev/null +++ "b/s\303\251lection_recherche/main.js" @@ -0,0 +1,193 @@ +// Création de la zone blanche initiale(prototype menu contextuel) +if (!document.getElementById('whiteBox')) { + // Création de la zone blanche + const whiteBox = document.createElement('div'); + whiteBox.id = 'whiteBox'; + + // Ajout de contenu dans la zone + whiteBox.innerHTML = '<p id="selectedWord"> Mot sélectionné </p>'; + + // Ajouter la zone au document + document.body.appendChild(whiteBox); +} + + + +// Variable globale pour stocker le token +let authToken = ''; + +// Fonction pour lire et afficher le contenu du fichier token +function readTokenFile() { + const tokenFilePath = browser.runtime.getURL('token.txt'); + console.log('Chemin du fichier token :', tokenFilePath); + + return fetch(tokenFilePath) + .then((response) => { + if (!response.ok) { + throw new Error(`Erreur lors de la lecture du fichier token : ${response.statusText}`); + } + return response.text(); + }) + .then((token) => { + console.log('Contenu du fichier token :', token); + authToken = token.trim(); // Stocke le token dans une variable globale + }) + .catch((error) => { + console.error('Erreur lors de la lecture du fichier token :', error); + }); +} + +// Appeler la fonction et attendre qu’elle soit terminée +readTokenFile().then(() => { + console.log("Le token est bien enregistré : ", authToken); +}); + + + +// Ecouteur de la sélection de texte +document.addEventListener('contextmenu', (event) => { + const selectedText = window.getSelection().toString().trim(); // Récupérer le texte sélectionné + + // SI on a du texte sélectionné, on modifie le contenu et affiche le bouton de recherche dans le lexique + if (selectedText) { + console.log("Texte sélectionné :", selectedText); + + // Modifier le contenu de la boîte blanche avec le texte sélectionné + const selectedWordElement = document.getElementById('selectedWord'); + if (selectedWordElement) { + selectedWordElement.textContent = selectedText; + } + + + + // Bouton de recherche dans le lexique perso + if (!document.getElementById('searchLexiconButton')) { + // Création du bouton "Rechercher dans le lexique" (lexique perso) + const searchLexiconButton = document.createElement('input'); + searchLexiconButton.id = 'searchLexiconButton'; + searchLexiconButton.type = 'button'; + searchLexiconButton.value = 'Rechercher dans le lexique personnel'; + searchLexiconButton.className = 'searchButton'; + + // Événement sur le bouton de recherche + searchLexiconButton.addEventListener('click', () => { + console.log("Recherche du mot dans le lexique:", selectedText); + searchInLexicon(selectedText); + }); + + // Ajout du bouton sous le texte + const whiteBox = document.getElementById('whiteBox'); + whiteBox.appendChild(searchLexiconButton); + } + + + + // Bouton de recherche requête sur le wiktionnaire + if (!document.getElementById('searchWikiButton')) { + // Création du bouton "Recherche sur le Wiktionnaire" + const searchWikiButton = document.createElement('input'); + searchWikiButton.id = 'searchWikiButton'; + searchWikiButton.type = 'button'; + searchWikiButton.value = 'Rechercher sur le Wiktionnaire'; + searchWikiButton.className = 'searchButton'; + + // // Évènement sur le bouton de recherche + searchWikiButton.addEventListener('click', () => { + console.log("Recherche du mot dans le Wiktionnaire:", selectedText); + searchInWiki(selectedText); + }); + + // Ajout du bouton sous le texte + const whiteBox = document.getElementById('whiteBox'); + whiteBox.appendChild(searchWikiButton); + } + } + + + +// Définition des fonctions APPELS API + +// Fonction pour rechercher dans le lexique personnel (français) +function searchInLexicon(selectedText) { + const lexiconsApiUrl = 'https://babalex.lezinter.net/api/user/lexicons'; + + if (!authToken) { + console.error('Token non disponible.'); + return; + } + + //Récupérer les lexiques de l'utilisateur + fetch(lexiconsApiUrl, { + method: 'GET', + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Content-Type': 'application/json', + }, + }) + .then((response) => { + if (!response.ok) { + throw new Error(`Erreur lors de la récupération des lexiques : ${response.statusText}`); + } + return response.json(); + }) + .then((lexicons) => { + console.log('Lexiques de l’utilisateur :', lexicons); + + //todo : Utiliser la variable "lang" pour chercher le mot dans le bon lexique + + // Rechercher l'ID du lexique français + const frenchLexicon = lexicons.find((lexicon) => lexicon.language === 'fr'); + + if (!frenchLexicon) { + throw new Error('Aucun lexique pour la langue française trouvé.'); + } + + const idLexicon = frenchLexicon.id; + console.log('ID du lexique français :', idLexicon); + + //Récupérer les graphies du lexique français + const entriesApiUrl = `https://babalex.lezinter.net/api/lexicon/entries/${idLexicon}`; + + return fetch(entriesApiUrl, { + method: 'GET', + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Content-Type': 'application/json', + }, + }); + }) + .then((response) => { + if (!response.ok) { + throw new Error(`Erreur lors de la récupération des graphies : ${response.statusText}`); + } + return response.json(); + }) + .then((entries) => { + console.log('Graphies dans le lexique français :', entries); + + //Comparer les graphies avec le mot sélectionné + let isWordPresent = false; + for (const entry of entries) { + console.log("Mots dans le lexique :", entry); + if (entry.graphy === selectedText) { + isWordPresent = true; + break; + } + } + + if (isWordPresent) { + alert(`Mot présent dans le lexique : "${selectedText}"`); + } else { + alert(`Le mot "${selectedText}" n'est pas présent dans le lexique.`); + } + }) + .catch((error) => { + console.error('Erreur lors de la requête API :', error); + }); +} + +//console.log('Token utilisé :', authToken); + + +}); + diff --git "a/s\303\251lection_recherche/manifest.json" "b/s\303\251lection_recherche/manifest.json" new file mode 100644 index 0000000000000000000000000000000000000000..163425207d2c6afcdbb96831e790dc50032ff4cd --- /dev/null +++ "b/s\303\251lection_recherche/manifest.json" @@ -0,0 +1,29 @@ +{ + "manifest_version": 2, + "name": "Rechercher si le mot est dans le lexique", + "version": "1.0", + "description": "Sélectionne un mot et affiche le mot sélectionné dans la zone pour vérifier s'il est dans un lexique", + "icons": { + "48": "icons/loupe-256.png" + }, + "permissions": [ + "https://babalex.lezinter.net/*", + "activeTab"], + "content_scripts": [ + { + "matches": ["<all_urls>"], + "js": ["main.js"], + "css": ["style.css"] + } + ], + "web_accessible_resources": [ + "token", + "token.txt" + ], + + "browser_action": { + "default_icon": "icons/loupe-256.png", + "default_title": "Recherche du mot" + } + } + \ No newline at end of file diff --git "a/s\303\251lection_recherche/style.css" "b/s\303\251lection_recherche/style.css" new file mode 100644 index 0000000000000000000000000000000000000000..60e994e0c3e489b7981b06a20af04964cd8c49b2 --- /dev/null +++ "b/s\303\251lection_recherche/style.css" @@ -0,0 +1,37 @@ +#whiteBox { + position: fixed; + top: 10px; + right: 10px; + background-color: rgb(255, 255, 255); + border: 5px solid rgb(0, 0, 0); + padding: 10px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + z-index: 10000; +} + +#selectedWord { + margin: 0; + font-size: 14px; + line-height: 1.5; + color: black; + font-weight: bold; +} + +/* Style des boutons */ +.searchButton { + margin-top: 10px; + padding: 8px 12px; + background-color: #4CAF50; + color: white; + border: none; + cursor: pointer; + font-size: 14px; + border-radius: 5px; + display: block; + width: 100%; +} + +.searchButton:hover { + background-color: #45a049; +} + diff --git "a/s\303\251lection_recherche/token.txt" "b/s\303\251lection_recherche/token.txt" new file mode 100644 index 0000000000000000000000000000000000000000..d1a05116c9ea5c3172fd4bcb43d453c48f7a5ce8 --- /dev/null +++ "b/s\303\251lection_recherche/token.txt" @@ -0,0 +1 @@ +eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmlzbXMiLCJqdGkiOiJkYWU4Mzc5OGJkMTk1Y2M1NzIyMGM5MTZiZDBjYjNjZDkwNjQ0NzYyNjViNWY4YzgwOWYwYTBkNWQyYzFlNjNhNTk1M2ZmZWM2ZmEzNWQ0YyIsImlhdCI6MTczNjk3Mjk4OS4wMjk2MiwibmJmIjoxNzM2OTcyOTg5LjAyOTYzMiwiZXhwIjoxNzM2OTc2NTg5LjAwNDQzMiwic3ViIjoiYXNvdW5hbGF0aCIsInNjb3BlcyI6WyJlbWFpbCIsInBzZXVkbyIsInV1aWQiXSwia2lkIjoiMSIsImN1c3RvbSI6eyJmb28iOiJiYXIifX0.AKd1wP8mCWSkZ9iPhuyDxb5OEeLf6pyu3b4iv4yDOYqzjEXEm3He2umAYHvvTLEt701NW_6_6uzzGKt8tm-sqsGp_sff6LEBZE9j2108nonBtYS6Hi4LtSTPS9Ls9DeKvQ_mRxpT2ENOF7Lnfgy2a7PHIYrxfV3Q4jc_1LE9K4rStJdwX-UjSyzdJzmlpJ651knsg32yLDAUWzgcfyf4Vn41vqMnwn3gXi3Yez4biVM1cxOX9iwL8QdIDiPlcF83KOULrtvErLSlWzKgmmwrT8b1o2PqxEdhbehSgkpiyAU9ewmwVoZSXqql4ITg9tzOvUcLR4qyJGceAnLrNJdRnw \ No newline at end of file