"""Interface commune aux backends de jointure de domaine (Linux/Windows).""" from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass from typing import Callable, Optional @dataclass class JoinResult: success: bool message: str needs_reboot: bool = False OutputCallback = Callable[[str], None] class DomainJoinBackend(ABC): """Backend de jointure à un domaine Active Directory.""" @abstractmethod def is_available(self) -> tuple[bool, str]: """Indique si les outils nécessaires sont présents. Retourne (disponible, message).""" @abstractmethod def join( self, domain: str, username: str, password: str, ou: Optional[str] = None, computer_name: Optional[str] = None, on_output: Optional[OutputCallback] = None, ) -> JoinResult: """Rejoint le domaine. Le mot de passe n'est jamais passé en argument de ligne de commande : il est transmis via l'entrée standard du sous-processus pour ne pas apparaître dans la liste des processus.""" def can_leave(self) -> bool: """True si ce backend sait faire quitter le domaine au poste.""" return False def leave( self, domain: str, username: str, password: str, remove_packages: bool = False, on_output: Optional[OutputCallback] = None, ) -> JoinResult: """Fait quitter le domaine au poste. Comme pour join(), le mot de passe ne passe jamais par la ligne de commande. `remove_packages` demande en plus de désinstaller les paquets système devenus inutiles — sans effet sur les backends qui n'en installent pas. """ return JoinResult(success=False, message="Sortie de domaine non prise en charge pour ce backend.") def can_install_prerequisites(self) -> bool: """True si ce backend sait installer automatiquement les outils manquants.""" return False def install_prerequisites(self, on_output: Optional[OutputCallback] = None) -> JoinResult: """Installe les outils manquants. À surcharger si can_install_prerequisites() est vrai.""" return JoinResult(success=False, message="Installation automatique non prise en charge pour ce backend.")