server.js.old 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // server.js - Fichier principal du serveur
  2. const express = require('express');
  3. const sqlite3 = require('sqlite3').verbose();
  4. const bcrypt = require('bcrypt');
  5. const cors = require('cors');
  6. const path = require('path');
  7. const app = express();
  8. const port = process.env.PORT || 3000;
  9. // Middleware
  10. app.use(express.json());
  11. app.use(cors());
  12. app.use(express.static(path.join(__dirname, 'public')));
  13. // Connexion à la base de données SQLite
  14. const db = new sqlite3.Database('/app/data/framed.db', (err) => {
  15. if (err) {
  16. console.error('Erreur de connexion à la base de données:', err.message);
  17. } else {
  18. console.log('Connecté à la base de données SQLite');
  19. initDatabase();
  20. }
  21. });
  22. // Initialiser la base de données
  23. function initDatabase() {
  24. // Activer les clés étrangères
  25. db.run('PRAGMA foreign_keys = ON');
  26. // Créer la table des utilisateurs
  27. db.run(`
  28. CREATE TABLE IF NOT EXISTS users (
  29. id INTEGER PRIMARY KEY AUTOINCREMENT,
  30. username TEXT UNIQUE NOT NULL,
  31. password TEXT NOT NULL,
  32. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  33. )
  34. `);
  35. // Créer la table des scores
  36. db.run(`
  37. CREATE TABLE IF NOT EXISTS scores (
  38. id INTEGER PRIMARY KEY AUTOINCREMENT,
  39. user_id INTEGER NOT NULL,
  40. date TEXT NOT NULL,
  41. game_type TEXT NOT NULL,
  42. game_number INTEGER,
  43. score INTEGER NOT NULL,
  44. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  45. FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
  46. )
  47. `);
  48. console.log('Tables vérifiées/créées');
  49. }
  50. // Routes d'API
  51. // Inscription
  52. app.post('/api/register', async (req, res) => {
  53. const { username, password } = req.body;
  54. if (!username || !password) {
  55. return res.status(400).json({ error: 'Nom d\'utilisateur et mot de passe requis' });
  56. }
  57. try {
  58. // Vérifier si l'utilisateur existe déjà
  59. db.get('SELECT * FROM users WHERE username = ?', [username], async (err, user) => {
  60. if (err) {
  61. return res.status(500).json({ error: err.message });
  62. }
  63. if (user) {
  64. return res.status(400).json({ error: 'Cet utilisateur existe déjà' });
  65. }
  66. // Hasher le mot de passe
  67. const hashedPassword = await bcrypt.hash(password, 10);
  68. // Insérer le nouvel utilisateur
  69. db.run('INSERT INTO users (username, password) VALUES (?, ?)',
  70. [username, hashedPassword],
  71. function(err) {
  72. if (err) {
  73. return res.status(500).json({ error: err.message });
  74. }
  75. res.status(201).json({
  76. message: 'Utilisateur créé avec succès',
  77. userId: this.lastID,
  78. username
  79. });
  80. }
  81. );
  82. });
  83. } catch (error) {
  84. res.status(500).json({ error: error.message });
  85. }
  86. });
  87. // Connexion
  88. app.post('/api/login', (req, res) => {
  89. const { username, password } = req.body;
  90. if (!username || !password) {
  91. return res.status(400).json({ error: 'Nom d\'utilisateur et mot de passe requis' });
  92. }
  93. db.get('SELECT * FROM users WHERE username = ?', [username], async (err, user) => {
  94. if (err) {
  95. return res.status(500).json({ error: err.message });
  96. }
  97. if (!user) {
  98. return res.status(401).json({ error: 'Identifiants invalides' });
  99. }
  100. // Vérifier le mot de passe
  101. const validPassword = await bcrypt.compare(password, user.password);
  102. if (!validPassword) {
  103. return res.status(401).json({ error: 'Identifiants invalides' });
  104. }
  105. res.json({
  106. userId: user.id,
  107. username: user.username
  108. });
  109. });
  110. });
  111. // Ajouter un score
  112. app.post('/api/scores', (req, res) => {
  113. const { userId, date, gameType, gameNumber, score } = req.body;
  114. if (!userId || !date || !gameType || !score) {
  115. return res.status(400).json({ error: 'Données incomplètes' });
  116. }
  117. db.run(
  118. 'INSERT INTO scores (user_id, date, game_type, game_number, score) VALUES (?, ?, ?, ?, ?)',
  119. [userId, date, gameType, gameNumber, score],
  120. function(err) {
  121. if (err) {
  122. return res.status(500).json({ error: err.message });
  123. }
  124. res.status(201).json({
  125. id: this.lastID,
  126. userId,
  127. date,
  128. gameType,
  129. gameNumber,
  130. score
  131. });
  132. }
  133. );
  134. });
  135. // Récupérer les scores d'un utilisateur
  136. app.get('/api/scores/user/:userId', (req, res) => {
  137. const userId = req.params.userId;
  138. db.all('SELECT * FROM scores WHERE user_id = ? ORDER BY date DESC', [userId], (err, scores) => {
  139. if (err) {
  140. return res.status(500).json({ error: err.message });
  141. }
  142. res.json(scores);
  143. });
  144. });
  145. // Récupérer tous les scores (pour le classement)
  146. app.get('/api/scores', (req, res) => {
  147. const gameType = req.query.gameType || 'all';
  148. let query = `
  149. SELECT s.*, u.username
  150. FROM scores s
  151. JOIN users u ON s.user_id = u.id
  152. `;
  153. if (gameType !== 'all') {
  154. query += ` WHERE s.game_type = '${gameType}'`;
  155. }
  156. db.all(query, (err, scores) => {
  157. if (err) {
  158. return res.status(500).json({ error: err.message });
  159. }
  160. res.json(scores);
  161. });
  162. });
  163. // Supprimer un score
  164. app.delete('/api/scores/:id', (req, res) => {
  165. const scoreId = req.params.id;
  166. const userId = req.query.userId;
  167. if (!userId) {
  168. return res.status(400).json({ error: 'Utilisateur non spécifié' });
  169. }
  170. db.run('DELETE FROM scores WHERE id = ? AND user_id = ?', [scoreId, userId], function(err) {
  171. if (err) {
  172. return res.status(500).json({ error: err.message });
  173. }
  174. if (this.changes === 0) {
  175. return res.status(404).json({ error: 'Score non trouvé ou non autorisé' });
  176. }
  177. res.json({ message: 'Score supprimé avec succès' });
  178. });
  179. });
  180. // Récupérer les statistiques d'un utilisateur
  181. app.get('/api/stats/:userId', (req, res) => {
  182. const userId = req.params.userId;
  183. const query = `
  184. SELECT
  185. game_type,
  186. COUNT(*) as total_games,
  187. AVG(score) as average_score,
  188. MIN(score) as best_score
  189. FROM scores
  190. WHERE user_id = ?
  191. GROUP BY game_type
  192. `;
  193. db.all(query, [userId], (err, stats) => {
  194. if (err) {
  195. return res.status(500).json({ error: err.message });
  196. }
  197. res.json(stats);
  198. });
  199. });
  200. // Récupérer le classement
  201. app.get('/api/leaderboard', (req, res) => {
  202. const gameType = req.query.gameType || 'all';
  203. let query = `
  204. SELECT
  205. u.id,
  206. u.username,
  207. COUNT(*) as total_games,
  208. AVG(s.score) as average_score,
  209. MIN(s.score) as best_score
  210. FROM scores s
  211. JOIN users u ON s.user_id = u.id
  212. `;
  213. if (gameType !== 'all') {
  214. query += ` WHERE s.game_type = '${gameType}'`;
  215. }
  216. query += `
  217. GROUP BY u.id
  218. ORDER BY average_score ASC, best_score ASC
  219. `;
  220. db.all(query, (err, leaderboard) => {
  221. if (err) {
  222. return res.status(500).json({ error: err.message });
  223. }
  224. res.json(leaderboard);
  225. });
  226. });
  227. // Route par défaut pour servir l'application React
  228. app.get('*', (req, res) => {
  229. res.sendFile(path.join(__dirname, 'public', 'index.html'));
  230. });
  231. // Démarrer le serveur
  232. //app.listen(port, () => {
  233. // console.log(`Serveur en écoute sur le port ${port}`);
  234. //});
  235. if (process.env.NODE_ENV === 'production') {
  236. // En production, servir les fichiers statiques
  237. app.use(express.static(path.join(__dirname, 'public')));
  238. // Route par défaut pour servir l'application React
  239. app.get('*', (req, res) => {
  240. res.sendFile(path.join(__dirname, 'public', 'index.html'));
  241. });
  242. } else {
  243. // En développement, juste répondre à l'API
  244. app.get('/', (req, res) => {
  245. res.json({ message: 'API Framed Tracker fonctionne correctement. Utilisez le port 3001 pour accéder au frontend.' });
  246. });
  247. }
  248. // Fermer proprement la connexion à la base de données lors de l'arrêt du serveur
  249. process.on('SIGINT', () => {
  250. db.close((err) => {
  251. if (err) {
  252. console.error(err.message);
  253. }
  254. console.log('Connexion à la base de données fermée');
  255. process.exit(0);
  256. });
  257. });