Spaces:
Sleeping
Sleeping
| # chatbot/database.py | |
| """ | |
| Gestion de la base de données SQLite. | |
| - Utilisateurs (inscription / connexion) | |
| - Conversations (sauvegarde / chargement) | |
| """ | |
| import sqlite3 | |
| import hashlib | |
| import datetime | |
| import json | |
| import os | |
| from chatbot.config import DB_PATH | |
| def get_connection(): | |
| """Crée et retourne une connexion SQLite.""" | |
| conn = sqlite3.connect(DB_PATH) | |
| conn.row_factory = sqlite3.Row | |
| return conn | |
| def init_database(): | |
| """Initialise les tables si elles n'existent pas.""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS users ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| nom TEXT NOT NULL, | |
| prenom TEXT NOT NULL, | |
| email TEXT UNIQUE NOT NULL, | |
| password_hash TEXT NOT NULL, | |
| is_admin INTEGER DEFAULT 0, | |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | |
| ) | |
| """) | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS conversations ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| user_id INTEGER NOT NULL, | |
| title TEXT DEFAULT 'Nouvelle conversation', | |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
| updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY (user_id) REFERENCES users(id) | |
| ) | |
| """) | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS messages ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| conversation_id INTEGER NOT NULL, | |
| role TEXT NOT NULL, | |
| content TEXT NOT NULL, | |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY (conversation_id) REFERENCES conversations(id) | |
| ) | |
| """) | |
| conn.commit() | |
| # Migration : ajouter is_admin si la colonne n'existe pas | |
| try: | |
| cursor.execute("SELECT is_admin FROM users LIMIT 1") | |
| except sqlite3.OperationalError: | |
| cursor.execute("ALTER TABLE users ADD COLUMN is_admin INTEGER DEFAULT 0") | |
| conn.commit() | |
| # Migration : ajouter les champs profil | |
| for col, coltype in [("telephone", "TEXT DEFAULT ''"), ("adresse", "TEXT DEFAULT ''"), | |
| ("ville", "TEXT DEFAULT ''"), ("organisation", "TEXT DEFAULT ''")]: | |
| try: | |
| cursor.execute(f"SELECT {col} FROM users LIMIT 1") | |
| except sqlite3.OperationalError: | |
| cursor.execute(f"ALTER TABLE users ADD COLUMN {col} {coltype}") | |
| conn.commit() | |
| # Table des logs de connexion (IP, user-agent, etc.) | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS login_logs ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| user_id INTEGER NOT NULL, | |
| ip_address TEXT, | |
| user_agent TEXT, | |
| action TEXT DEFAULT 'login', | |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY (user_id) REFERENCES users(id) | |
| ) | |
| """) | |
| conn.commit() | |
| conn.close() | |
| def hash_password(password: str) -> str: | |
| """Hash un mot de passe avec SHA-256.""" | |
| return hashlib.sha256(password.encode()).hexdigest() | |
| def register_user(nom: str, prenom: str, email: str, password: str) -> dict: | |
| """ | |
| Inscrit un nouvel utilisateur. | |
| Retourne {"success": True, "user_id": ...} ou {"success": False, "error": ...} | |
| """ | |
| conn = get_connection() | |
| try: | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "INSERT INTO users (nom, prenom, email, password_hash) VALUES (?, ?, ?, ?)", | |
| (nom.strip(), prenom.strip(), email.strip().lower(), hash_password(password)) | |
| ) | |
| conn.commit() | |
| return {"success": True, "user_id": cursor.lastrowid} | |
| except sqlite3.IntegrityError: | |
| return {"success": False, "error": "Cet email est déjà utilisé."} | |
| finally: | |
| conn.close() | |
| def login_user(email: str, password: str) -> dict: | |
| """ | |
| Connecte un utilisateur. | |
| Retourne {"success": True, "user": {...}} ou {"success": False, "error": ...} | |
| """ | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "SELECT * FROM users WHERE email = ? AND password_hash = ?", | |
| (email.strip().lower(), hash_password(password)) | |
| ) | |
| user = cursor.fetchone() | |
| conn.close() | |
| if user: | |
| return { | |
| "success": True, | |
| "user": { | |
| "id": user["id"], | |
| "nom": user["nom"], | |
| "prenom": user["prenom"], | |
| "email": user["email"], | |
| "is_admin": user["is_admin"] if "is_admin" in user.keys() else 0, | |
| "telephone": user["telephone"] if "telephone" in user.keys() else "", | |
| "adresse": user["adresse"] if "adresse" in user.keys() else "", | |
| "ville": user["ville"] if "ville" in user.keys() else "", | |
| "organisation": user["organisation"] if "organisation" in user.keys() else "", | |
| } | |
| } | |
| return {"success": False, "error": "Email ou mot de passe incorrect."} | |
| def create_conversation(user_id: int, title: str = "Nouvelle conversation") -> int: | |
| """Crée une nouvelle conversation et retourne son ID.""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "INSERT INTO conversations (user_id, title) VALUES (?, ?)", | |
| (user_id, title) | |
| ) | |
| conn.commit() | |
| conv_id = cursor.lastrowid or 0 | |
| conn.close() | |
| return conv_id | |
| def get_user_conversations(user_id: int) -> list: | |
| """Retourne toutes les conversations d'un utilisateur (les plus récentes en premier).""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "SELECT * FROM conversations WHERE user_id = ? ORDER BY updated_at DESC", | |
| (user_id,) | |
| ) | |
| conversations = [dict(row) for row in cursor.fetchall()] | |
| conn.close() | |
| return conversations | |
| def add_message(conversation_id: int, role: str, content: str): | |
| """Ajoute un message à une conversation.""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "INSERT INTO messages (conversation_id, role, content) VALUES (?, ?, ?)", | |
| (conversation_id, role, content) | |
| ) | |
| # Met à jour la date de modification de la conversation | |
| cursor.execute( | |
| "UPDATE conversations SET updated_at = CURRENT_TIMESTAMP WHERE id = ?", | |
| (conversation_id,) | |
| ) | |
| conn.commit() | |
| conn.close() | |
| def get_conversation_messages(conversation_id: int) -> list: | |
| """Retourne tous les messages d'une conversation.""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "SELECT role, content, created_at FROM messages WHERE conversation_id = ? ORDER BY created_at ASC", | |
| (conversation_id,) | |
| ) | |
| messages = [dict(row) for row in cursor.fetchall()] | |
| conn.close() | |
| return messages | |
| def update_conversation_title(conversation_id: int, title: str): | |
| """Met à jour le titre d'une conversation.""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "UPDATE conversations SET title = ? WHERE id = ?", | |
| (title, conversation_id) | |
| ) | |
| conn.commit() | |
| conn.close() | |
| def delete_conversation(conversation_id: int): | |
| """Supprime une conversation et tous ses messages.""" | |
| conn = get_connection() | |
| cursor = conn.cursor() | |
| cursor.execute("DELETE FROM messages WHERE conversation_id = ?", (conversation_id,)) | |
| cursor.execute("DELETE FROM conversations WHERE id = ?", (conversation_id,)) | |
| conn.commit() | |
| conn.close() | |
| def log_login(user_id, ip_address=None, user_agent=None, action="login"): | |
| """Enregistre un log de connexion avec IP et user-agent.""" | |
| conn = get_connection() | |
| conn.execute( | |
| "INSERT INTO login_logs (user_id, ip_address, user_agent, action) VALUES (?, ?, ?, ?)", | |
| (user_id, ip_address, user_agent, action) | |
| ) | |
| conn.commit() | |
| conn.close() | |
| def get_login_logs(user_id=None, limit=50): | |
| """Recupere les logs de connexion.""" | |
| conn = get_connection() | |
| if user_id: | |
| rows = conn.execute( | |
| "SELECT l.*, u.email FROM login_logs l JOIN users u ON l.user_id = u.id WHERE l.user_id = ? ORDER BY l.created_at DESC LIMIT ?", | |
| (user_id, limit) | |
| ).fetchall() | |
| else: | |
| rows = conn.execute( | |
| "SELECT l.*, u.email FROM login_logs l JOIN users u ON l.user_id = u.id ORDER BY l.created_at DESC LIMIT ?", | |
| (limit,) | |
| ).fetchall() | |
| conn.close() | |
| return [dict(r) for r in rows] | |
| def update_user_profile(user_id, telephone="", adresse="", ville="", organisation=""): | |
| """Met a jour le profil utilisateur.""" | |
| conn = get_connection() | |
| conn.execute( | |
| "UPDATE users SET telephone=?, adresse=?, ville=?, organisation=? WHERE id=?", | |
| (telephone, adresse, ville, organisation, user_id) | |
| ) | |
| conn.commit() | |
| conn.close() | |
| def get_user_by_id(user_id): | |
| """Recupere un utilisateur par son ID.""" | |
| conn = get_connection() | |
| row = conn.execute("SELECT * FROM users WHERE id=?", (user_id,)).fetchone() | |
| conn.close() | |
| return dict(row) if row else None | |
| # Initialiser la base au chargement du module | |
| init_database() | |