ia-telecom / chatbot /database.py
wendsom's picture
Upload 3 files
96edb0f verified
Raw
History Blame Contribute Delete
9.17 kB
# 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()