227 Zeilen
11 KiB
Python
227 Zeilen
11 KiB
Python
"""
|
|
Basis-Klasse für alle Platform Worker Threads zur Eliminierung von Code-Duplikation
|
|
"""
|
|
from abc import ABC, abstractmethod
|
|
from PyQt5.QtCore import QThread, pyqtSignal
|
|
from typing import Dict, Any, Optional
|
|
from utils.text_similarity import TextSimilarity
|
|
from domain.value_objects.browser_protection_style import BrowserProtectionStyle, ProtectionLevel
|
|
import traceback
|
|
|
|
|
|
class BaseAccountCreationWorkerThread(QThread):
|
|
"""Basis-Klasse für alle Platform Worker Threads"""
|
|
|
|
# Signals MÜSSEN identisch zu bestehenden sein
|
|
update_signal = pyqtSignal(str)
|
|
log_signal = pyqtSignal(str)
|
|
progress_signal = pyqtSignal(int)
|
|
finished_signal = pyqtSignal(dict)
|
|
error_signal = pyqtSignal(str)
|
|
|
|
def __init__(self, params: Dict[str, Any], platform_name: str,
|
|
session_controller: Optional[Any] = None,
|
|
generator_tab: Optional[Any] = None):
|
|
super().__init__()
|
|
self.params = params
|
|
self.platform_name = platform_name
|
|
self.session_controller = session_controller
|
|
self.generator_tab = generator_tab
|
|
self.running = True
|
|
|
|
# TextSimilarity für robustes Fehler-Matching
|
|
self.text_similarity = TextSimilarity(default_threshold=0.8)
|
|
|
|
# Platform-spezifische Error-Patterns (überschreibbar)
|
|
self.error_interpretations = self.get_error_interpretations()
|
|
|
|
@abstractmethod
|
|
def get_automation_class(self):
|
|
"""Muss von Subklassen implementiert werden"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_error_interpretations(self) -> Dict[str, str]:
|
|
"""Platform-spezifische Fehlerinterpretationen"""
|
|
pass
|
|
|
|
def run(self):
|
|
"""Gemeinsame Logik für Account-Erstellung - IDENTISCH zum Original"""
|
|
try:
|
|
self.update_signal.emit("Status: Initialisierung...")
|
|
self.log_signal.emit(f"{self.platform_name}-Account-Erstellung gestartet...")
|
|
self.progress_signal.emit(10)
|
|
|
|
# Automation-Klasse dynamisch laden
|
|
AutomationClass = self.get_automation_class()
|
|
|
|
# WICHTIG: Exakt gleiche Parameter wie im Original
|
|
# Prüfe ob die Automation-Klasse die neuen Parameter unterstützt
|
|
automation_params = {
|
|
# Unterstütze beide Parameter-Namen für Abwärtskompatibilität
|
|
"headless": self.params.get("headless", not self.params.get("show_browser", False)),
|
|
"proxy_type": self.params.get("proxy_type", "NoProxy")
|
|
}
|
|
|
|
# Optionale Parameter nur hinzufügen wenn unterstützt
|
|
import inspect
|
|
init_signature = inspect.signature(AutomationClass.__init__)
|
|
param_names = list(init_signature.parameters.keys())
|
|
|
|
if "fingerprint" in param_names:
|
|
fingerprint_data = self.params.get("fingerprint")
|
|
# Handle BrowserFingerprint object vs dict
|
|
if fingerprint_data and hasattr(fingerprint_data, 'to_dict'):
|
|
automation_params["fingerprint"] = fingerprint_data.to_dict()
|
|
else:
|
|
automation_params["fingerprint"] = fingerprint_data
|
|
if "imap_handler" in param_names:
|
|
automation_params["imap_handler"] = self.params.get("imap_handler")
|
|
if "phone_service" in param_names:
|
|
automation_params["phone_service"] = self.params.get("phone_service")
|
|
if "use_proxy" in param_names:
|
|
automation_params["use_proxy"] = self.params.get("use_proxy", False)
|
|
if "save_screenshots" in param_names:
|
|
automation_params["save_screenshots"] = True
|
|
if "debug" in param_names:
|
|
automation_params["debug"] = self.params.get("debug", False)
|
|
if "email_domain" in param_names:
|
|
automation_params["email_domain"] = self.params.get("email_domain", "z5m7q9dk3ah2v1plx6ju.com")
|
|
if "window_position" in param_names:
|
|
automation_params["window_position"] = self.params.get("window_position")
|
|
|
|
automation = AutomationClass(**automation_params)
|
|
|
|
# Setze Callback für kundenfreundliche Logs
|
|
automation.set_customer_log_callback(lambda msg: self.log_signal.emit(msg))
|
|
|
|
self.update_signal.emit(f"{self.platform_name}-Automation initialisiert")
|
|
self.progress_signal.emit(20)
|
|
|
|
# Browser-Schutz wird jetzt direkt in base_automation.py nach Browser-Start angewendet
|
|
|
|
# Account registrieren
|
|
self.log_signal.emit(f"Registriere Account für: {self.params['full_name']}")
|
|
|
|
# Account registrieren mit allen Original-Parametern
|
|
# Erstelle saubere Parameter für register_account
|
|
register_params = {
|
|
"full_name": self.params["full_name"],
|
|
"age": self.params["age"],
|
|
"registration_method": self.params.get("registration_method", "email"),
|
|
"email_domain": self.params.get("email_domain", "z5m7q9dk3ah2v1plx6ju.com")
|
|
}
|
|
|
|
# Füge optionale Parameter hinzu wenn vorhanden
|
|
if "phone_number" in self.params:
|
|
register_params["phone_number"] = self.params["phone_number"]
|
|
|
|
# Additional params separat behandeln
|
|
if "additional_params" in self.params:
|
|
register_params.update(self.params["additional_params"])
|
|
|
|
result = automation.register_account(**register_params)
|
|
|
|
if result["success"]:
|
|
# Stelle sicher, dass die Datenstruktur kompatibel ist
|
|
if "account_data" not in result:
|
|
# Wenn account_data nicht existiert, erstelle es aus den Top-Level-Feldern
|
|
result["account_data"] = {
|
|
"username": result.get("username", ""),
|
|
"password": result.get("password", ""),
|
|
"email": result.get("email", ""),
|
|
"phone": result.get("phone", "")
|
|
}
|
|
|
|
fingerprint_data = self.params.get("fingerprint")
|
|
# Handle BrowserFingerprint object vs dict
|
|
if fingerprint_data and hasattr(fingerprint_data, 'to_dict'):
|
|
result["fingerprint"] = fingerprint_data.to_dict()
|
|
else:
|
|
result["fingerprint"] = fingerprint_data
|
|
self.log_signal.emit("Account erfolgreich erstellt!")
|
|
self.finished_signal.emit(result)
|
|
self.progress_signal.emit(100)
|
|
|
|
# Session-Speicherung wenn verfügbar
|
|
self._save_session_if_available(result)
|
|
else:
|
|
error_msg = result.get("error", "Unbekannter Fehler")
|
|
interpreted_error = self._interpret_error(error_msg)
|
|
self.log_signal.emit(f"Fehler bei der Account-Erstellung: {interpreted_error}")
|
|
self.error_signal.emit(interpreted_error)
|
|
self.progress_signal.emit(0) # Reset progress on error
|
|
|
|
except Exception as e:
|
|
error_msg = str(e)
|
|
self.log_signal.emit(f"Schwerwiegender Fehler: {error_msg}")
|
|
self.log_signal.emit(traceback.format_exc())
|
|
|
|
interpreted_error = self._interpret_error(error_msg)
|
|
self.error_signal.emit(interpreted_error)
|
|
self.progress_signal.emit(0) # Reset progress on error
|
|
|
|
def _interpret_error(self, error_message: str) -> str:
|
|
"""Interpretiert Fehler mit Fuzzy-Matching"""
|
|
error_lower = error_message.lower()
|
|
|
|
for pattern, interpretation in self.error_interpretations.items():
|
|
if pattern in error_lower or self.text_similarity.is_similar(pattern, error_lower, threshold=0.8):
|
|
return interpretation
|
|
|
|
return f"Fehler bei der Registrierung: {error_message}"
|
|
|
|
|
|
def _save_session_if_available(self, result: Dict[str, Any]):
|
|
"""Speichert Session wenn Controller verfügbar"""
|
|
# Session über SessionController speichern wenn verfügbar
|
|
if hasattr(self, 'session_controller') and self.session_controller:
|
|
try:
|
|
# Verwende den SessionController direkt für Clean Architecture
|
|
if hasattr(self.session_controller, 'create_and_save_account'):
|
|
# Account-Daten aus dem korrekten Pfad extrahieren
|
|
if "account_data" in result:
|
|
account_data = result["account_data"]
|
|
else:
|
|
account_data = {
|
|
'username': result.get("username"),
|
|
'password': result.get("password"),
|
|
'email': result.get("email"),
|
|
'phone': result.get("phone")
|
|
}
|
|
|
|
save_result = self.session_controller.create_and_save_account(
|
|
platform=self.platform_name,
|
|
account_data=account_data
|
|
)
|
|
|
|
if save_result.get('success'):
|
|
self.log_signal.emit(f"Session erfolgreich gespeichert")
|
|
else:
|
|
self.log_signal.emit(f"Warnung: Session konnte nicht gespeichert werden")
|
|
|
|
except Exception as e:
|
|
self.log_signal.emit(f"Warnung: Session konnte nicht gespeichert werden: {e}")
|
|
|
|
# Alternativ: Signal an Generator Tab senden
|
|
elif hasattr(self, 'generator_tab') and self.generator_tab:
|
|
try:
|
|
if hasattr(self.generator_tab, 'account_created'):
|
|
# Account-Daten aus dem korrekten Pfad extrahieren
|
|
if "account_data" in result:
|
|
account_data = result["account_data"]
|
|
else:
|
|
account_data = {
|
|
'username': result.get("username"),
|
|
'password': result.get("password"),
|
|
'email': result.get("email"),
|
|
'phone': result.get("phone")
|
|
}
|
|
self.generator_tab.account_created.emit(self.platform_name, account_data)
|
|
except Exception as e:
|
|
self.log_signal.emit(f"Warnung: Konnte Account-Daten nicht an UI senden: {e}")
|
|
|
|
def stop(self):
|
|
"""Stoppt den Thread"""
|
|
self.running = False
|
|
self.terminate() |