mirror of
https://github.com/Ladebeze66/llm_ticket3.git
synced 2025-12-15 19:26:53 +01:00
308 lines
10 KiB
Python
308 lines
10 KiB
Python
import json
|
|
import logging
|
|
import os
|
|
import requests
|
|
from typing import Dict, Any, Optional
|
|
|
|
# Variable globale pour stocker l'instance du gestionnaire d'authentification
|
|
_auth_manager_instance = None
|
|
|
|
class AuthManager:
|
|
"""
|
|
Gestionnaire d'authentification pour l'API Odoo.
|
|
Gère la connexion et les appels RPC à l'API Odoo.
|
|
"""
|
|
|
|
def __init__(self, url: str, db: str, username: str, api_key: str):
|
|
"""
|
|
Initialise le gestionnaire d'authentification.
|
|
|
|
Args:
|
|
url: URL de l'instance Odoo
|
|
db: Nom de la base de données Odoo
|
|
username: Nom d'utilisateur pour la connexion
|
|
api_key: Clé API ou mot de passe pour l'authentification
|
|
"""
|
|
self.url = url.rstrip('/')
|
|
self.db = db
|
|
self.username = username
|
|
self.api_key = api_key
|
|
self.uid = None
|
|
self.session = requests.Session()
|
|
self.session.headers.update({
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
})
|
|
self.max_retries = 3
|
|
self.timeout = 30 # secondes
|
|
|
|
def login(self) -> bool:
|
|
"""
|
|
Se connecte à l'API Odoo en utilisant les identifiants fournis.
|
|
|
|
Returns:
|
|
True si l'authentification réussie, False sinon
|
|
"""
|
|
try:
|
|
logging.info(f"Tentative de connexion à {self.url} avec l'utilisateur {self.username}")
|
|
endpoint = '/web/session/authenticate'
|
|
|
|
payload = {
|
|
"jsonrpc": "2.0",
|
|
"params": {
|
|
"db": self.db,
|
|
"login": self.username,
|
|
"password": self.api_key
|
|
}
|
|
}
|
|
|
|
response = self.session.post(
|
|
f"{self.url}{endpoint}",
|
|
data=json.dumps(payload),
|
|
timeout=self.timeout
|
|
)
|
|
response.raise_for_status()
|
|
|
|
result = response.json()
|
|
if 'error' in result:
|
|
error = result['error']
|
|
logging.error(f"Erreur d'authentification: {error.get('message', 'Erreur inconnue')}")
|
|
return False
|
|
|
|
self.uid = result.get('result', {}).get('uid')
|
|
if not self.uid:
|
|
logging.error("Erreur: UID non trouvé dans la réponse d'authentification")
|
|
return False
|
|
|
|
logging.info(f"Authentification réussie. UID: {self.uid}")
|
|
return True
|
|
|
|
except requests.RequestException as e:
|
|
logging.error(f"Erreur de connexion à l'API Odoo: {e}")
|
|
return False
|
|
except json.JSONDecodeError as e:
|
|
logging.error(f"Erreur de décodage JSON: {e}")
|
|
return False
|
|
except Exception as e:
|
|
logging.error(f"Erreur inattendue lors de l'authentification: {e}")
|
|
return False
|
|
|
|
def _rpc_call(self, endpoint: str, params: Dict[str, Any], retry_count: int = 0) -> Any:
|
|
"""
|
|
Effectue un appel RPC à l'API Odoo.
|
|
|
|
Args:
|
|
endpoint: Point de terminaison de l'API
|
|
params: Paramètres de l'appel
|
|
retry_count: Nombre de tentatives actuelles (pour les nouvelles tentatives)
|
|
|
|
Returns:
|
|
Résultat de l'appel RPC ou None en cas d'erreur
|
|
"""
|
|
if not self.uid and endpoint != '/web/session/authenticate':
|
|
logging.warning("Tentative d'appel RPC sans être authentifié. Reconnexion...")
|
|
if not self.login():
|
|
logging.error("Échec de la reconnexion")
|
|
return None
|
|
|
|
try:
|
|
payload = {
|
|
"jsonrpc": "2.0",
|
|
"params": params
|
|
}
|
|
|
|
response = self.session.post(
|
|
f"{self.url}{endpoint}",
|
|
data=json.dumps(payload),
|
|
timeout=self.timeout
|
|
)
|
|
response.raise_for_status()
|
|
|
|
result = response.json()
|
|
if 'error' in result:
|
|
error = result['error']
|
|
error_msg = error.get('message', 'Erreur inconnue')
|
|
error_data = error.get('data', {})
|
|
error_name = error_data.get('name', 'UnknownError')
|
|
logging.error(f"Erreur RPC: {error_name} - {error_msg}")
|
|
|
|
# Gérer les erreurs d'authentification
|
|
if "session expired" in error_msg or "Access denied" in error_msg:
|
|
if retry_count < self.max_retries:
|
|
logging.info("Session expirée, nouvelle tentative d'authentification...")
|
|
if self.login():
|
|
return self._rpc_call(endpoint, params, retry_count + 1)
|
|
|
|
return None
|
|
|
|
return result.get('result')
|
|
|
|
except requests.RequestException as e:
|
|
logging.error(f"Erreur de requête RPC: {e}")
|
|
if retry_count < self.max_retries:
|
|
logging.info(f"Nouvelle tentative ({retry_count + 1}/{self.max_retries})...")
|
|
return self._rpc_call(endpoint, params, retry_count + 1)
|
|
return None
|
|
except json.JSONDecodeError as e:
|
|
logging.error(f"Erreur de décodage JSON dans la réponse RPC: {e}")
|
|
return None
|
|
except Exception as e:
|
|
logging.error(f"Erreur inattendue lors de l'appel RPC: {e}")
|
|
return None
|
|
|
|
def search_read(self, model: str, domain: list, fields: list, **kwargs) -> list:
|
|
"""
|
|
Effectue une recherche et lecture sur le modèle spécifié.
|
|
|
|
Args:
|
|
model: Nom du modèle Odoo
|
|
domain: Domaine de recherche (filtres)
|
|
fields: Liste des champs à récupérer
|
|
**kwargs: Arguments supplémentaires (limit, offset, etc.)
|
|
|
|
Returns:
|
|
Liste des enregistrements trouvés
|
|
"""
|
|
params = {
|
|
"model": model,
|
|
"method": "search_read",
|
|
"args": [domain, fields],
|
|
"kwargs": kwargs
|
|
}
|
|
|
|
return self._rpc_call("/web/dataset/call_kw", params) or []
|
|
|
|
def read(self, model: str, ids: list, fields: list) -> list:
|
|
"""
|
|
Lit les enregistrements spécifiés par leurs IDs.
|
|
|
|
Args:
|
|
model: Nom du modèle Odoo
|
|
ids: Liste des IDs des enregistrements à lire
|
|
fields: Liste des champs à récupérer
|
|
|
|
Returns:
|
|
Liste des enregistrements lus
|
|
"""
|
|
if not ids:
|
|
return []
|
|
|
|
params = {
|
|
"model": model,
|
|
"method": "read",
|
|
"args": [ids, fields],
|
|
"kwargs": {}
|
|
}
|
|
|
|
return self._rpc_call("/web/dataset/call_kw", params) or []
|
|
|
|
def get_fields(self, model: str) -> Dict[str, Any]:
|
|
"""
|
|
Récupère les informations sur les champs d'un modèle.
|
|
|
|
Args:
|
|
model: Nom du modèle Odoo
|
|
|
|
Returns:
|
|
Dictionnaire avec les informations sur les champs
|
|
"""
|
|
params = {
|
|
"model": model,
|
|
"method": "fields_get",
|
|
"args": [],
|
|
"kwargs": {}
|
|
}
|
|
|
|
return self._rpc_call("/web/dataset/call_kw", params) or {}
|
|
|
|
|
|
# Fonctions d'aide pour centraliser l'authentification
|
|
def load_config(config_file: str = "config.json") -> Dict[str, Any]:
|
|
"""
|
|
Charge le fichier de configuration.
|
|
|
|
Args:
|
|
config_file: Chemin vers le fichier de configuration
|
|
|
|
Returns:
|
|
Dictionnaire contenant les paramètres de configuration
|
|
"""
|
|
try:
|
|
with open(config_file, "r", encoding='utf-8') as f:
|
|
return json.load(f)
|
|
except Exception as e:
|
|
logging.error(f"Erreur lors du chargement du fichier de configuration: {e}")
|
|
return {}
|
|
|
|
def get_auth_manager(config_file: str = "config.json", force_new: bool = False) -> Optional[AuthManager]:
|
|
"""
|
|
Obtient une instance unique du gestionnaire d'authentification.
|
|
|
|
Args:
|
|
config_file: Chemin vers le fichier de configuration
|
|
force_new: Si True, force la création d'une nouvelle instance
|
|
|
|
Returns:
|
|
Instance du gestionnaire d'authentification ou None en cas d'erreur
|
|
"""
|
|
global _auth_manager_instance
|
|
|
|
# Si une instance existe et que force_new est False, retourner l'instance existante
|
|
if _auth_manager_instance is not None and not force_new:
|
|
return _auth_manager_instance
|
|
|
|
# Charger la configuration
|
|
config = load_config(config_file)
|
|
|
|
# Extraire les informations de connexion
|
|
odoo_config = config.get("odoo", {})
|
|
url = odoo_config.get("url")
|
|
db = odoo_config.get("db")
|
|
username = odoo_config.get("username")
|
|
api_key = odoo_config.get("api_key")
|
|
|
|
if not all([url, db, username, api_key]):
|
|
logging.error("Informations de connexion Odoo manquantes dans le fichier de configuration")
|
|
return None
|
|
|
|
# Créer une nouvelle instance
|
|
try:
|
|
auth_manager = AuthManager(
|
|
url=url,
|
|
db=db,
|
|
username=username,
|
|
api_key=api_key
|
|
)
|
|
|
|
# Tenter de se connecter
|
|
if not auth_manager.login():
|
|
logging.error("Échec de la connexion à l'API Odoo")
|
|
return None
|
|
|
|
# Stocker l'instance pour les appels futurs
|
|
_auth_manager_instance = auth_manager
|
|
return auth_manager
|
|
|
|
except Exception as e:
|
|
logging.exception(f"Erreur lors de l'initialisation du gestionnaire d'authentification: {e}")
|
|
return None
|
|
|
|
def get_output_dir(config_file: str = "config.json", subdir: Optional[str] = None) -> str:
|
|
"""
|
|
Obtient le répertoire de sortie à partir de la configuration.
|
|
|
|
Args:
|
|
config_file: Chemin vers le fichier de configuration
|
|
subdir: Sous-répertoire à ajouter au chemin (optionnel)
|
|
|
|
Returns:
|
|
Chemin du répertoire de sortie
|
|
"""
|
|
config = load_config(config_file)
|
|
output_dir = config.get("output_dir", "output")
|
|
|
|
if subdir:
|
|
return os.path.join(output_dir, subdir)
|
|
|
|
return output_dir
|
|
|