mirror of
https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
synced 2025-09-07 09:05:57 +02:00
updated the whole structure
This commit is contained in:
162
app-rappaurio/server/controllers/auth.js
Normal file
162
app-rappaurio/server/controllers/auth.js
Normal file
@@ -0,0 +1,162 @@
|
||||
const mysql = require('mysql');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const { promisify } = require('util');
|
||||
|
||||
const db = mysql.createConnection({
|
||||
host: process.env.DATABASE_HOST,
|
||||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
database: process.env.DATABASE
|
||||
});
|
||||
|
||||
exports.login = async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
if (!email || !password) {
|
||||
return res.status(400).render('contains/connexion', {
|
||||
message: 'Veuillez entrer un email et un mot de passe'
|
||||
})
|
||||
}
|
||||
|
||||
db.query('SELECT * FROM users WHERE email = ?', [email], async (error, result) => {
|
||||
console.log(result)
|
||||
if (!result || result.length == 0 || !(await bcrypt.compare(password, result[0].password))) {
|
||||
res.status(401).render('contains/connexion', {
|
||||
message: 'Email ou Mot de passe incorrect'
|
||||
})
|
||||
}
|
||||
else {
|
||||
const id = result[0].id;
|
||||
// creating a token
|
||||
const token = jwt.sign({ id: id }, process.env.JWT_SECRET, {
|
||||
expiresIn: process.env.JWT_EXPIRES_IN
|
||||
});
|
||||
|
||||
console.log("The token is : " + token);
|
||||
|
||||
// when does our token expires
|
||||
const cookieOptions = {
|
||||
expires: new Date(
|
||||
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 * 60 * 1000
|
||||
),
|
||||
// just to prevent if someone is not messing with our cookies
|
||||
httpOnly: true
|
||||
}
|
||||
// we can use any name here in res.cookie(name , token , cookieoptions ) ;
|
||||
// after a user is loged in we put cookie in browser
|
||||
res.cookie('jwt', token, cookieOptions);
|
||||
res.status(200).redirect('/');
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports.register = (req, res) => {
|
||||
console.log(req.body);
|
||||
|
||||
// de-structuring in javaScript....
|
||||
const { name, email, password } = req.body;
|
||||
|
||||
db.query('SELECT email FROM users WHERE email = ?', [email], async (error, result) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
if (result.length > 0) {
|
||||
return res.render('contains/inscription', {
|
||||
message: 'Cet email est déjà utilisé'
|
||||
})
|
||||
}
|
||||
|
||||
let hashedPassword = await bcrypt.hash(password, 8);
|
||||
|
||||
console.log(hashedPassword);
|
||||
|
||||
db.query('INSERT INTO users SET ?', { name: name, email: email, password: hashedPassword }, (error, result) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
else {
|
||||
console.log(result);
|
||||
|
||||
db.query('SELECT * FROM users WHERE email = ?', [email], async (error, result) => {
|
||||
console.log(result)
|
||||
|
||||
const id = result[0].id;
|
||||
// creating a token
|
||||
const token = jwt.sign({ id: id }, process.env.JWT_SECRET, {
|
||||
expiresIn: process.env.JWT_EXPIRES_IN
|
||||
});
|
||||
|
||||
console.log("The token is : " + token);
|
||||
|
||||
// when does our token expires
|
||||
const cookieOptions = {
|
||||
expires: new Date(
|
||||
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 * 60 * 1000
|
||||
),
|
||||
// just to prevent if someone is not messing with our cookies
|
||||
httpOnly: true
|
||||
}
|
||||
// we can use any name here in res.cookie(name , token , cookieoptions ) ;
|
||||
// after a user is loged in we put cookie in browser
|
||||
res.cookie('jwt', token, cookieOptions);
|
||||
res.status(200).redirect('/');
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
exports.isLoggedIn = async (req, res, next) => {
|
||||
|
||||
console.log(req.cookies);
|
||||
if (req.cookies.jwt) {
|
||||
try {
|
||||
// step 1 : Verify the token
|
||||
const decoded = await promisify(jwt.verify)(
|
||||
req.cookies.jwt,
|
||||
process.env.JWT_SECRET
|
||||
)
|
||||
|
||||
//console.log(decoded);
|
||||
|
||||
const userId = decoded.id;
|
||||
req.userId = userId;
|
||||
|
||||
// step 2: check if the user still exists
|
||||
db.query('SELECT * FROM users WHERE id = ?', [decoded.id], (error, result) => {
|
||||
console.log(result);
|
||||
|
||||
if (!result) {
|
||||
return next();
|
||||
}
|
||||
req.user = result[0];
|
||||
return next();
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.logout = async (req, res) => {
|
||||
res.cookie('jwt', 'déconnecté', {
|
||||
expires: new Date(Date.now() + 2 * 1000),
|
||||
httpOnly: true
|
||||
});
|
||||
res.status(200).redirect('/');
|
||||
}
|
21
app-rappaurio/server/controllers/historiqueController.js
Normal file
21
app-rappaurio/server/controllers/historiqueController.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const mysql = require('mysql');
|
||||
|
||||
// Créez une connexion à la base de données
|
||||
const db = mysql.createConnection({
|
||||
host: process.env.DATABASE_HOST,
|
||||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
database: process.env.DATABASE
|
||||
});
|
||||
|
||||
// Fonction pour récupérer les données depuis la base de données
|
||||
exports.getHistoriqueData = (userId, callback) => {
|
||||
db.query('SELECT * FROM search WHERE id = ? LIMIT 50', [userId], (error, results) => {
|
||||
if (error) {
|
||||
console.error('Erreur lors de la récupération des données depuis la base de données :', error);
|
||||
callback(error, null);
|
||||
} else {
|
||||
callback(null, results);
|
||||
}
|
||||
});
|
||||
};
|
27
app-rappaurio/server/controllers/searchController.js
Normal file
27
app-rappaurio/server/controllers/searchController.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// searchController.js
|
||||
|
||||
const mysql = require('mysql');
|
||||
|
||||
// Créez une connexion à la base de données
|
||||
const db = mysql.createConnection({
|
||||
host: process.env.DATABASE_HOST,
|
||||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
database: process.env.DATABASE
|
||||
});
|
||||
|
||||
// Fonction pour insérer les données de recherche dans la base de données
|
||||
exports.insertSearchData = (userId, articleTitle1, articleTitle2, callback) => {
|
||||
db.query('INSERT INTO search (id, article1, article2) VALUES (?, ?, ?)', [userId, articleTitle1, articleTitle2], (error, result) => {
|
||||
if (error) {
|
||||
console.error('Erreur lors de l\'insertion des données dans la base de données :', error);
|
||||
// Vous pouvez gérer l'erreur en appelant le callback avec l'erreur
|
||||
callback(error, null);
|
||||
} else {
|
||||
// Les données ont été insérées avec succès
|
||||
console.log('Données insérées avec succès dans la base de données.');
|
||||
// Appelez le callback avec succès
|
||||
callback(null, result);
|
||||
}
|
||||
});
|
||||
};
|
165
app-rappaurio/server/functions/compare.js
Normal file
165
app-rappaurio/server/functions/compare.js
Normal file
@@ -0,0 +1,165 @@
|
||||
const Wikiapi = require('wikiapi');
|
||||
const wiki = new Wikiapi('fr');
|
||||
const axios = require('axios');
|
||||
|
||||
|
||||
// == Functions
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchArticleInfoFromAPI
|
||||
};
|
14
app-rappaurio/server/routes/auth.js
Normal file
14
app-rappaurio/server/routes/auth.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const express = require('express');
|
||||
const authController = require('../controllers/auth');
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
|
||||
router.post('/inscription' , authController.register);
|
||||
|
||||
router.post('/connexion' , authController.login);
|
||||
|
||||
router.get('/deconnexion' , authController.logout)
|
||||
|
||||
|
||||
module.exports = router ;
|
83
app-rappaurio/server/routes/index.js
Normal file
83
app-rappaurio/server/routes/index.js
Normal file
@@ -0,0 +1,83 @@
|
||||
var express = require('express');
|
||||
const authController = require('../controllers/auth')
|
||||
const searchController = require('../controllers/searchController');
|
||||
const historiqueController = require('../controllers/historiqueController');
|
||||
const { fetchArticleInfoFromAPI } = require('../functions/compare');
|
||||
|
||||
var router = express.Router();
|
||||
|
||||
/* GET home page. */
|
||||
router.get('/', authController.isLoggedIn, (req, res, next) => {
|
||||
res.render('contains/index', { user_details: req.user });
|
||||
});
|
||||
|
||||
|
||||
// inscription page
|
||||
router.get('/inscription', (req, res) => {
|
||||
res.render('contains/inscription')
|
||||
});
|
||||
|
||||
router.get('/connexion', (req, res) => {
|
||||
res.render('contains/connexion')
|
||||
});
|
||||
|
||||
|
||||
router.get('/historique', authController.isLoggedIn, (req, res) => {
|
||||
console.log(req.user);
|
||||
|
||||
if (req.user) {
|
||||
const userId = req.user.id;
|
||||
historiqueController.getHistoriqueData(userId, (error, historiqueData) => {
|
||||
if (error) {
|
||||
console.error('Erreur lors de la récupération des données depuis la base de données :', error);
|
||||
res.status(500).json({ error: 'Une erreur s\'est produite lors de la récupération des données.' });
|
||||
} else {
|
||||
|
||||
res.render('contains/historique', {
|
||||
user_details: req.user,
|
||||
historiqueData: historiqueData
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.redirect('/connexion');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Send search for articles
|
||||
router.post('/search', authController.isLoggedIn, 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);
|
||||
|
||||
// Récupérez l'ID de l'utilisateur
|
||||
const userId = req.userId;
|
||||
|
||||
// Utilisez la fonction du contrôleur pour insérer les données
|
||||
|
||||
if (userId) {
|
||||
searchController.insertSearchData(userId, articleTitle1, articleTitle2, (error, result) => {
|
||||
if (error) {
|
||||
console.error('Erreur lors de l\'insertion des données dans la base de données :', error);
|
||||
res.status(500).json({ error: 'Une erreur s\'est produite lors de l\'enregistrement des données.' });
|
||||
} else {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 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.' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
Reference in New Issue
Block a user