Mise à jour
This commit is contained in:
@@ -1,13 +1,3 @@
|
||||
/**
|
||||
* ============================================
|
||||
* DATABASE.JS - Gestion MariaDB
|
||||
* Smart Parking v3.0
|
||||
* AJOUTÉ : checkReservationConflict()
|
||||
* → vérifie les conflits d'horaire
|
||||
* au lieu de bloquer toute la place
|
||||
* ============================================
|
||||
*/
|
||||
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcryptjs');
|
||||
require('dotenv').config();
|
||||
@@ -23,9 +13,6 @@ const pool = mysql.createPool({
|
||||
queueLimit: 0
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// INITIALISATION
|
||||
// ============================================
|
||||
|
||||
async function initDatabase() {
|
||||
try {
|
||||
@@ -105,7 +92,6 @@ async function initDatabase() {
|
||||
|
||||
console.log('✅ Tables vérifiées/créées');
|
||||
|
||||
// Admin par défaut
|
||||
const [rows] = await pool.query('SELECT id FROM users WHERE email = ?', ['admin@smartparking.fr']);
|
||||
if (rows.length === 0) {
|
||||
const hashed = await bcrypt.hash('admin123', 10);
|
||||
@@ -116,7 +102,7 @@ async function initDatabase() {
|
||||
console.log('✅ Admin par défaut créé');
|
||||
}
|
||||
|
||||
// 10 places par défaut
|
||||
|
||||
const [spots] = await pool.query('SELECT COUNT(*) AS count FROM spots');
|
||||
if (spots[0].count === 0) {
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
@@ -134,9 +120,6 @@ async function initDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// UTILISATEURS
|
||||
// ============================================
|
||||
|
||||
async function createUser(name, email, phone, hashedPassword, role = 'client') {
|
||||
const [result] = await pool.query(
|
||||
@@ -180,9 +163,6 @@ async function deleteUser(id) {
|
||||
return { deleted: result.affectedRows };
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// PLACES
|
||||
// ============================================
|
||||
|
||||
async function createSpot(number, sensorId, status = 'free') {
|
||||
const [result] = await pool.query(
|
||||
@@ -215,9 +195,6 @@ async function deleteAllSpots() {
|
||||
return { deleted: result.affectedRows };
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// RÉSERVATIONS
|
||||
// ============================================
|
||||
|
||||
async function createReservation(userId, spotId, date, startTime, endTime, duration, vehicle, price, paymentCode) {
|
||||
const [result] = await pool.query(
|
||||
@@ -229,21 +206,7 @@ async function createReservation(userId, spotId, date, startTime, endTime, durat
|
||||
return { id: result.insertId };
|
||||
}
|
||||
|
||||
/**
|
||||
* ⭐ NOUVELLE FONCTION — Vérification des conflits d'horaire
|
||||
*
|
||||
* Problème corrigé : avant, quand une place était réservée,
|
||||
* elle restait bloquée pour TOUS les jours et TOUTES les heures.
|
||||
*
|
||||
* Maintenant on vérifie uniquement s'il y a une réservation
|
||||
* qui se chevauche sur la MÊME date et le MÊME créneau horaire.
|
||||
*
|
||||
* Exemple :
|
||||
* Place 2 réservée aujourd'hui 10h-11h ✅
|
||||
* Place 2 réservée aujourd'hui 14h-15h ✅ (pas de conflit)
|
||||
* Place 2 réservée demain 10h-11h ✅ (pas de conflit)
|
||||
* Place 2 réservée aujourd'hui 10h30-11h30 ❌ (conflit !)
|
||||
*/
|
||||
|
||||
async function checkReservationConflict(spotId, date, startTime, endTime) {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT id FROM reservations
|
||||
@@ -254,7 +217,7 @@ async function checkReservationConflict(spotId, date, startTime, endTime) {
|
||||
AND end_time > ?
|
||||
`, [spotId, date, endTime, startTime]);
|
||||
|
||||
return rows.length > 0; // true = conflit, false = créneau libre
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
async function getReservationById(id) {
|
||||
@@ -299,10 +262,7 @@ async function updateReservationStatus(id, status) {
|
||||
return { changed: result.affectedRows };
|
||||
}
|
||||
|
||||
/**
|
||||
* Expiration automatique des réservations
|
||||
* Appelée toutes les 60 secondes par server.js
|
||||
*/
|
||||
|
||||
async function expireReservations() {
|
||||
const [expiredRows] = await pool.query(`
|
||||
SELECT r.id, r.spot_id, r.user_id, s.number AS spot_number
|
||||
@@ -334,9 +294,36 @@ async function expireReservations() {
|
||||
return expiredRows.length;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// HISTORIQUE
|
||||
// ============================================
|
||||
|
||||
async function cleanupStaleReservedSpots() {
|
||||
try {
|
||||
const [staleSpots] = await pool.query(`
|
||||
SELECT s.id, s.number FROM spots s
|
||||
WHERE s.status = 'reserved'
|
||||
AND s.id NOT IN (
|
||||
SELECT r.spot_id FROM reservations r
|
||||
WHERE r.status IN ('active', 'pending')
|
||||
AND r.date = CURDATE()
|
||||
AND r.start_time <= CURTIME()
|
||||
AND r.end_time > CURTIME()
|
||||
)
|
||||
`);
|
||||
|
||||
for (const spot of staleSpots) {
|
||||
await pool.query(
|
||||
"UPDATE spots SET status = 'free', last_update = NOW() WHERE id = ?",
|
||||
[spot.id]
|
||||
);
|
||||
console.log(`🧹 Place ${spot.number} nettoyée : reserved → free (pas de réservation en cours)`);
|
||||
}
|
||||
|
||||
return staleSpots.length;
|
||||
} catch (err) {
|
||||
console.error('❌ Erreur cleanup stale spots:', err.message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function addHistory(action, details, userId = null) {
|
||||
const [result] = await pool.query(
|
||||
@@ -358,9 +345,6 @@ async function getHistory(limit = 50) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// STATISTIQUES
|
||||
// ============================================
|
||||
|
||||
async function recordStats(total, free, occupied, reserved) {
|
||||
const rate = total > 0 ? Math.round(((occupied + reserved) / total) * 100) : 0;
|
||||
@@ -381,9 +365,7 @@ async function getStats(days = 7) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MQTT
|
||||
// ============================================
|
||||
|
||||
|
||||
async function recordMqttEvent(topic, message) {
|
||||
const [result] = await pool.query(
|
||||
@@ -393,9 +375,6 @@ async function recordMqttEvent(topic, message) {
|
||||
return { id: result.insertId };
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// FERMETURE
|
||||
// ============================================
|
||||
|
||||
async function closeDatabase() {
|
||||
await pool.end();
|
||||
@@ -411,7 +390,7 @@ module.exports = {
|
||||
createReservation, checkReservationConflict,
|
||||
getReservationById, getReservationsByUser,
|
||||
getAllReservations, updateReservationStatus,
|
||||
expireReservations,
|
||||
expireReservations, cleanupStaleReservedSpots,
|
||||
addHistory, getHistory,
|
||||
recordStats, getStats,
|
||||
recordMqttEvent
|
||||
|
||||
Reference in New Issue
Block a user