Files
notytex/utils.py

99 lines
4.1 KiB
Python

from functools import wraps
from flask import current_app, flash, jsonify, request, render_template
from models import db
from sqlalchemy.exc import SQLAlchemyError, IntegrityError
from decimal import Decimal, InvalidOperation
def handle_db_errors(f):
"""Décorateur pour gérer les erreurs de base de données"""
@wraps(f)
def decorated_function(*args, **kwargs):
try:
result = f(*args, **kwargs)
# Vérifier que le résultat est une réponse Flask valide
if result is None:
current_app.logger.error(f'Fonction {f.__name__} a retourné None')
return render_template('error.html', error="Une erreur inattendue s'est produite."), 500
return result
except IntegrityError as e:
db.session.rollback()
current_app.logger.error(f'Erreur d\'intégrité dans {f.__name__}: {e}')
error_msg = "Une erreur s'est produite lors de l'enregistrement."
if "UNIQUE constraint failed" in str(e):
error_msg = "Cette donnée existe déjà."
elif "CHECK constraint failed" in str(e):
error_msg = "Les données saisies ne respectent pas les contraintes."
if request.is_json:
return jsonify({'success': False, 'error': error_msg}), 400
else:
flash(error_msg, 'error')
return render_template('error.html', error=error_msg), 400
except SQLAlchemyError as e:
db.session.rollback()
current_app.logger.error(f'Erreur SQLAlchemy dans {f.__name__}: {e}')
error_msg = "Une erreur de base de données s'est produite."
if request.is_json:
return jsonify({'success': False, 'error': error_msg}), 500
else:
flash(error_msg, 'error')
return render_template('error.html', error=error_msg), 500
except Exception as e:
db.session.rollback()
current_app.logger.error(f'Erreur inattendue dans {f.__name__}: {e}')
error_msg = "Une erreur inattendue s'est produite."
if request.is_json:
return jsonify({'success': False, 'error': error_msg}), 500
else:
flash(error_msg, 'error')
return render_template('error.html', error=error_msg), 500
return decorated_function
def safe_int_conversion(value, field_name="valeur"):
"""Conversion sécurisée en entier"""
if value is None:
return None
try:
return int(value)
except (ValueError, TypeError):
raise ValueError(f"La {field_name} doit être un nombre entier valide.")
def safe_decimal_conversion(value, field_name="valeur"):
"""Conversion sécurisée en décimal"""
if value is None:
return None
try:
return Decimal(str(value))
except (ValueError, TypeError, InvalidOperation):
raise ValueError(f"La {field_name} doit être un nombre décimal valide.")
def validate_json_data(data, required_fields):
"""Valide les données JSON et vérifie les champs requis"""
if not data:
raise ValueError("Aucune donnée fournie.")
missing_fields = [field for field in required_fields if field not in data or data[field] is None]
if missing_fields:
raise ValueError(f"Champs requis manquants: {', '.join(missing_fields)}")
return True
def log_user_action(action, details=None):
"""Log les actions utilisateur pour audit"""
current_app.logger.info(f"Action utilisateur: {action}" + (f" - {details}" if details else ""))
class ValidationError(Exception):
"""Exception personnalisée pour les erreurs de validation"""
pass
def handle_error(exception, default_message="Une erreur s'est produite"):
"""Gestionnaire d'erreur générique"""
current_app.logger.error(f"Erreur: {exception}")
flash(default_message, 'error')
return render_template('error.html', error=default_message), 500