fix: backend dead code + bug destroy + nettoyage legacy
- Suppression forgottenPassword/resetPassword (dead code, routes jamais câblées) - Suppression nodemailer (plus utilisé) - Fix destroy() : getById() → read() (bug — méthode inexistante) - Ajout getByNickname() dans UserManager (appelé mais manquant) - README rebrandé Clickerz/Tetardtek - Commentaire legacy WildCoinContext supprimé - SPRINT1.md : ref Xmass nettoyée
This commit is contained in:
@@ -3,11 +3,9 @@ require("dotenv").config();
|
||||
const bcrypt = require("bcrypt");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const Joi = require("joi");
|
||||
const nodemailer = require("nodemailer");
|
||||
const tables = require("../tables");
|
||||
|
||||
const secretKey = process.env.APP_SECRET;
|
||||
const resetTokenSecret = process.env.RESET_TOKEN_SECRET;
|
||||
const saltRounds = 10;
|
||||
|
||||
const passwordSchema = Joi.string()
|
||||
@@ -36,126 +34,13 @@ const validateEmail = async (email) => {
|
||||
|
||||
const validateUniqueNickname = async (nickname) => {
|
||||
await nicknameSchema.validateAsync(nickname);
|
||||
const existingUserByNickname = await tables.users.getByNickname(
|
||||
nickname
|
||||
);
|
||||
const existingUserByNickname = await tables.users.getByNickname(nickname);
|
||||
|
||||
if (existingUserByNickname) {
|
||||
throw new Error("Ce pseudo est déjà pris.");
|
||||
}
|
||||
};
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "gmail",
|
||||
auth: {
|
||||
user: process.env.EMAIL_USER,
|
||||
pass: process.env.EMAIL_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
const generateResetToken = (user) => {
|
||||
const resetToken = jwt.sign({ user: user.id }, resetTokenSecret, {
|
||||
expiresIn: "1h",
|
||||
});
|
||||
|
||||
const base64Token = Buffer.from(resetToken).toString("base64");
|
||||
|
||||
return base64Token;
|
||||
};
|
||||
|
||||
const sendPasswordResetEmail = async (user, resetToken) => {
|
||||
const resetLink = `${process.env.FRONTEND_URL}/reset-password/${resetToken}`;
|
||||
const mailOptions = {
|
||||
from: "INSERT_YOUR_EMAIL_ADDRESS_HERE",
|
||||
to: user.mail,
|
||||
subject: "Réinitialisation de mot de passe",
|
||||
html: `
|
||||
<p>Bonjour ${user.firstname},</p>
|
||||
<p>Vous avez demandé une réinitialisation de mot de passe pour votre compte.</p>
|
||||
<p>Cliquez sur le lien ci-dessous pour réinitialiser votre mot de passe :</p>
|
||||
<a href="${resetLink}">Réinitialiser le mot de passe</a>
|
||||
<p>Si vous n'avez pas demandé cette réinitialisation, veuillez ignorer ce message.</p>
|
||||
<p>Merci,</p>
|
||||
`,
|
||||
};
|
||||
|
||||
await transporter.sendMail(mailOptions);
|
||||
};
|
||||
|
||||
const forgottenPassword = async (req, res) => {
|
||||
const { mail } = req.body;
|
||||
|
||||
try {
|
||||
const user = await tables.users.getByMail(mail);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "Utilisateur non trouvé" });
|
||||
}
|
||||
|
||||
const resetToken = generateResetToken(user);
|
||||
|
||||
await sendPasswordResetEmail(user, resetToken);
|
||||
|
||||
return res.status(200).json({
|
||||
message: "Envoi d'un e-mail de réinitialisation du mot de passe",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Erreur dans l'envoi de l'e-mail de réinitialisation du mot de passe:",
|
||||
error
|
||||
);
|
||||
return res.status(500).json({
|
||||
message:
|
||||
"Erreur dans l'envoi de l'e-mail de réinitialisation du mot de passe",
|
||||
});
|
||||
}
|
||||
};
|
||||
const resetPassword = async (req, res) => {
|
||||
const { password } = req.body;
|
||||
|
||||
const resetToken = decodeURIComponent(req.params.token);
|
||||
|
||||
try {
|
||||
const decodedToken = jwt.verify(resetToken, resetTokenSecret);
|
||||
|
||||
const user = await tables.users.read(decodedToken.user);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "Utilisateur non trouvé" });
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
return res.status(400).json({ message: "Nouveau mot de passe manquant" });
|
||||
}
|
||||
|
||||
const { error } = Joi.string()
|
||||
.min(8)
|
||||
.regex(/[A-Z]/)
|
||||
.message("Le mot de passe doit contenir au moins une majuscule.")
|
||||
.regex(/\d/)
|
||||
.message("Le mot de passe doit contenir au moins un chiffre.")
|
||||
.regex(/[!@#$%^&*()_+{}[\]:;<>,.?~\\/-]/)
|
||||
.message("Le mot de passe doit contenir au moins un caractère spécial.")
|
||||
.validate(password);
|
||||
|
||||
if (error) {
|
||||
return res.status(400).json({ message: error.details[0].message });
|
||||
}
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||
await tables.users.edit(user.id, { password: hashedPassword });
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({ message: "Réinitialisation du mot de passe réussie" });
|
||||
} catch (error) {
|
||||
console.error("Erreur de réinitialisation du mot de passe:", error);
|
||||
return res.status(500).json({
|
||||
message: "Erreur de réinitialisation du mot de passe",
|
||||
error,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const login = async (req, res) => {
|
||||
const { mail, password } = req.body;
|
||||
|
||||
@@ -378,7 +263,7 @@ const destroy = async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const user = await tables.users.getById(userId);
|
||||
const user = await tables.users.read(userId);
|
||||
|
||||
const isCurrentPasswordCorrect = await bcrypt.compare(
|
||||
currentPassword,
|
||||
@@ -438,7 +323,5 @@ module.exports = {
|
||||
add,
|
||||
destroy,
|
||||
login,
|
||||
forgottenPassword,
|
||||
resetPassword,
|
||||
updateCoins,
|
||||
};
|
||||
|
||||
@@ -60,6 +60,14 @@ class UserManager extends AbstractManager {
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async getByNickname(nickname) {
|
||||
const [rows] = await this.database.query(
|
||||
`SELECT * FROM ${this.table} WHERE nickname = ?`,
|
||||
[nickname]
|
||||
);
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
|
||||
async getByMail(mail) {
|
||||
const [rows] = await this.database.query(
|
||||
`SELECT * FROM ${this.table} WHERE mail = ?`,
|
||||
|
||||
@@ -1,50 +1,11 @@
|
||||
<!--Head-->
|
||||
# Clickerz — Tetard Universe
|
||||
|
||||
<h3>Clickerz — Tetard Universe</h3>
|
||||
<br>
|
||||
Idle clicker game. Fais éclore des têtards, construis ton empire et domine le marais.
|
||||
|
||||
### 📄 About :
|
||||
<br> This site is a prototype exercise designed and developed by TrueQuiLeaks Team as part of their Web and Mobile Developer training at the Wild Code School on the Remote campus from September 2023.
|
||||
### Stack
|
||||
|
||||
<br>
|
||||
<br>
|
||||
React · Vite · SCSS · Tailwind · Zustand
|
||||
|
||||
### Credits
|
||||
|
||||
### ✏️ Languages :
|
||||
This site is developed with the following languages : <br>
|
||||
<p dir="auto">
|
||||
<a href="https://www.w3.org/html/" target="_blank" rel="noreferrer">
|
||||
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/html5/html5-original-wordmark.svg" alt="html5" width="40" height="40"/></a>
|
||||
|
||||
<a href="https://www.w3schools.com/css/" target="_blank" rel="noreferrer">
|
||||
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/css3/css3-original-wordmark.svg" alt="css3" width="40" height="40"/></a>
|
||||
|
||||
<a href="https://sass-lang.com" target="_blank" rel="noreferrer">
|
||||
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/sass/sass-original.svg" alt="sass" width="40" height="40"/></a>
|
||||
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank" rel="noreferrer">
|
||||
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg" alt="javascript" width="40" height="40"/></a>
|
||||
|
||||
<a href="https://reactjs.org/" target="_blank" rel="noreferrer">
|
||||
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/react/react-original-wordmark.svg" alt="react" width="40" height="40"/></a>
|
||||
</p>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
### 🎖️Achievements :
|
||||
- **W3C:** Our website has passed W3C certification.
|
||||
- **Accessibility:** bookofwilder.fr to pass the LightHouse PC and Mobile test with a result of 100%.
|
||||
- **SEO:** This was one of our personal validation criteria and after the LightHouse tests (PC and Mobile), our site fulfilled it 100%.
|
||||
- **Speed:** Our site sets speed records with a 100% on the LightHouse PC test and 100% on Mobile. Improvements are underway to optimize this latter result.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
### Credits :
|
||||
|
||||
This site is a prototype exercise designed and developed by: Alix C, Sebastien L, Baptiste S, Kévin T and Nicolas DF as part of their Web and Mobile Developer training at the Wild Code School on the Remote campus from September 2023 .
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
Développé par [Kevin T](https://github.com/tetardtek) · Powered by Brain
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// GeneratorShop.tsx — Boutique de générateurs (economy.ts)
|
||||
// Remplace Amelioration.jsx (legacy WildCoinContext)
|
||||
|
||||
import { useGameStore } from "../store/useGameStore";
|
||||
import { formatNumber } from "../utils/formatNumber";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## Objectif
|
||||
|
||||
Transformer le prototype Xmass Clicker en Clickerz Tetard Universe avec :
|
||||
Transformer le prototype legacy en Clickerz Tetard Universe avec :
|
||||
- Rethème complet (noms, visuels, textes)
|
||||
- Arbre d'Évolution (permanent, jamais reset)
|
||||
- Save serveur (anti-triche, fin du localStorage)
|
||||
|
||||
Reference in New Issue
Block a user