# -*- coding: utf-8 -*- # These imports will work in an Odoo environment, even if your IDE marks them as not found # pylint: disable=import-error from odoo import models, fields, api, _ from odoo.exceptions import UserError, ValidationError # pylint: enable=import-error import json import logging import requests import urllib3 from datetime import datetime, timedelta from requests.exceptions import RequestException _logger = logging.getLogger(__name__) class UnifiSiteManager(models.Model): """Extension du modèle UnifiSite pour l'API Site Manager (Cloud) Cette classe ajoute les champs et méthodes spécifiques à l'API Site Manager cloud. Elle est utilisée lorsque api_type = 'site_manager'. """ _name = 'unifi.site.manager' _description = 'UniFi Site Manager API' # Champs pour établir la relation avec unifi.site site_id = fields.Many2one( comodel_name='unifi.site', string='Site', required=True, ondelete='cascade', help='Site associé à cette configuration API Site Manager' ) # Champs nécessaires pour le fonctionnement du modèle name = fields.Char(related='site_id.name', string='Nom', readonly=True) api_type = fields.Selection(related='site_id.api_type', string='Type API', readonly=True) verify_ssl = fields.Boolean(string='Verify SSL', default=True) last_sync = fields.Datetime(string='Dernière synchronisation') def test_connection(self): """Teste la connexion à l'API Site Manager Cette méthode tente d'établir une connexion avec l'API Site Manager pour vérifier que les paramètres de connexion sont corrects. Returns: bool: True si la connexion est établie avec succès, False sinon """ try: # Utiliser la méthode existante pour tester la connexion return self._test_site_manager_connection() except Exception as e: _logger.error('Erreur lors du test de connexion à l\'API Site Manager: %s', str(e)) return False def _make_request(self, method, endpoint, data=None, params=None, headers=None): """Effectue une requête HTTP vers l'API Site Manager Cette méthode gère les requêtes HTTP vers l'API Site Manager, en incluant les en-têtes d'authentification et en gérant les erreurs. Args: method: Méthode HTTP (GET, POST, PUT, DELETE) endpoint: Point de terminaison API (chemin relatif) data: Données à envoyer dans le corps de la requête (optionnel) params: Paramètres de requête (optionnel) headers: En-têtes HTTP supplémentaires (optionnel) Returns: Response: Objet réponse HTTP Raises: RequestException: Si une erreur se produit lors de la requête """ self.ensure_one() # Créer un log API pour cette requête api_log = self.env['unifi.api.log'].create({ 'site_id': self.site_id.id, 'api_type': 'site_manager', 'endpoint': endpoint, 'method': method, 'request_body': json.dumps(data) if data else '', 'request_params': json.dumps(params) if params else '', 'request_headers': json.dumps(headers) if headers else '', 'start_time': fields.Datetime.now(), }) try: # Désactiver les avertissements SSL si verify_ssl est False if not self.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Construire l'URL de base base_url = "https://sitemanager.unifi.ui.com" url = f"{base_url}{endpoint}" # Préparer les en-têtes avec la clé API default_headers = { 'Content-Type': 'application/json', 'User-Agent': 'Odoo UniFi Integration', 'Authorization': f'Bearer {self.api_key}' } # Fusionner les en-têtes par défaut avec les en-têtes personnalisées if headers: default_headers.update(headers) # Effectuer la requête HTTP response = requests.request( method=method, url=url, json=data if data else None, params=params, headers=default_headers, verify=self.verify_ssl, timeout=30 ) # Mettre à jour le log API avec la réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_body': response.text if response.text else '', 'response_headers': json.dumps(dict(response.headers)) if response.headers else '', 'duration': (fields.Datetime.now() - api_log.start_time).total_seconds() * 1000, }) # Gérer les erreurs HTTP response.raise_for_status() return response except RequestException as e: # Mettre à jour le log API avec l'erreur api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': e.response.status_code if hasattr(e, 'response') and e.response else 0, 'error_message': str(e), 'duration': (fields.Datetime.now() - api_log.start_time).total_seconds() * 1000, }) _logger.error('Erreur lors de la requête HTTP vers l\'API Site Manager: %s', str(e)) raise @api.model def _check_required_fields(self, site): """Vérifie que les champs requis pour l'API Site Manager sont renseignés Cette méthode est appelée par le modèle principal lors de la validation des contraintes. Args: site: L'enregistrement du site à vérifier Raises: ValidationError: Si des champs requis ne sont pas renseignés """ if not site.api_key: raise ValidationError(_("Le champ 'API Key' est requis pour l'API Site Manager.")) if site.mfa_enabled and not site.mfa_token: raise ValidationError(_("Le champ 'MFA Token' est requis lorsque l'authentification à deux facteurs est activée.")) @api.model def _create_or_update_api_log(self, api_log=None, **kwargs): """Crée ou met à jour un enregistrement de log API Cette méthode d'aide simplifie la gestion des logs API en créant un nouvel enregistrement si api_log est None, ou en mettant à jour l'enregistrement existant sinon. Args: api_log: L'enregistrement de log API existant, ou None pour en créer un nouveau **kwargs: Les valeurs à écrire dans l'enregistrement Returns: L'enregistrement de log API créé ou mis à jour """ if not api_log: # Valeurs par défaut pour la création default_values = { 'site_id': self.id, 'api_type': 'site_manager', 'method': 'GET', 'endpoint': 'error_handler', 'start_time': fields.Datetime.now() } # Fusionner les valeurs par défaut avec les valeurs fournies values = {**default_values, **kwargs} return self.env['unifi.api.log'].create(values) else: # Mettre à jour l'enregistrement existant api_log.write(kwargs) return api_log def _clear_irrelevant_fields(self, site): """Nettoie les champs qui ne sont pas pertinents pour l'API Site Manager Cette méthode est appelée par le modèle principal lors du changement de type d'API. Elle supprime les enregistrements unifi.site.controller associés au site. Args: site: L'enregistrement du site à nettoyer """ # Rechercher et supprimer les enregistrements unifi.site.controller associés au site controllers = self.env['unifi.site.controller'].search([('site_id', '=', site.id)]) if controllers: _logger.info("Suppression des enregistrements unifi.site.controller associés au site %s", site.name) controllers.unlink() # Site Manager API fields - Only used when api_type = 'site_manager' api_key = fields.Char( string='API Key', help='API key for Site Manager authentication' ) mfa_enabled = fields.Boolean( string='MFA Enabled', default=False, help='Whether two-factor authentication is enabled for this site' ) mfa_token = fields.Char( string='MFA Token', help='Two-factor authentication token if enabled' ) def _test_site_manager_connection(self): """Test connection to the Site Manager API""" self.ensure_one() if self.api_type != 'site_manager': return False # Disable SSL warnings if verify_ssl is False if not self.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Create a new session for this connection test session = requests.Session() # Build the API URL base_url = "https://sitemanager.unifi.ui.com/api" sites_url = f"{base_url}/sites" # Prepare headers with API key headers = { 'Content-Type': 'application/json', 'User-Agent': 'Odoo UniFi Integration', 'Authorization': f'Bearer {self.api_key}' } # Add MFA token if enabled if self.mfa_enabled and self.mfa_token: headers['X-MFA-Token'] = self.mfa_token # Initialiser le log API api_log = self.env['unifi.api.log'].create({ 'site_id': self.site_id.id, 'api_type': 'site_manager', 'endpoint': sites_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) try: # Make the request response = session.get( sites_url, headers=headers, verify=self.verify_ssl, timeout=10 ) # Update the API log with response data api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Return True if the request was successful return response.status_code == 200 except Exception as e: # Utiliser la méthode d'aide pour créer ou mettre à jour le log API if self.env.get('unifi.api.log'): self._create_or_update_api_log( api_log=api_log, end_time=fields.Datetime.now(), error_message=str(e) ) _logger.error("Error testing connection to Site Manager API: %s", str(e)) return False finally: # Close the session session.close() @api.model def get_system_info_data(self, site): """Récupère les données d'information système du site Cette méthode utilise l'API Site Manager pour obtenir les informations système. Args: site: L'enregistrement du site UniFi Returns: dict: Données d'information système """ # Créer une session pour les requêtes session = requests.Session() # URL de base pour l'API Site Manager base_url = "https://sitemanager.unifi.ui.com/api" # Préparer les en-têtes avec la clé API headers = { 'Content-Type': 'application/json', 'User-Agent': 'Odoo UniFi Integration', 'Authorization': f'Bearer {site.api_key}' } # Ajouter le token MFA si activé if site.mfa_enabled and site.mfa_token: headers['X-MFA-Token'] = site.mfa_token # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Construire l'URL pour récupérer les données système system_url = f"{base_url}/sites/{site.site_id}/system" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': system_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête pour récupérer les données système response = session.get( system_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données système: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if not data: _logger.error("Aucune donnée système trouvée dans la réponse") return False # Retourner les données système return data except (RequestException, json.JSONDecodeError) as e: # Journaliser l'erreur error_msg = f"Erreur lors de la récupération des données système: {str(e)}" if api_log: api_log.write({ 'end_time': fields.Datetime.now(), 'error_message': error_msg }) _logger.error(error_msg) return False finally: # Fermer la session session.close() @api.model def get_device_data(self, site, mac_address=None): """Récupère les données d'un appareil spécifique ou de tous les appareils du site Cette méthode utilise l'API Site Manager pour obtenir les informations sur les appareils. Args: site: L'enregistrement du site UniFi mac_address: Adresse MAC de l'appareil spécifique à récupérer (optionnel) Returns: dict ou list: Données de l'appareil ou liste des données de tous les appareils """ # Créer une session pour les requêtes session = requests.Session() # URL de base pour l'API Site Manager base_url = "https://api.cloud.ui.com" # URL pour l'authentification auth_url = f"{base_url}/auth/login" # Données d'authentification auth_data = { 'username': site.username, 'password': site.password, 'token': site.api_key or '', 'rememberMe': True } # En-têtes de la requête headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': auth_url, 'method': 'POST', 'request_headers': json.dumps(headers), 'request_body': json.dumps(auth_data), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête d'authentification response = session.post( auth_url, json=auth_data, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si l'authentification a réussi if response.status_code != 200: _logger.error("Erreur d'authentification à l'API Site Manager: %s", response.text) return False # Extraire le token d'authentification auth_response = response.json() if 'access_token' not in auth_response: _logger.error("Token d'authentification non trouvé dans la réponse") return False # Mettre à jour les en-têtes avec le token d'authentification headers['Authorization'] = f"Bearer {auth_response['access_token']}" # Construire l'URL pour récupérer les données des appareils if mac_address: # URL pour un appareil spécifique device_url = f"{base_url}/api/site/{site.site_id}/device/{mac_address}" else: # URL pour tous les appareils device_url = f"{base_url}/api/site/{site.site_id}/device" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': device_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des appareils response = session.get( device_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données des appareils: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if 'data' not in data: _logger.error("Aucune donnée d'appareil trouvée dans la réponse") return False # Retourner les données des appareils if mac_address and data['data']: # Retourner les données de l'appareil spécifique return data['data'] else: # Retourner la liste des données de tous les appareils return data['data'] except (RequestException, json.JSONDecodeError) as e: # Journaliser l'erreur error_msg = f"Erreur lors de la récupération des données des appareils: {str(e)}" if api_log: api_log.write({ 'end_time': fields.Datetime.now(), 'error_message': error_msg }) _logger.error(error_msg) return False finally: # Fermer la session session.close() @api.model def get_vlan_data(self, site): """Récupère les données des VLANs du site Cette méthode utilise l'API Site Manager pour obtenir les informations sur les VLANs. Args: site: L'enregistrement du site UniFi Returns: list: Liste des données de tous les VLANs """ # Initialiser api_log à None pour éviter les erreurs de variable potentiellement indépendante api_log = None # Créer une session pour les requêtes session = requests.Session() # URL de base pour l'API Site Manager base_url = "https://api.cloud.ui.com" # URL pour l'authentification auth_url = f"{base_url}/auth/login" # Données d'authentification auth_data = { 'username': site.username, 'password': site.password, 'token': site.api_key or '', 'rememberMe': True } # En-têtes de la requête headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': auth_url, 'method': 'POST', 'request_headers': json.dumps(headers), 'request_body': json.dumps(auth_data), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête d'authentification response = session.post( auth_url, json=auth_data, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si l'authentification a réussi if response.status_code != 200: _logger.error("Erreur d'authentification à l'API Site Manager: %s", response.text) return False # Extraire le token d'authentification auth_response = response.json() if 'access_token' not in auth_response: _logger.error("Token d'authentification non trouvé dans la réponse") return False # Mettre à jour les en-têtes avec le token d'authentification headers['Authorization'] = f"Bearer {auth_response['access_token']}" # Construire l'URL pour récupérer les données des VLANs vlan_url = f"{base_url}/api/site/{site.site_id}/vlan" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': vlan_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des VLANs response = session.get( vlan_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données des VLANs: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if 'data' not in data: _logger.error("Aucune donnée de VLAN trouvée dans la réponse") return False # Retourner la liste des données de tous les VLANs return data['data'] except (RequestException, json.JSONDecodeError) as e: # Journaliser l'erreur error_msg = f"Erreur lors de la récupération des données des VLANs: {str(e)}" if 'api_log' in locals() and api_log: api_log.write({ 'end_time': fields.Datetime.now(), 'error_message': error_msg }) _logger.error(error_msg) return False finally: # Fermer la session session.close() @api.model def get_network_data(self, site): """Récupère les données des réseaux du site Cette méthode utilise l'API Site Manager pour obtenir les informations sur les réseaux. Args: site: L'enregistrement du site UniFi Returns: list: Liste des données de tous les réseaux """ # Initialiser api_log à None pour éviter les erreurs de variable potentiellement indépendante api_log = None # Créer une session pour les requêtes session = requests.Session() # URL de base pour l'API Site Manager base_url = "https://api.cloud.ui.com" # URL pour l'authentification auth_url = f"{base_url}/auth/login" # Données d'authentification auth_data = { 'username': site.username, 'password': site.password, 'token': site.api_key or '', 'rememberMe': True } # En-têtes de la requête headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': auth_url, 'method': 'POST', 'request_headers': json.dumps(headers), 'request_body': json.dumps(auth_data), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête d'authentification response = session.post( auth_url, json=auth_data, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si l'authentification a réussi if response.status_code != 200: _logger.error("Erreur d'authentification à l'API Site Manager: %s", response.text) return False # Extraire le token d'authentification auth_response = response.json() if 'access_token' not in auth_response: _logger.error("Token d'authentification non trouvé dans la réponse") return False # Mettre à jour les en-têtes avec le token d'authentification headers['Authorization'] = f"Bearer {auth_response['access_token']}" # Construire l'URL pour récupérer les données des réseaux network_url = f"{base_url}/api/site/{site.site_id}/network" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': network_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des réseaux response = session.get( network_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données des réseaux: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if 'data' not in data: _logger.error("Aucune donnée de réseau trouvée dans la réponse") return False # Retourner la liste des données de tous les réseaux return data['data'] except (RequestException, json.JSONDecodeError) as e: # Journaliser l'erreur error_msg = f"Erreur lors de la récupération des données des réseaux: {str(e)}" if 'api_log' in locals() and api_log: api_log.write({ 'end_time': fields.Datetime.now(), 'error_message': error_msg }) _logger.error(error_msg) return False finally: # Fermer la session session.close() def _sync_site_manager(self): """Synchronize data with the Site Manager API""" self.ensure_one() if self.api_type != 'site_manager': return False # Create a sync job to track progress sync_job = self.env['unifi.sync.job'].create({ 'site_id': self.id, 'api_type': 'site_manager', 'status': 'running', 'start_time': fields.Datetime.now() }) try: # Implement synchronization logic here # This would typically involve: # 1. Authenticating with the Site Manager API # 2. Fetching site data # 3. Fetching device data # 4. Fetching network data # 5. Updating local records # For now, just a placeholder _logger.info("Starting synchronization with Site Manager API for site %s", self.name) # Update sync job with success status sync_job.write({ 'status': 'completed', 'end_time': fields.Datetime.now(), 'message': 'Synchronization completed successfully' }) # Update site's last sync timestamp self.write({ 'last_sync': fields.Datetime.now() }) return True except Exception as e: # Log the error and update sync job _logger.error("Error during synchronization with Site Manager API: %s", str(e)) sync_job.write({ 'status': 'failed', 'end_time': fields.Datetime.now(), 'message': f'Synchronization failed: {str(e)}' }) return False @api.model def get_user_data(self, site): """Récupère les données des utilisateurs du site Cette méthode utilise l'API Site Manager pour obtenir les informations sur les utilisateurs. Args: site: L'enregistrement du site UniFi Returns: list: Liste des données de tous les utilisateurs """ # Créer une session pour les requêtes session = requests.Session() # URL de base pour l'API Site Manager base_url = "https://api.cloud.ui.com" # URL pour l'authentification auth_url = f"{base_url}/auth/login" # Données d'authentification auth_data = { 'username': site.username, 'password': site.password, 'token': site.api_key or '', 'rememberMe': True } # En-têtes de la requête headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': auth_url, 'method': 'POST', 'request_headers': json.dumps(headers), 'request_body': json.dumps(auth_data), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête d'authentification response = session.post( auth_url, json=auth_data, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si l'authentification a réussi if response.status_code != 200: _logger.error("Erreur d'authentification à l'API Site Manager: %s", response.text) return False # Extraire le jeton d'authentification auth_response = response.json() if 'token' not in auth_response: _logger.error("Jeton d'authentification manquant dans la réponse de l'API Site Manager") return False # Mettre à jour les en-têtes avec le jeton d'authentification headers['Authorization'] = f"Bearer {auth_response['token']}" # Construire l'URL pour récupérer les données des utilisateurs # Pour les utilisateurs réguliers user_url = f"{base_url}/proxy/network/api/s/{site.site_id}/rest/user" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': user_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des utilisateurs response = session.get( user_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données des utilisateurs: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if 'data' not in data: _logger.warning("Aucune donnée d'utilisateur trouvée dans la réponse de l'API Site Manager") return [] # Récupérer également les utilisateurs invités guest_url = f"{base_url}/proxy/network/api/s/{site.site_id}/rest/guest" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': guest_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des utilisateurs invités guest_response = session.get( guest_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': guest_response.status_code, 'response_headers': json.dumps(dict(guest_response.headers)), 'response_body': guest_response.text }) # Si la requête pour les invités a réussi, ajouter les données à la liste if guest_response.status_code == 200: guest_data = guest_response.json() if 'data' in guest_data: # Marquer ces utilisateurs comme invités for guest in guest_data['data']: guest['is_guest'] = True # Ajouter les invités à la liste des utilisateurs data['data'].extend(guest_data['data']) return data['data'] except RequestException as e: # Gérer les erreurs de requête error_msg = f"Erreur lors de la récupération des données des utilisateurs: {str(e)}" if 'api_log' in locals() and api_log: api_log.write({ 'end_time': fields.Datetime.now(), 'error_message': error_msg }) _logger.error(error_msg) return False finally: # Fermer la session session.close() @api.model def get_firewall_data(self, site): """Récupère les données des règles de pare-feu du site Cette méthode utilise l'API Site Manager pour obtenir les informations sur les règles de pare-feu. Args: site: L'enregistrement du site UniFi Returns: list: Liste des données de toutes les règles de pare-feu """ # Créer une session pour les requêtes session = requests.Session() # URL de base pour l'API Site Manager base_url = "https://api.cloud.ui.com" # URL pour l'authentification auth_url = f"{base_url}/auth/login" # Données d'authentification auth_data = { 'username': site.username, 'password': site.password, 'token': site.api_key or '', 'rememberMe': True } # En-têtes de la requête headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': auth_url, 'method': 'POST', 'request_headers': json.dumps(headers), 'request_body': json.dumps(auth_data), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête d'authentification response = session.post( auth_url, json=auth_data, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si l'authentification a réussi if response.status_code != 200: _logger.error("Erreur d'authentification à l'API Site Manager: %s", response.text) return False # Extraire le jeton d'authentification auth_response = response.json() if 'token' not in auth_response: _logger.error("Jeton d'authentification manquant dans la réponse de l'API Site Manager") return False # Mettre à jour les en-têtes avec le jeton d'authentification headers['Authorization'] = f"Bearer {auth_response['token']}" # Construire l'URL pour récupérer les données des règles de pare-feu firewall_url = f"{base_url}/proxy/network/api/s/{site.site_id}/rest/firewallrule" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': firewall_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des règles de pare-feu response = session.get( firewall_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données des règles de pare-feu: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if 'data' not in data: _logger.warning("Aucune donnée de règle de pare-feu trouvée dans la réponse de l'API Site Manager") return [] return data['data'] except RequestException as e: # Gérer les erreurs de requête error_msg = f"Erreur lors de la récupération des données des règles de pare-feu: {str(e)}" if 'api_log' in locals() and api_log: api_log.write({ 'end_time': fields.Datetime.now(), 'error_message': error_msg }) _logger.error(error_msg) return False finally: # Fermer la session session.close() @api.model def get_port_forward_data(self, site): """Récupère les données des redirections de port du site Cette méthode utilise l'API Site Manager pour obtenir les informations sur les redirections de port. Args: site: L'enregistrement du site UniFi Returns: list: Liste des données de toutes les redirections de port """ # Créer une session pour les requêtes session = requests.Session() # Construire l'URL de base base_url = f"https://{site.host}:{site.port}" # URL pour la connexion login_url = f"{base_url}/api/auth/login" # Données de connexion login_data = { 'username': site.username, 'password': site.password } # En-têtes de la requête headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Désactiver les avertissements SSL si verify_ssl est False if not site.verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': login_url, 'method': 'POST', 'request_headers': json.dumps(headers), 'request_body': json.dumps(login_data), 'start_time': fields.Datetime.now() }) try: # Effectuer la requête de connexion response = session.post( login_url, json=login_data, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la connexion a réussi if response.status_code != 200: _logger.error("Erreur de connexion à l'API Site Manager: %s", response.text) return False # Analyser la réponse JSON auth_data = response.json() # Vérifier si la réponse contient un jeton d'authentification if 'data' not in auth_data or 'token' not in auth_data['data']: _logger.error("Aucun jeton d'authentification trouvé dans la réponse de l'API Site Manager") return False # Extraire le jeton d'authentification token = auth_data['data']['token'] # Mettre à jour les en-têtes avec le jeton d'authentification headers['Authorization'] = f"Bearer {token}" # Construire l'URL pour récupérer les données des redirections de port port_forward_url = f"{base_url}/proxy/network/api/s/{site.site_id}/rest/portforward" # Journaliser l'appel API api_log = self.env['unifi.api.log'].create({ 'site_id': site.id, 'api_type': 'site_manager', 'endpoint': port_forward_url, 'method': 'GET', 'request_headers': json.dumps(headers), 'start_time': fields.Datetime.now() }) # Effectuer la requête pour récupérer les données des redirections de port response = session.get( port_forward_url, headers=headers, verify=site.verify_ssl, timeout=10 ) # Mettre à jour le journal API avec les données de réponse api_log.write({ 'end_time': fields.Datetime.now(), 'status_code': response.status_code, 'response_headers': json.dumps(dict(response.headers)), 'response_body': response.text }) # Vérifier si la requête a réussi if response.status_code != 200: _logger.error("Erreur lors de la récupération des données des redirections de port: %s", response.text) return False # Analyser la réponse JSON data = response.json() # Vérifier si la réponse contient des données if 'data' not in data: _logger.warning("Aucune donnée de redirection de port trouvée dans la réponse de l'API Site Manager") return [] return data['data'] except RequestException as e: # Gérer les erreurs de requête _logger.error("Erreur lors de la communication avec l'API Site Manager: %s", str(e)) return False finally: # Fermer la session session.close()