diff --git a/app.js b/app.js index 747bc34ab84c0a7d1cd09ee1f29cce346cce53fd..39038244d4219effcf13ec8813213b1519bbed64 100644 --- a/app.js +++ b/app.js @@ -5,7 +5,7 @@ const db = require('./db/Database.js'); const auth = require('./controller/AuthController.js'); const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); -const bcrypt = require('bcrypt'); +const { createHash, randomBytes } = require('crypto'); @@ -33,35 +33,108 @@ app.get("/", defaut).get("/accueil",defaut); app.get("/db/:collection", collection).get("/db", dbAdmin); app.get("/login", (req, res) => res.render("login")).post("/login", postLogin); + + //route pour creation compte app.get("/signup" , (req ,res)=>{ res.render("signup", { title: 'Inscription' }); + }); -app.all("*", (req, res) => res.status(404).send("<h1>Il semblerait que cette page n'existe pas.</h1>")); - - +function generateRandomSalt() { + return randomBytes(16).toString('hex'); +} -const saltRounds = 10; app.post('/signup', async (req, res) => { try { - // Récupère les données du formulaire - const { username, email, password } = req.body; + const { username, email, password } = req.body; + + // Générer un sel aléatoire + const salt = generateRandomSalt(); - // hasher le passWord - const hashedPassword = await bcrypt.hash(password, saltRounds); + // Concaténer le mot de passe avec le sel et hacher le tout + const passwordToHash = salt + password; + const hashedPassword = createHash('sha256').update(passwordToHash).digest('hex'); - // Insère les données dans la base de données - await db.insert('users', { username, email, password:hashedPassword }); + // Insérer les données dans la base de données avec le sel et le mot de passe haché + await db.insert('users', { username, email, salt, password: hashedPassword }); - res.send('Inscription réussie'); + // Rediriger vers la page de connexion après l'inscription + res.redirect('/login'); } catch (error) { console.error(error); - res.status(500).send('Erreur lors de l\'inscription'); + res.status(500).send("Erreur lors de l'inscription"); + } +}); + + +// route pour logout +app.post('/logout', function(req, res) { + res.clearCookie('accessToken'); // Assurez-vous que le nom du cookie est correct + res.redirect('/accueil'); +}); + + +//route pour document +app.get("/document", (req, res) => { + if (!res.locals.user) { + return res.redirect("/login"); // Redirige vers la page de connexion si l'utilisateur n'est pas connecté + } + res.render("document", { title: 'Créer un Document' }); +}); + +app.get("/mydocuments", (req, res) => { + if (!res.locals.user) { + return res.redirect("/login"); // Redirige vers la page de connexion si l'utilisateur n'est pas connecté } + res.render("mydocuments", { title: 'Mes Documents' }); }); +// route pour la sauvegarde de documents +app.post('/document/save', async (req, res) => { + try { + const documentData = req.body; + const savedDocumentId = await db.saveDocument(documentData); + + res.status(200).json({ message: 'Document sauvegardé avec succès', documentId: savedDocumentId }); + } catch (error) { + console.error('Erreur lors de la sauvegarde du document:', error); + res.status(500).json({ message: 'Erreur lors de la sauvegarde du document' }); + } +}); + + + +// route pour affichier mes docs +app.get("/mes-documents", async (req, res) => { + if (!res.locals.user) { + return res.redirect("/login"); // Redirige vers la page de connexion si l'utilisateur n'est pas connecté + } + try { + // la fonction db.getDocumentsByUserId(userId) renvoie tous les documents pour cet utilisateur + const documents = await db.getDocumentsByUserId(res.locals.user._id); + res.render("index", { documents: documents }); // Passezles documents au template EJS + } catch (error) { + console.error('Erreur lors de la récupération des documents:', error); + res.status(500).send('Erreur lors de la récupération des documents'); + } +}); + + + + + +app.all("*", (req, res) => res.status(404).send("<h1>Il semblerait que cette page n'existe pas.</h1>")); + + + + + + + + + function defaut(req, res){ const ind = {method : req.method, url : req.url} res.render("index",ind); @@ -79,15 +152,25 @@ async function dbAdmin(req, res){ } async function postLogin(req, res){ - let { username, password } = req.body; - let token = await auth.checkLogin(username, password); - if (token == -1) { - res.render("login",{username, password, error: "Il semblerait que le nom d'utilisateur ou le mot de passe soit incorrect."}); - } else { - res.cookie("accessToken", token, {httpOnly: true}); - res.redirect("/accueil"); + const { username, password } = req.body; + + try { + let token = await auth.checkLogin(username, password); + if (token == -1) { + // Si l'authentification échoue + res.render("login", { error: "Il semblerait que le nom d'utilisateur ou le mot de passe soit incorrect." }); + } else { + // Si l'authentification réussit + res.cookie("accessToken", token, { httpOnly: true }); + res.redirect("/accueil"); + } + } catch (error) { + console.error(error); + res.status(500).send('Erreur lors de la connexion'); } } + + module.exports = app; \ No newline at end of file diff --git a/db/Database.js b/db/Database.js index 42d103801a6f774d246676378d5f87b197078618..b111cec24528869fecc14609cd5e7a66c84ac4d2 100644 --- a/db/Database.js +++ b/db/Database.js @@ -37,18 +37,80 @@ class Database{ console.log("Collections créées !"); } + + // stockage des References _id doc + async createDocument(userId, documentData) { + const document = { + ...documentData, + auteur: userId, // Ici, userId est l'_id de l'utilisateur dans la collection 'users' + }; + const result = await this.insert('documents', document); + return result.insertedId; // Retourne l'ID du nouveau document créé + } + + //Recuperer les DOnnees liees de doc + async getDocumentWithAuthor(documentId) { + const document = await this.find('documents', { _id: new this.#client.ObjectId(documentId) }); + if(!document) throw new Error("Document n'est pas trouve"); + const user = await this.findOne('users', { _id: new this.#client.ObjectId(document.auteur) }); + if(!user) throw new Error("Auteur n'est pas trouve"); + return { + ...document, + auteur: user + }; + } + + // sauvgarde le fichier + async saveDocument(documentData) { + // Vérifie si le document a un ID pour déterminer si c'est une création ou une mise à jour + if (documentData._id) { + // Convertir _id en un objet ObjectId + const documentId = documentData._id; + delete documentData._id; // Retire _id des données car on ne peut pas le mettre à jour + const result = await this.#db.collection('documents').updateOne( + { _id: new this.#client.ObjectId(documentId) }, + { $set: documentData } + ); + return result.upsertedId || documentId; // Retourne l'ID mis à jour ou l'ID existant + } else { + // C'est un nouveau document, utilisez la méthode insert + const result = await this.insert('documents', documentData); + return result; // Retourne l'ID du nouveau document créé + } + } + + + + // chercher les docs d'un utilisateur + async getDocumentsByUserId(userId) { + return await this.#db.collection('documents').find({ auteur: userId }).toArray(); + } + + + // Gestion des Collections + async createPartage(userId, documentId) { + await this.insert('partage', { userId, documentId }); + } + async insert(collection, data){ - await this.#db.collection(collection).insertOne(data); + const result = await this.#db.collection(collection).insertOne(data); + return result.insertedId; // Retourne l'ID du document inséré } async insertMany(collection, data){ - await this.#db.collection(collection).insertMany(data); + const result = await this.#db.collection(collection).insertMany(data); + return result.insertedId; // Retourne l'ID du document inséré } async find(collection, query){ return await this.#db.collection(collection).find(query).toArray(); } + async findOne(collection, query) { + return await this.#db.collection(collection).findOne(query); + } + + } db = new Database("mongodb://127.0.0.1:27017/test?retryWrites=true&w=majority"); diff --git a/modele/Document.js b/modele/Document.js index 9505b2140873f9fdbba74d7ee819607d3490f690..29a2e4484ac12ee6a027c1f0b76e7b6fe3bffd45 100644 --- a/modele/Document.js +++ b/modele/Document.js @@ -19,6 +19,16 @@ class Document extends Component{ //TODO: historique des commandes } + async create(db) { + try { + const documentData = this.toJSON(); + this.#id = await db.createDocument(this.#auteur, documentData); + } catch (e) { + console.error('Échec de la création du document:', e); + throw e; // Renvoie l'erreur pour une gestion plus haut dans la pile d'appels. + } + } + //ajoute une feuille à la liste des feuilles addFeuille(feuille){ this.#feuilles.push(feuille); @@ -58,7 +68,7 @@ class Document extends Component{ this.#feuilles.forEach(feuille => feuillesJSON.push(feuille.toJSON())); return { - id: this.#id, + //id: this.#id, // pas besoin un ID là car mongodb gere ça tous seul nom: super.getNom(), auteur: this.#auteur, feuilles: feuillesJSON, diff --git a/public/css/spreadsheet-style.css b/public/css/spreadsheet-style.css new file mode 100644 index 0000000000000000000000000000000000000000..261629e6a5c405fb3cec8ad5178de4ad82eeb2b7 --- /dev/null +++ b/public/css/spreadsheet-style.css @@ -0,0 +1,71 @@ +.spreadsheet-container { + display: flex; + justify-content: center; + margin-top: 20px; + } + table { + border-collapse: collapse; + } + td, th { + border: 1px solid #ddd; + text-align: center; + min-width: 60px; + height: 30px; + padding: 4px; + } + th { + background-color: #f4f4f4; + height: 40px; + } + tr:nth-child(odd) td { + background-color: #f9f9f9; + } + + .navbar { + position: fixed; + top: 0; + left: 0; + width: 100%; + background-color: #081229; + color: white; +} + +.navbar_ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + background-color: #081229; +} + +.navbar li { + float: left; + text-align: center; + padding: 20px 16px; +} + +.navbar li a { + display: block; + color: white; + text-decoration: none; +} + +.navbar li a:hover { + background-color: #111; +} + +.navbar button{ + float : right; + background: #0b3595; + border: 0; + outline : none; + border-radius: 30px; + color: white; +} + +footer { + text-align: center; + padding: 5px; + background-color: #081229; + color: #FFF; +} diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000000000000000000000000000000000000..4daea8c24c5cbaed4bd0f5e6539e70ec59e728e4 --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,34 @@ +body { + font-family: 'Arial', sans-serif; + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: #f4f4f4; + } + + .home-container { + text-align: center; + } + + .button-container { + margin-top: 20px; + } + + .button { + display: inline-block; + padding: 10px 20px; + margin: 0 10px; + text-decoration: none; + color: white; + background-color: #007bff; + border-radius: 5px; + transition: background-color 0.3s ease; + } + + .button:hover { + background-color: #0056b3; + } + \ No newline at end of file diff --git a/public/res/construction.png b/public/res/construction.png new file mode 100644 index 0000000000000000000000000000000000000000..fcd3f1032950c9839b9d2bc74fc1b39e7f51d72b Binary files /dev/null and b/public/res/construction.png differ diff --git a/views/document.ejs b/views/document.ejs new file mode 100644 index 0000000000000000000000000000000000000000..54f9e6c40e2b046af8a80a67c722e7d0da76ee02 --- /dev/null +++ b/views/document.ejs @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Création document</title> + <link rel="stylesheet" href="/css/spreadsheet-style.css"> +</head> + +<body> + <%- include('partials/header') %> + <div class="spreadsheet-container"> + <button onclick="sauvegarderDocument()">Sauvegarder</button> + <table> + <% for(let row = 0; row < 18; row++) { %> + <tr> + <% for(let col = 0; col < 9; col++) { %> + <% if(row === 0) { %> + <th><%= String.fromCharCode(65 + col) %></th> + <% } else { %> + <td contenteditable="true"></td> + <% } %> + <% } %> + </tr> + <% } %> + </table> + </div> + + <script> + // JavaScript pour la gestion des événements peut être ajouté ici + function sauvegarderDocument() { + const tableau = []; + const lignes = document.querySelectorAll("table tr"); + + lignes.forEach((ligne, rowIndex) => { + if (rowIndex === 0) return; // Ignorer l'en-tête + + const cellules = ligne.querySelectorAll("td"); + const rowData = Array.from(cellules).map(cell => cell.innerText || ""); + tableau.push(rowData); + }); + + // Créer un objet pour envoyer + const documentData = { + nom: "Nom du Document", // le rendre dynamique si nécessaire + contenu: tableau + }; + + // Appel AJAX pour envoyer les données + envoyerDonnees(documentData); + } + + function envoyerDonnees(data) { + fetch('/document/save', { // Mette ici ton URL de sauvegarde + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }) + .then(response => response.json()) + .then(data => { + console.log('Succès:', data); + // Traite ici le retour de la sauvegarde + }) + .catch((error) => { + console.error('Erreur:', error); + }); + } + </script> + </body> + <%- include('partials/footer') %> +</html> diff --git a/views/index.ejs b/views/index.ejs index e8cb08cab23ca7dc340fc1d82b6d466fbef1ceaf..b3784fac58784ae739b53039ff463785a101a0fa 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -1,15 +1,35 @@ <!DOCTYPE html> -<html> - <head> - <title>Index</title> - </head> - <body> - <h1>Requête reçu</h1> - <p> La requête <%= method %> a été reçu à l'adresse <%= url %> </p> - <% if (locals.user) {%> - <p>Bonjour <%= locals.user.username %></p> - <% } else { %> - <p>Vous n'êtes pas connecté</p> - <% } %> - </body> -</html> \ No newline at end of file +<html lang="fr"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Accueil</title> + <link rel="stylesheet" href="/css/style.css"> +</head> + +<body> + <div class="home-container"> + <h1>Bienvenue sur Notre Application de Tableur</h1> + <p>Organisez vos données efficacement et en toute simplicité.</p> + + <% if (locals.user) { %> + <p>Bonjour, <%= locals.user.username %>!</p> + <div class="button-container"> + <a href="/document" class="button">Créer un Document</a> + <form action="/logout" method="post" style="display: inline;"> + <button type="submit" class="button">Se Déconnecter</button> + </form> + </div> + <% } else { %> + <div class="button-container"> + <a href="/login" class="button">Se Connecter</a> + <a href="/signup" class="button">S'inscrire</a> + </div> + <% } %> + </div> + +<script> +// JavaScript pour d'autres interactions si nécessaire +</script> +</body> +</html> diff --git a/views/login.ejs b/views/login.ejs index 995b76d2c54198d5b5f49a394d9acf148d61b825..8d9d864985af141d41bb43828e6d3480fba45681 100644 --- a/views/login.ejs +++ b/views/login.ejs @@ -3,16 +3,19 @@ <head> <meta charset="UTF-8"> <title>Connexion</title> + <link rel="stylesheet" href="/css/style.css"> </head> <body> - <h1>Connexion</h1> - <form action="/login" method="post"> - <input type="text" name="username" value="<%= locals.username ?? '' %>"> - <input type="password" name="password" value="<%= locals.password ?? '' %>"> - <input type="submit" value="Se connecter"> - </form> - <% if (locals.error) {%> - <p><%= locals.error %></p> - <% } %> + <div class="signin-container"> + <h1>Connexion</h1> + <form action="/login" method="post"> + <input type="text" name="username" value="<%= locals.username ?? '' %>"> + <input type="password" name="password" placeholder="Mot de passe"> + <input type="submit" class="button" value="Se connecter"> + </form> + <% if (locals.error) {%> + <p><%= locals.error %></p> + <% } %> + </div> </body> </html> \ No newline at end of file diff --git a/views/mydocuments.ejs b/views/mydocuments.ejs new file mode 100644 index 0000000000000000000000000000000000000000..9d3c92108286575312f43d5af3e978eb7d08a89c --- /dev/null +++ b/views/mydocuments.ejs @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> + <title>Construction en cours</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + font-family: Arial, sans-serif; + background-color: #f1f1f1; + } + + .container { + text-align: center; + } + + .message { + font-size: 24px; + font-weight: bold; + color: #333; + margin-bottom: 20px; + } + + .image { + width: 200px; + height: 200px; + margin-bottom: 20px; + } + </style> +</head> +<body> + <div class="container"> + <h1 class="message">Construction en cours</h1> + <img class="image" src="res/construction.png" alt="Construction en cours"> + <p>Veuillez revenir ultérieurement.</p> + </div> +</body> +</html> diff --git a/views/partials/footer.ejs b/views/partials/footer.ejs index 7a135954989f553a927af19669b6c45d68a2bca3..e91c84fc0e6a15461cb7b184cb964161080bde61 100644 --- a/views/partials/footer.ejs +++ b/views/partials/footer.ejs @@ -1,6 +1,4 @@ <footer> <!-- Contenu de ton pied de page ici --> - <p> this is footer</p> + <p> CollabSheet </p> </footer> -</body> -</html> diff --git a/views/partials/header.ejs b/views/partials/header.ejs index 198f0c617ecfdcfc721126d05b815cc36b51c8af..5e96195fa81669ba758ea0cc268b67285fbdbc37 100644 --- a/views/partials/header.ejs +++ b/views/partials/header.ejs @@ -1,5 +1,24 @@ +<header> + <!-- Contenu de l'en-tête ici --> + - <header> - <!-- Contenu de ton en-tête ici --> - <p>this is header</p> - </header> + <p>this is header</p> + <div class="navbar"> + <ul class="navbar_ul"> + <% if (locals.user) { %> + <li>Bonjour, <%= locals.user.username %> !</li> + <% } %> + <li><a href="/">Accueil</a></li> + <li><a href="/mydocuments">Documents</a></li> + <li><a href="/document">Créer un document</a></li> + <% if (locals.user) { %> + <form action="/logout" method="post"> + <li><button type="submit">Se Déconnecter</button> </li> + </form> + <% } else { %> + <li><a href="/register">Inscription</a></li> + <li><a href="/login">Connexion</a></li> + <% } %> + </ul> + </div> +</header> diff --git a/views/signup.ejs b/views/signup.ejs index b9148455b8bec736644a1933b50deec6e6f8dcfa..fda75628b2c7cb3585b046ab5468f29a94186c48 100644 --- a/views/signup.ejs +++ b/views/signup.ejs @@ -26,6 +26,7 @@ </div> <button type="submit">S'inscrire</button> </form> + <p>Déjà inscrit? <a href="/login">Se connecter</a></p> </div> </div> </body>