Corrected error on sending document to universign

This commit is contained in:
Fanilo-Nantenaina 2025-12-03 13:54:28 +03:00
parent 5ff01c6c45
commit a73bdc4d9e
3 changed files with 213 additions and 6 deletions

212
api.py
View file

@ -297,11 +297,11 @@ async def lifespan(app: FastAPI):
await init_db() await init_db()
logger.info("✅ Base de données initialisée") logger.info("✅ Base de données initialisée")
# Injecter session_factory dans email_queue # ✅ CORRECTION: Injecter session_factory ET sage_client dans email_queue
email_queue.session_factory = async_session_factory email_queue.session_factory = async_session_factory
email_queue.sage_client = sage_client
# ⚠️ PAS de sage_connector ici (c'est sur Windows !) logger.info("✅ sage_client injecté dans email_queue")
# email_queue utilisera sage_client pour générer les PDFs via HTTP
# Démarrer queue # Démarrer queue
email_queue.start(num_workers=settings.max_email_workers) email_queue.start(num_workers=settings.max_email_workers)
@ -1739,6 +1739,212 @@ async def lire_utilisateur_debug(
raise HTTPException(500, str(e)) raise HTTPException(500, str(e))
# À ajouter dans api.py dans la section Debug
@app.get("/debug/database/check", tags=["Debug"])
async def verifier_integrite_database(session: AsyncSession = Depends(get_session)):
"""
🔍 Vérification de l'intégrité de la base de données
Retourne des statistiques détaillées sur toutes les tables
"""
from database import User, RefreshToken, LoginAttempt, EmailLog, SignatureLog
from sqlalchemy import func, text
try:
diagnostics = {}
# === TABLE USERS ===
# Compter tous les users
total_users = await session.execute(select(func.count(User.id)))
diagnostics["users"] = {
"total": total_users.scalar(),
"details": []
}
# Lister tous les users avec détails
all_users = await session.execute(select(User))
users_list = all_users.scalars().all()
for u in users_list:
diagnostics["users"]["details"].append({
"id": u.id,
"email": u.email,
"nom": f"{u.prenom} {u.nom}",
"role": u.role,
"is_active": u.is_active,
"is_verified": u.is_verified,
"created_at": u.created_at.isoformat() if u.created_at else None,
"has_reset_token": u.reset_token is not None,
"has_verification_token": u.verification_token is not None,
})
# === TABLE REFRESH_TOKENS ===
total_tokens = await session.execute(select(func.count(RefreshToken.id)))
diagnostics["refresh_tokens"] = {
"total": total_tokens.scalar()
}
# === TABLE LOGIN_ATTEMPTS ===
total_attempts = await session.execute(select(func.count(LoginAttempt.id)))
diagnostics["login_attempts"] = {
"total": total_attempts.scalar()
}
# === TABLE EMAIL_LOGS ===
total_emails = await session.execute(select(func.count(EmailLog.id)))
diagnostics["email_logs"] = {
"total": total_emails.scalar()
}
# === TABLE SIGNATURE_LOGS ===
total_signatures = await session.execute(select(func.count(SignatureLog.id)))
diagnostics["signature_logs"] = {
"total": total_signatures.scalar()
}
# === VÉRIFIER LES FICHIERS SQLITE ===
import os
db_file = "sage_dataven.db"
diagnostics["database_file"] = {
"exists": os.path.exists(db_file),
"size_bytes": os.path.getsize(db_file) if os.path.exists(db_file) else 0,
"path": os.path.abspath(db_file)
}
# === TESTER UNE REQUÊTE RAW SQL ===
try:
raw_count = await session.execute(text("SELECT COUNT(*) FROM users"))
diagnostics["raw_sql_check"] = {
"users_count": raw_count.scalar(),
"status": "✅ Connexion DB OK"
}
except Exception as e:
diagnostics["raw_sql_check"] = {
"status": "❌ Erreur",
"error": str(e)
}
return {
"success": True,
"timestamp": datetime.now().isoformat(),
"diagnostics": diagnostics
}
except Exception as e:
logger.error(f"❌ Erreur diagnostic DB: {e}", exc_info=True)
raise HTTPException(500, f"Erreur diagnostic: {str(e)}")
@app.post("/debug/database/test-user-persistence", tags=["Debug"])
async def tester_persistance_utilisateur(session: AsyncSession = Depends(get_session)):
"""
🧪 Test de création/lecture/modification d'un utilisateur de test
Crée un utilisateur de test, le modifie, et vérifie la persistance
"""
import uuid
from database import User
from security.auth import hash_password
try:
test_email = f"test_{uuid.uuid4().hex[:8]}@example.com"
# === ÉTAPE 1: CRÉATION ===
test_user = User(
id=str(uuid.uuid4()),
email=test_email,
hashed_password=hash_password("TestPassword123!"),
nom="Test",
prenom="User",
role="user",
is_verified=True,
is_active=True,
created_at=datetime.now()
)
session.add(test_user)
await session.flush()
user_id = test_user.id
await session.commit()
logger.info(f"✅ ÉTAPE 1: User créé - {user_id}")
# === ÉTAPE 2: LECTURE ===
result = await session.execute(
select(User).where(User.id == user_id)
)
loaded_user = result.scalar_one_or_none()
if not loaded_user:
return {
"success": False,
"error": "❌ User introuvable après création !",
"step": "LECTURE"
}
logger.info(f"✅ ÉTAPE 2: User chargé - {loaded_user.email}")
# === ÉTAPE 3: MODIFICATION (simulate reset password) ===
loaded_user.hashed_password = hash_password("NewPassword456!")
loaded_user.reset_token = None
loaded_user.reset_token_expires = None
session.add(loaded_user)
await session.flush()
await session.commit()
await session.refresh(loaded_user)
logger.info(f"✅ ÉTAPE 3: User modifié")
# === ÉTAPE 4: RE-LECTURE ===
result2 = await session.execute(
select(User).where(User.id == user_id)
)
reloaded_user = result2.scalar_one_or_none()
if not reloaded_user:
return {
"success": False,
"error": "❌ User DISPARU après modification !",
"step": "RE-LECTURE",
"user_id": user_id
}
logger.info(f"✅ ÉTAPE 4: User re-chargé - {reloaded_user.email}")
# === ÉTAPE 5: SUPPRESSION DU TEST ===
await session.delete(reloaded_user)
await session.commit()
logger.info(f"✅ ÉTAPE 5: User test supprimé")
return {
"success": True,
"message": "✅ Tous les tests de persistance sont OK",
"test_user_id": user_id,
"test_email": test_email,
"steps_completed": [
"1. Création",
"2. Lecture",
"3. Modification (reset password simulé)",
"4. Re-lecture (vérification persistance)",
"5. Suppression (cleanup)"
]
}
except Exception as e:
logger.error(f"❌ Erreur test persistance: {e}", exc_info=True)
# Rollback en cas d'erreur
await session.rollback()
return {
"success": False,
"error": str(e),
"traceback": str(e.__class__.__name__)
}
# ===================================================== # =====================================================
# LANCEMENT # LANCEMENT
# ===================================================== # =====================================================

View file

@ -5,6 +5,7 @@ from sqlalchemy import select
from database import get_session, User from database import get_session, User
from security.auth import decode_token from security.auth import decode_token
from typing import Optional from typing import Optional
from datetime import datetime # ✅ AJOUT MANQUANT - C'ÉTAIT LE BUG !
security = HTTPBearer() security = HTTPBearer()
@ -75,7 +76,7 @@ async def get_current_user(
detail="Email non vérifié. Consultez votre boîte de réception." detail="Email non vérifié. Consultez votre boîte de réception."
) )
# Vérifier si le compte est verrouillé # ✅ FIX: Vérifier si le compte est verrouillé (maintenant datetime est importé!)
if user.locked_until and user.locked_until > datetime.now(): if user.locked_until and user.locked_until > datetime.now():
raise HTTPException( raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, status_code=status.HTTP_403_FORBIDDEN,

View file

@ -31,7 +31,7 @@ class EmailQueue:
self.workers = [] self.workers = []
self.running = False self.running = False
self.session_factory = None self.session_factory = None
self.sage_client = None # Sera injecté depuis api.py self.sage_client = None
def start(self, num_workers: int = 3): def start(self, num_workers: int = 3):
"""Démarre les workers""" """Démarre les workers"""