182 lines
5.2 KiB
Python
182 lines
5.2 KiB
Python
"""
|
|
DragonBank - Validateurs
|
|
=========================
|
|
Centralise toutes les fonctions de validation des donnees
|
|
recues depuis les requetes HTTP.
|
|
|
|
Principe : chaque validateur retourne soit la valeur nettoyee,
|
|
soit leve une ValueError avec un message explicite.
|
|
Les routes n'ont ainsi pas a contenir de logique de validation.
|
|
|
|
Version : 3.0
|
|
"""
|
|
|
|
import re
|
|
import decimal
|
|
|
|
from config import (
|
|
MONTANT_MINIMUM_VIREMENT,
|
|
MONTANT_MAXIMUM_VIREMENT,
|
|
SIMULATION_DUREE_MIN,
|
|
SIMULATION_DUREE_MAX
|
|
)
|
|
|
|
|
|
# ============================================================
|
|
# EXPRESSIONS REGULIERES
|
|
# ============================================================
|
|
|
|
# Valide le format d'une adresse email (RFC 5322 simplifie).
|
|
REGEX_EMAIL = re.compile(
|
|
r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$'
|
|
)
|
|
|
|
|
|
# ============================================================
|
|
# VALIDATEURS
|
|
# ============================================================
|
|
|
|
def valider_email(email):
|
|
"""
|
|
Valide le format d'une adresse email.
|
|
|
|
Args:
|
|
email (str): L'adresse email a valider.
|
|
|
|
Returns:
|
|
str: L'email normalise (strip + lowercase).
|
|
|
|
Raises:
|
|
ValueError: Si le format est invalide ou si l'email est vide.
|
|
"""
|
|
if not email or not email.strip():
|
|
raise ValueError("L'adresse email est obligatoire")
|
|
|
|
email_normalise = email.strip().lower()
|
|
|
|
if not REGEX_EMAIL.match(email_normalise):
|
|
raise ValueError("Le format de l'adresse email est invalide")
|
|
|
|
return email_normalise
|
|
|
|
|
|
def valider_mot_de_passe(mot_de_passe):
|
|
"""
|
|
Valide la complexite d'un mot de passe.
|
|
|
|
Regles appliquees :
|
|
- Au moins 8 caracteres.
|
|
- Au moins une lettre majuscule (A-Z).
|
|
- Au moins une lettre minuscule (a-z).
|
|
- Au moins un chiffre (0-9).
|
|
|
|
Args:
|
|
mot_de_passe (str): Le mot de passe en clair a verifier.
|
|
|
|
Returns:
|
|
str: Le mot de passe inchange si valide.
|
|
|
|
Raises:
|
|
ValueError: Si une regle n'est pas respectee.
|
|
"""
|
|
if not mot_de_passe or len(mot_de_passe) < 8:
|
|
raise ValueError("Le mot de passe doit contenir au moins 8 caracteres")
|
|
if not re.search(r'[A-Z]', mot_de_passe):
|
|
raise ValueError("Le mot de passe doit contenir au moins une majuscule")
|
|
if not re.search(r'[a-z]', mot_de_passe):
|
|
raise ValueError("Le mot de passe doit contenir au moins une minuscule")
|
|
if not re.search(r'\d', mot_de_passe):
|
|
raise ValueError("Le mot de passe doit contenir au moins un chiffre")
|
|
|
|
return mot_de_passe
|
|
|
|
|
|
def valider_montant(montant_brut):
|
|
"""
|
|
Valide et convertit un montant en Decimal de maniere securisee.
|
|
|
|
Utilise Decimal (et non float) pour eviter les erreurs d'arrondi
|
|
inherentes aux nombres a virgule flottante (ex: 0.1 + 0.2 != 0.3).
|
|
|
|
Args:
|
|
montant_brut: Le montant brut a valider (str, int ou float).
|
|
|
|
Returns:
|
|
Decimal: Le montant valide et converti.
|
|
|
|
Raises:
|
|
ValueError: Si le montant est non numerique ou hors limites.
|
|
"""
|
|
try:
|
|
montant = decimal.Decimal(str(montant_brut))
|
|
except (decimal.InvalidOperation, TypeError):
|
|
raise ValueError("Le montant doit etre un nombre valide")
|
|
|
|
if montant < MONTANT_MINIMUM_VIREMENT:
|
|
raise ValueError(
|
|
"Le montant minimum est de " + str(MONTANT_MINIMUM_VIREMENT) + " euros"
|
|
)
|
|
if montant > MONTANT_MAXIMUM_VIREMENT:
|
|
raise ValueError(
|
|
"Le montant maximum par virement est de " + str(MONTANT_MAXIMUM_VIREMENT) + " euros"
|
|
)
|
|
|
|
return montant
|
|
|
|
|
|
def valider_champs_obligatoires(donnees, champs):
|
|
"""
|
|
Verifie que tous les champs obligatoires sont presents et non vides.
|
|
|
|
Args:
|
|
donnees (dict): Dictionnaire des donnees recues.
|
|
champs (list) : Liste des noms de champs obligatoires.
|
|
|
|
Returns:
|
|
None
|
|
|
|
Raises:
|
|
ValueError: Liste des champs manquants si au moins un est absent.
|
|
"""
|
|
if not donnees:
|
|
raise ValueError("Le corps de la requete JSON est manquant")
|
|
|
|
manquants = []
|
|
for champ in champs:
|
|
valeur = donnees.get(champ, '')
|
|
if not valeur or (isinstance(valeur, str) and not valeur.strip()):
|
|
manquants.append(champ)
|
|
|
|
if manquants:
|
|
raise ValueError("Champs obligatoires manquants : " + ", ".join(manquants))
|
|
|
|
|
|
def valider_parametres_simulateur(capital, taux, duree, versement):
|
|
"""
|
|
Valide les parametres d'entree du simulateur d'epargne.
|
|
|
|
Args:
|
|
capital (float): Capital initial en euros.
|
|
taux (float): Taux annuel en pourcentage.
|
|
duree (int) : Duree en annees.
|
|
versement (float): Versement mensuel en euros.
|
|
|
|
Returns:
|
|
None
|
|
|
|
Raises:
|
|
ValueError: Si un parametre est invalide.
|
|
"""
|
|
if capital < 0:
|
|
raise ValueError("Le capital initial ne peut pas etre negatif")
|
|
if taux < 0 or taux > 100:
|
|
raise ValueError("Le taux annuel doit etre compris entre 0 et 100 %")
|
|
if duree < SIMULATION_DUREE_MIN or duree > SIMULATION_DUREE_MAX:
|
|
raise ValueError(
|
|
"La duree doit etre comprise entre "
|
|
+ str(SIMULATION_DUREE_MIN) + " et "
|
|
+ str(SIMULATION_DUREE_MAX) + " ans"
|
|
)
|
|
if versement < 0:
|
|
raise ValueError("Le versement mensuel ne peut pas etre negatif")
|