I have multiple routes that are used to change details of a users account. One is specifically made to change the password for the user. However, no matter what I do, I always get a 404 error telling me the route doesnt exist even though it does. I’ll provide the 3 files that I think are related to this issue.
Note: I use the same button to update the user’s info whether it’s name, email or password. But the button changes its function depending on the tab that is active.
comptepersonnel.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href='https://unpkg.com/[email protected]/css/boxicons.min.css' rel='stylesheet'>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/styles.css">
<title>Mon Compte</title>
<style>
/* Add styles specific to comptepersonnel page here */
#comptepersonnel .input-field {
border: 1px solid #cccccc; /* Ensure border is visible */
background-color: #ffffff; /* Ensure background is white */
color: #333333; /* Text color for input */
}
#comptepersonnel .input-field::placeholder {
color: #aaaaaa; /* Placeholder text color */
}
/* Additional specific styles */
#comptepersonnel .input-wrapper {
display: block; /* Ensure wrappers are visible */
}
#comptepersonnel .warning-message {
display: none; /* Hide warning messages by default */
color: #d9534f; /* Style for warning messages */
font-size: 0.8em;
margin-top: 4px;
}
</style>
</head>
<body id="comptepersonnel">
<div class="wrapper">
<video id="video1" src="/Background_Video_Connection.mp4" autoplay muted loop plays-inline class="back-video"></video>
<nav class="nav">
<div class="nav-logo">
<p>Clipper Link MTL .</p>
</div>
<div class="nav-menu" id="navMenu" style="right : 20%;">
<ul>
<li><a href="acceuil.html" class="link">Acceuil</a></li>
<li><a href="Salons.html" class="link">Services</a></li>
<li><a href="Apropos.html" class="link">À propos</a></li>
<li><a href="contact.html" class="link">Contact</a></li>
<li><a href="inscription.html" class="link">Connexion/Inscription</a></li>
</ul>
</div>
<div class="nav-button" style="visibility: hidden" disabled>
<button class="btn white-btn" id="loginBtn" onclick="login()">Connexion</button>
<button class="btn" id="registerBtn" onclick="register()">Inscription</button>
</div>
<div class="nav-menu-btn" style="visibility: hidden" disabled>
<i class="bx bx-menu" onclick="myMenuFunction()"></i>
</div>
</nav>
<body>
<div class="container light-style flex-grow-1 container-p-y">
<div class="card overflow-hidden">
<div class="row no-gutters row-bordered row-border-light">
<div class="col-md-3 pt-0">
<div class="list-group list-group-flush account-settings-links">
<a class="list-group-item list-group-item-action active" data-toggle="list"
href="#account-compte">Mon Compte</a>
<a class="list-group-item list-group-item-action" data-toggle="list"
href="#account-mdp">Changer Mot de Passe</a>
<a class="list-group-item list-group-item-action" data-toggle="list"
href="#account-reservation">Réservation</a>
<a class="list-group-item list-group-item-action" data-toggle="list"
href="#account-favoris">Favoris</a>
<a class="list-group-item list-group-item-action" id="deconnecter"
href="javascript:void(0);">Déconnecter</a>
</div>
</div>
<div class="col-md-9">
<div class="tab-content">
<div class="tab-pane fade active show" id="account-compte">
<div id="messageContainerAccount" class="message-container"></div>
<hr class="border-light m-0">
<div class="card-body">
<div class="form-group">
<label class="form-label">Prénom</label>
<div class="input-wrapper">
<input type="text" id="inputFirstName" class="form-control mb-1 input-field" value="" required pattern="[a-zA-Z-]+">
<span class="warning-message"></span>
</div>
</div>
<div class="form-group">
<label class="form-label">Nom</label>
<div class="input-wrapper">
<input type="text" id="inputLastName" class="form-control input-field" value="" required pattern="[a-zA-Z-]+">
<span class="warning-message"></span>
</div>
</div>
<div class="form-group">
<label class="form-label">Courriel</label>
<div class="input-wrapper">
<input type="email" id="inputEmail" class="form-control mb-1 input-field" value="" required pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$">
<span class="warning-message"></span>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="account-mdp">
<div id="messageContainerPassword" class="message-container"></div>
<div class="card-body pb-2">
<div class="form-group">
<label class="form-label">Mot de passe actuel</label>
<div class="input-wrapper">
<input type="password" id="currentPasswordInput" class="form-control input-field" required pattern="(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,}">
<span class="warning-message"></span>
</div>
</div>
<div class="form-group">
<label class="form-label">Nouveau mot de passe</label>
<div class="input-wrapper">
<input type="password" id="newPasswordInput" class="form-control input-field" required pattern="(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,}">
<span class="warning-message"></span>
</div>
</div>
<div class="form-group">
<label class="form-label">Répétez le nouveau mot de passe</label>
<div class="input-wrapper">
<input type="password" id="repeatNewPasswordInput" class="form-control input-field" required pattern="(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,}">
<span class="warning-message"></span>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="account-reservation">
</div>
<div class="tab-pane fade" id="account-favoris">
</div>
</div>
</div>
</div>
</div>
<div class="text-right mt-3">
<button type="submit" id="saveButton" class="btn btn-primary">Sauvegarder</button>
<button type="button" class="btn btn-default">Annulé</button>
</div>
</div>
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script src="/comptepersonnel.js"></script>
</body>
</html>
comptepersonnel.js:
document.addEventListener("DOMContentLoaded", function() {
var token = sessionStorage.getItem("token");
// Gestion des changements de navigation
if (token) {
var button = document.querySelector(".nav-menu .link[href='inscription.html']");
if (button) {
button.textContent = "Mon Compte";
button.href = "comptepersonnel.html";
button.classList.add("active");
}
}
// Récupération et affichage des données utilisateur
fetchUserData();
// Définition d'un moment aléatoire pour la vidéo
setRandomVideoTime();
// Validation des champs de saisie lors de la saisie
document.querySelectorAll('.input-field').forEach(input => {
input.addEventListener('input', validateInput);
});
// Écouteur d'événement pour le bouton de sauvegarde
document.getElementById('saveButton').addEventListener('click', function(event) {
event.preventDefault();
// Vérification de l'onglet actif
if (document.getElementById('account-mdp').classList.contains('active')) {
// L'onglet Changer le mot de passe est actif
if (validatePasswordChangeForm()) {
submitPasswordChange();
}
} else {
// L'onglet Mon Compte est actif
if (validateForm()) {
updateAccount();
}
}
});
// Fonctionnalité de déconnexion
const deconnecterBtn = document.getElementById('deconnecter');
if (deconnecterBtn) {
deconnecterBtn.addEventListener('click', () => {
sessionStorage.removeItem('token');
window.location.href = 'acceuil.html';
});
}
});
function setRandomVideoTime() {
const video = document.getElementById('video1');
if (video && video.duration) {
video.currentTime = Math.random() * video.duration;
}
}
function fetchUserData() {
const token = sessionStorage.getItem('token');
fetch('/api/account', {
method: 'GET',
headers: { 'Authorization': `Bearer ${token}` }
})
.then(response => {
if (!response.ok) {
throw new Error('La réponse du réseau n'était pas correcte: ' + response.statusText);
}
return response.json();
})
.then(data => {
document.querySelector('#inputFirstName').value = data.firstName;
document.querySelector('#inputLastName').value = data.lastName;
document.querySelector('#inputEmail').value = data.email;
})
.catch(error => {
console.error('Erreur lors de la récupération des données du compte:', error);
});
}
function updateAccount() {
const userData = {
firstName: document.querySelector('#inputFirstName').value,
lastName: document.querySelector('#inputLastName').value,
email: document.querySelector('#inputEmail').value,
token: sessionStorage.getItem('token')
};
fetch('/api/account/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
})
.then(response => response.json())
.then(data => {
if(data.success) {
displayMessage('Compte mis à jour avec succès', 'success');
} else {
throw new Error(data.message);
}
})
.catch(error => {
console.error('Erreur lors de la mise à jour du compte:', error);
displayMessage('Échec de la mise à jour du compte', 'error');
});
}
function validatePasswordChangeForm() {
let isValid = true;
const currentPassword = document.querySelector('#currentPasswordInput').value;
const newPassword = document.querySelector('#newPasswordInput').value;
const repeatNewPassword = document.querySelector('#repeatNewPasswordInput').value;
// Validation du mot de passe actuel
if (!currentPassword || !currentPassword.match(/(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,}/)) {
displayWarning('currentPasswordInput', 'Le mot de passe actuel est invalide.');
isValid = false;
}
// Validation du nouveau mot de passe
if (!newPassword || !newPassword.match(/(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,}/)) {
displayWarning('newPasswordInput', 'Le nouveau mot de passe doit contenir au moins 8 caractères, dont un chiffre, une lettre minuscule et une lettre majuscule.');
isValid = false;
}
// Vérification de la correspondance des nouveaux mots de passe
if (newPassword !== repeatNewPassword) {
displayWarning('repeatNewPasswordInput', 'Le nouveau mot de passe ne correspond pas.');
isValid = false;
}
return isValid;
}
function submitPasswordChange() {
const currentPassword = document.querySelector('#currentPasswordInput').value;
const newPassword = document.querySelector('#newPasswordInput').value;
const token = sessionStorage.getItem('token');
const passwordData = { currentPassword, newPassword, token };
fetch('/api/account/change-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(passwordData)
})
.then(handleResponse)
.then(handleData)
.catch(handleError);
}
function handleResponse(response) {
if (!response.ok) {
throw new Error(`Erreur HTTP! status: ${response.status}`);
}
return response.json();
}
function handleData(data) {
if (data.success) {
displayMessage('Mot de passe changé avec succès.', 'success');
} else {
displayMessage(data.message, 'error');
}
}
function handleError(error) {
console.error('Erreur lors du changement de mot de passe:', error);
displayMessage('Échec du changement de mot de passe', 'error');
}
function validateInput(event) {
const input = event.target;
const inputWrapper = input.closest('.input-wrapper');
const warningMessage = inputWrapper.querySelector('.warning-message');
const pattern = input.getAttribute('pattern');
if (pattern) {
const regex = new RegExp(pattern);
if (!regex.test(input.value)) {
warningMessage.textContent = getMessageAvertissement(input.id, input.value);
warningMessage.style.display = 'block';
} else {
warningMessage.style.display = 'none';
}
}
}
function validateForm() {
let isValid = true;
const firstName = document.querySelector('#inputFirstName').value;
if (firstName.length < 2) {
displayWarning('inputFirstName', 'Le prénom doit contenir au moins 2 caractères.');
isValid = false;
}
const lastName = document.querySelector('#inputLastName').value;
if (lastName.length < 2) {
displayWarning('inputLastName', 'Le nom doit contenir au moins 2 caractères.');
isValid = false;
}
const email = document.querySelector('#inputEmail').value;
if (!email.includes('@')) {
displayWarning('inputEmail', 'L'adresse email n'est pas valide.');
isValid = false;
}
return isValid;
}
function displayWarning(inputId, message) {
const warningElement = document.querySelector('#' + inputId + ' + .warning-message');
warningElement.textContent = message;
warningElement.style.display = 'block';
}
function getMessageAvertissement(inputId, inputValue) {
switch(inputId) {
case 'inputFirstName':
return 'Prénom invalide.';
case 'inputLastName':
return 'Nom invalide.';
case 'inputEmail':
return 'Format de l'email invalide.';
}
}
function displayMessage(message, type) {
const messageContainerId = document.getElementById('account-mdp').classList.contains('active') ? 'messageContainerPassword' : 'messageContainerAccount';
const messageElement = document.getElementById(messageContainerId);
if (messageElement) {
messageElement.textContent = message;
messageElement.className = type;
messageElement.style.display = 'block';
} else {
console.error('Message container not found');
}
}
serveur.js:
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const knex = require('knex')({
client: 'sqlite3',
connection: {
filename: './mydatabase.db'
},
useNullAsDefault: true
});
const app = express();
const PORT = process.env.PORT || 3000;
app.use(cors());
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'PageHTML')));
// Home page route
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'PageHTML', 'acceuil.html'));
});
// Salon information route
app.get('/salons', (req, res) => {
knex.select().from('UtilisateurEntreprise')
.then(salons => res.json(salons))
.catch(err => res.status(500).json({ error: 'Error retrieving salons: ' + err }));
});
// Static page for salons
app.get('/salons-html', (req, res) => {
res.sendFile(path.join(__dirname, 'PageHTML', 'Salons.html'));
});
// User registration
app.post('/register', (req, res) => {
const { firstName, lastName, email, password } = req.body;
if (!validatePassword(password)) {
return res.status(400).json({ success: false, message: "Password does not meet criteria." });
}
const uniqueToken = require('crypto').randomBytes(50).toString('hex');
knex('UtilisateurClient').insert({
Nom: lastName,
Prenom: firstName,
Courriel: email,
MotDePasse: password, // Store password as plain text
UniqueToken: uniqueToken
})
.then(() => res.json({ success: true, message: "User successfully registered." }))
.catch(err => {
if (err.message.includes('UNIQUE constraint failed')) {
res.status(409).json({ success: false, message: "Email already in use." });
} else {
res.status(500).json({ success: false, message: "An error occurred: " + err });
}
});
});
// Password validation
function validatePassword(password) {
const regex = /(?=.*d)(?=.*[a-z])(?=.*[A-Z])(?=.*W).{8,}/;
return regex.test(password);
}
// User login
app.post('/login', (req, res) => {
const { email, password } = req.body;
knex('UtilisateurClient')
.select('MotDePasse', 'UniqueToken')
.where({ Courriel: email })
.first()
.then(user => {
if (!user) {
return res.status(401).json({ success: false, message: 'Email not registered.' });
}
if (user.MotDePasse !== password) {
return res.status(401).json({ success: false, message: 'Incorrect password.' });
}
res.json({ success: true, message: 'Login successful.', token: user.UniqueToken });
})
.catch(err => res.status(500).json({ success: false, message: 'Error during login: ' + err }));
});
// Fetch user account data
app.get('/api/account', (req, res) => {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(401).send('No token provided');
}
knex('UtilisateurClient')
.where({ UniqueToken: token })
.first()
.then(user => {
if (!user) {
return res.status(404).send('User not found');
}
res.json({
firstName: user.Prenom,
lastName: user.Nom,
email: user.Courriel
});
})
.catch(error => res.status(500).send('Internal server error: ' + error));
});
// Update user account
app.post('/api/account/update', (req, res) => {
const { firstName, lastName, email, token } = req.body;
knex('UtilisateurClient')
.where({ UniqueToken: token })
.first()
.then(user => {
if (!user) {
return res.status(404).json({ success: false, message: "User not found" });
}
knex('UtilisateurClient')
.where({ IdClient: user.IdClient })
.update({
Prenom: firstName || user.Prenom,
Nom: lastName || user.Nom,
Courriel: email || user.Courriel
})
.then(() => res.json({ success: true }))
.catch(err => res.status(500).json({ success: false, message: 'Failed to update user: ' + err }));
})
.catch(err => res.status(500).json({ success: false, message: 'User retrieval failed: ' + err }));
});
// Route pour changer le mot de passe
app.post('/api/account/change-password', (req, res) => {
const { token, currentPassword, newPassword } = req.body;
if (!token) {
return res.status(401).json({ success: false, message: 'Token non fourni.' });
}
// Trouver l'utilisateur par token
knex('UtilisateurClient')
.where({ UniqueToken: token })
.first()
.then(user => {
if (!user) {
return res.status(404).json({ success: false, message: 'Utilisateur non trouvé.' });
}
// Comparer le mot de passe actuel (ici sans hachage)
if (user.MotDePasse !== currentPassword) {
return res.status(401).json({ success: false, message: 'Mot de passe actuel incorrect.' });
}
// Mettre à jour le mot de passe avec le nouveau mot de passe en clair
knex('UtilisateurClient')
.where({ UniqueToken: token })
.update({ MotDePasse: newPassword })
.then(() => {
res.json({ success: true, message: "Mot de passe mis à jour avec succès." });
})
.catch(err => {
console.error('Erreur lors de la mise à jour du mot de passe:', err);
res.status(500).json({ success: false, message: "Une erreur s'est produite lors de la mise à jour du mot de passe." });
});
})
.catch(err => {
console.error('Erreur lors de la récupération de l’utilisateur:', err);
res.status(500).json({ success: false, message: 'Erreur interne du serveur.' });
});
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
The console log error:
If anything else is needed let me know!
I have tried changing the names of the route. Changing the methods used to change the password and even completely reset the database so that it doesn’t use a hashed password.
I’m just trying to make it so that the Current password and changed to the new password that the user submits.