Corrected error on sending document to universign
This commit is contained in:
parent
5ff01c6c45
commit
a73bdc4d9e
3 changed files with 213 additions and 6 deletions
212
api.py
212
api.py
|
|
@ -297,11 +297,11 @@ async def lifespan(app: FastAPI):
|
|||
await init_db()
|
||||
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.sage_client = sage_client
|
||||
|
||||
# ⚠️ PAS de sage_connector ici (c'est sur Windows !)
|
||||
# email_queue utilisera sage_client pour générer les PDFs via HTTP
|
||||
logger.info("✅ sage_client injecté dans email_queue")
|
||||
|
||||
# Démarrer queue
|
||||
email_queue.start(num_workers=settings.max_email_workers)
|
||||
|
|
@ -1739,6 +1739,212 @@ async def lire_utilisateur_debug(
|
|||
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
|
||||
# =====================================================
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from sqlalchemy import select
|
|||
from database import get_session, User
|
||||
from security.auth import decode_token
|
||||
from typing import Optional
|
||||
from datetime import datetime # ✅ AJOUT MANQUANT - C'ÉTAIT LE BUG !
|
||||
|
||||
security = HTTPBearer()
|
||||
|
||||
|
|
@ -75,7 +76,7 @@ async def get_current_user(
|
|||
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():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class EmailQueue:
|
|||
self.workers = []
|
||||
self.running = False
|
||||
self.session_factory = None
|
||||
self.sage_client = None # Sera injecté depuis api.py
|
||||
self.sage_client = None
|
||||
|
||||
def start(self, num_workers: int = 3):
|
||||
"""Démarre les workers"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue