from functools import wraps from flask import current_app, flash, jsonify, request, render_template, redirect, url_for from models import db from sqlalchemy.exc import SQLAlchemyError, IntegrityError from decimal import Decimal, InvalidOperation import logging 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