2023-09-27 01:10:25 +02:00

407 lines
16 KiB
JavaScript

const express = require('express');
const exphbs = require('express-handlebars');
const session = require('express-session');
const MySQLStore = require('connect-mysql')(session);
const path = require('path');
const cookieParser = require('cookie-parser');
const axios = require('axios');
const bodyParser = require('body-parser');
const Wikiapi = require('wikiapi');
const wiki = new Wikiapi('fr');
const app = express();
const morgan = require('morgan');
app.use(morgan('dev'));
const mysql = require('mysql2');
const dotenv = require('dotenv');
const jwt = require('jsonwebtoken');
// get config vars
dotenv.config();
// Configuration du moteur de modèle Handlebars
app.engine('.hbs', exphbs.engine({ extname: '.hbs' }));
app.set('view engine', '.hbs');
app.set('views', path.join(__dirname, 'views'));
// Middleware pour servir les fichiers statiques
app.use(express.static(path.join(__dirname, '/')));
// Utilisation de cookie-parser comme middleware
app.use(cookieParser());
// Middleware body-parser pour traiter les données POST du formulaire
app.use(bodyParser.urlencoded({ extended: false }));
// ============================= FONCTIONS ========================================================
// Génère un token
function generateAccessToken(username) {
return jwt.sign(username, process.env.TOKEN_SECRET, { expiresIn: '1800s' });
}
// Fonction de nettoyage personnalisée (pour infobox)
function cleanInfoboxText(text) {
// Supprimer les balises HTML
const cleanedText = text.replace(/<\/?[^>]+(>|$)/g, "");
// Supprimer les caractères '{' et '}'
const cleanedTextWithoutBraces = cleanedText.replace(/[{}]/g, "");
// Supprimer le caractère '|'
const cleanedTextWithoutPipe = cleanedTextWithoutBraces.replace(/\|/g, "");
// Supprimer les caractères '[' et ']'
const finalText = cleanedTextWithoutPipe.replace(/[\[\]]/g, "");
return finalText.trim();
}
// Fonction pour récupérer les informations d'un article depuis l'API MediaWiki
async function fetchArticleInfoFromAPI(articleTitle) {
try {
// Définir les paramètres de la requête pour obtenir les suggestions de titre
const suggestionParams = new URLSearchParams({
action: 'opensearch',
search: articleTitle,
format: 'json',
});
// Effectuer la requête GET pour obtenir les suggestions de titre
const suggestionResponse = await axios.get(`https://fr.wikipedia.org/w/api.php?${suggestionParams.toString()}`);
const suggestionData = suggestionResponse.data;
// Vérifier s'il y a des suggestions de titre
if (Array.isArray(suggestionData[1]) && suggestionData[1].length > 0) {
// Utiliser le premier titre suggéré comme titre de l'article
articleTitle = suggestionData[1][0];
}
// Répéter la requête pour obtenir les informations de l'article avec le titre corrigé ou suggéré
const params = new URLSearchParams({
action: 'query',
titles: articleTitle,
format: 'json',
prop: 'extracts|info|revisions|pageimages', // Ajoutez 'pageimages' pour obtenir les informations sur l'image
inprop: 'url',
explaintext: true,
rvprop: 'timestamp|user|size|ids',
rvlimit: 1,
piprop: 'original', // Spécifiez 'original' pour obtenir l'URL de l'image originale
});
// Effectuer la requête GET à l'API MediaWiki
const response = await axios.get(`https://fr.wikipedia.org/w/api.php?${params.toString()}`);
const data = response.data;
// ==== RECHERCHE INFOBOX ====
let infobox = {};
// Vérifiez si articleTitle est défini et non vide
if (articleTitle) {
const page_data = await wiki.page(articleTitle);
const parsed = page_data.parse();
// Filtre des données compliquée à représentée
const variablesExclues = ['image', 'blason', 'drapeau', 'logo', 'légende', 'carte', 'légende-carte', '_', 'statut', 1, 2, 3, 4, 5, 6, 7, 8, 9];
// Lire les modèles Infobox, les convertir en JSON.
parsed.each('template', (template_token) => {
if (template_token.name.startsWith('Infobox')) {
const parameters = template_token.parameters;
for (const key of Object.keys(parameters)) {
const value = parameters[key];
if (value !== '' && !variablesExclues.some(excluded => key.includes(excluded))) {
infobox[key] = cleanInfoboxText(value.toString()); // Appliquer la fonction de nettoyage ici
}
}
return parsed.each.exit;
}
});
// Vérifiez si l'infobox est vide
if (Object.keys(infobox).length === 0) {
console.log("Warning : Pas d'infobox");
infobox = {
Erreur: "Pas d'infobox sur wikipédia"
};
}
} else {
return null;
}
// ------------------------------------------------------------
// Vérifier si 'query' existe dans les données
if (data.query) {
// Obtenir la première page (il peut y avoir plusieurs résultats, nous prenons le premier)
const page = Object.values(data.query.pages)[0];
if (page.missing !== undefined) {
console.log(`Warning : l'article "${articleTitle}" n'a pas été trouvé.`);
return null;
} else {
// Fonction pour limiter le texte à 300 caractères et s'arrêter au dernier point
function limitTextTo300Chars(text) {
if (text.length <= 300) {
// Si le texte est déjà inférieur ou égal à 300 caractères, retournez-le tel quel
return text;
} else {
// Trouvez le dernier point dans les 300 premiers caractères
const truncatedText = text.substring(0, 300);
const lastPeriodIndex = truncatedText.lastIndexOf('.');
if (lastPeriodIndex !== -1) {
// S'il y a un point dans les 300 premiers caractères, coupez le texte jusqu'à ce point
return truncatedText.substring(0, lastPeriodIndex + 1);
} else {
// S'il n'y a pas de point, retournez simplement les 200 premiers caractères
return truncatedText;
}
}
}
// Extraire les informations
const articleInfo = {
url: page.fullurl,
title: page.title,
extract: page.extract ? limitTextTo300Chars(page.extract) : 'Non disponible',
lastEdit: page.revisions ? new Date(page.revisions[0].timestamp).toLocaleString() : 'Non disponible',
numRevisions: page.revisions ? page.revisions[0].revid : 'Non disponible',
pageSize: page.revisions ? page.revisions[0].size : 'Non disponible',
firstRevisionUser: page.revisions ? page.revisions[0].user : 'Non disponible',
latestRevisionId: page.revisions ? page.revisions[0].revid : 'Non disponible',
pageId: page.pageid ? page.pageid : 'Non disponible',
latestVersion: page.revisions ? page.revisions[0].parentid : 'Non disponible',
wordCount: page.extract ? page.extract.split(/\s+/).length : 'Non disponible',
charCount: page.extract ? page.extract.length : 'Non disponible',
lastContributor: page.revisions ? page.revisions[0].user : 'Non disponible',
image: page.original ? page.original.source : 'Non disponible',
infobox,
};
return articleInfo;
}
} else {
console.log(`Warning : l'article "${articleTitle}" n'a pas été trouvé.`);
return null;
}
} catch (error) {
console.error('Erreur : lors de la récupération des informations depuis l\'API :', error);
return null;
}
}
// ============================= ROUTES ===========================================================
// Index
app.get('/', async (req, res) => {
// Renvoyez la page index avec les informations de l'article et de l'infobox
res.render('contains/index', { pageTitle: 'Accueil' });
});
// Comparaison d'articles
app.post('/search', async (req, res) => {
try {
// Récupérez les données du formulaire depuis req.body
const articleTitle1 = req.body.articleTitle1;
const articleTitle2 = req.body.articleTitle2;
// Utilisez la fonction pour récupérer les informations des articles
const articleInfo1 = await fetchArticleInfoFromAPI(articleTitle1);
const articleInfo2 = await fetchArticleInfoFromAPI(articleTitle2);
// Renvoyez la réponse au format JSON
res.json({ articleInfo1, articleInfo2 });
} catch (error) {
console.error('Erreur lors de la recherche d\'informations sur les articles :', error);
res.status(500).json({ error: 'Une erreur s\'est produite lors de la recherche d\'informations sur les articles.' });
}
});
// Connexion
app.get('/connexion', (req, res) => {
res.render('contains/signin', { pageTitle: 'Connexion' });
});
app.post('/connexion', async (req, res) => {
try {
// Récupérez les données du formulaire depuis req.body
const ClientEmail = req.body.email;
const ClientPassword = req.body.password;
//console.log("Succès : " + ClientEmail + " " + ClientPassword);
// config de la connexion à la BDD
var connection = mysql.createConnection({
host: 'localhost',
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DB
});
// Connexion à la BDD
connection.connect(function (err) {
if (err) {
console.error('Erreur de connexion à la base de données :', err);
throw err;
} else {
console.log('Connecté à la base de données MariaDB !');
// Requète BDD qui recupère les données
connection.query("SELECT * FROM User", (err, results, fields) => {
if (err) {
console.error('Erreur lors de l\'exécution de la requête :', err);
throw err;
}
// Vérification si l'utilisateur est correct
let ValidationConnection = '';
for (const row of results) {
const BddEmail = row.email;
const BddPassword = row.password;
if (BddEmail === ClientEmail && BddPassword === ClientPassword) {
ValidationConnection = 'OK';
break; // Sort de la boucle dès qu'il y a une correspondance
}
}
if (ValidationConnection !== 'OK') {
ValidationConnection = 'WrongID';
}
else {
const token = generateAccessToken({ username: ClientEmail });
//console.log(token);
res.json({token});
connection.query("INSERT INTO sessions (session_id, email) VALUES (?, ?)", [token, ClientEmail], (err, results, fields) => {
if (err) {
console.error('Erreur lors de l\'exécution de la requête :', err);
throw err;
}
});
}
// Fermeture de la BDD
connection.end(function (err) {
if (err) {
console.error('Erreur lors de la fermeture de la connexion :', err);
} else {
console.log('Connexion à la base de données fermée.');
}
});
});
}
});
} catch (error) {
console.error('Erreur lors de la tentative de connexion :', error);
}
});
// Inscription
app.get('/inscription', (req, res) => {
res.render('contains/signup', { pageTitle: 'Inscription' });
});
app.post('/inscription', async (req, res) => {
try {
// Récupérez les données du formulaire depuis req.body
const name = req.body.name;
const ClientEmail = req.body.email;
const ClientPassword = req.body.password;
// config de la connexion à la BDD
var connection = mysql.createConnection({
host: 'localhost',
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DB
});
// Connexion à la BDD
connection.connect(function (err) {
if (err) {
console.error('Erreur de connexion à la base de données :', err);
} else {
console.log('Connecté à la base de données MariaDB !');
// Requette BDD qui vérifie les adresses mails
connection.query("SELECT email FROM User", (err, results, fields) => {
if (err) {
console.error('Erreur lors de l\'exécution de la requête :', err);
throw err;
}
let ValidationInscription = '';
for (const row of results) {
const BddEmail = row.email;
if (BddEmail === ClientEmail) {
ValidationInscription = 'Doublon';
break; // Sort de la boucle dès qu'il y a une correspondance
}
}
if (ValidationInscription !== 'Doublon') {
// Requète BDD qui insère les données
connection.query("INSERT INTO User (name, email, password) VALUES (?, ?, ?)", [name, ClientEmail, ClientPassword], (err, results, fields) => {
if (err) {
console.error('Erreur lors de l\'exécution de la requête :', err);
throw err;
}
});
ValidationInscription = 'OK';
}
console.log(ValidationInscription);
// Fermeture de la BDD
connection.end(function (err) {
if (err) {
console.error('Erreur lors de la fermeture de la connexion :', err);
} else {
console.log('Connexion à la base de données fermée.');
}
});
});
}
});
} catch (error) {
console.error("Erreur lors de la tentative d'inscription :", error);
}
});
// Historique
app.get('/historique', (req, res) => {
res.render('contains/historique', { pageTitle: 'Historique' });
});
// 404
app.use((req, res, next) => {
res.status(404).render('contains/404', { title: 'Erreur 404' });
});
// ============================= PORT ============================================================
// Port
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Info : le serveur est en écoute sur le port ${PORT}`);
});