Rollbackpunkt, alles außer TikTok geht, die wollen wieder so eine extra locke bei Login
Dieser Commit ist enthalten in:
@ -133,7 +133,7 @@ class BaseAccountCreationWorkerThread(QThread):
|
|||||||
register_params.update(self.params["additional_params"])
|
register_params.update(self.params["additional_params"])
|
||||||
|
|
||||||
result = automation.register_account(**register_params)
|
result = automation.register_account(**register_params)
|
||||||
|
|
||||||
if result["success"]:
|
if result["success"]:
|
||||||
# Stelle sicher, dass die Datenstruktur kompatibel ist
|
# Stelle sicher, dass die Datenstruktur kompatibel ist
|
||||||
if "account_data" not in result:
|
if "account_data" not in result:
|
||||||
@ -144,19 +144,48 @@ class BaseAccountCreationWorkerThread(QThread):
|
|||||||
"email": result.get("email", ""),
|
"email": result.get("email", ""),
|
||||||
"phone": result.get("phone", "")
|
"phone": result.get("phone", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# KRITISCHE VALIDIERUNG: Prüfe PFLICHTFELDER vor Weitergabe
|
||||||
|
account_data = result.get("account_data", {})
|
||||||
|
validation_errors = []
|
||||||
|
|
||||||
|
# Prüfe Username
|
||||||
|
if not account_data.get("username") or account_data["username"] == "":
|
||||||
|
validation_errors.append("Username fehlt oder ist leer")
|
||||||
|
|
||||||
|
# Prüfe Password
|
||||||
|
if not account_data.get("password") or account_data["password"] == "":
|
||||||
|
validation_errors.append("Passwort fehlt oder ist leer")
|
||||||
|
|
||||||
|
# Prüfe Email oder Phone (mindestens eins muss vorhanden sein)
|
||||||
|
if not account_data.get("email") and not account_data.get("phone"):
|
||||||
|
validation_errors.append("Weder E-Mail noch Telefon vorhanden")
|
||||||
|
|
||||||
|
# Wenn Validierungsfehler existieren, markiere als Fehler
|
||||||
|
if validation_errors:
|
||||||
|
error_msg = f"Account-Daten unvollständig: {', '.join(validation_errors)}"
|
||||||
|
self.log_signal.emit(f"VALIDIERUNGSFEHLER: {error_msg}")
|
||||||
|
self.log_signal.emit(f"Account-Daten: {account_data}")
|
||||||
|
self.error_signal.emit(error_msg)
|
||||||
|
self.progress_signal.emit(0)
|
||||||
|
return # Breche ab - sende KEIN finished_signal
|
||||||
|
|
||||||
fingerprint_data = self.params.get("fingerprint")
|
fingerprint_data = self.params.get("fingerprint")
|
||||||
# Handle BrowserFingerprint object vs dict
|
# Handle BrowserFingerprint object vs dict
|
||||||
if fingerprint_data and hasattr(fingerprint_data, 'to_dict'):
|
if fingerprint_data and hasattr(fingerprint_data, 'to_dict'):
|
||||||
result["fingerprint"] = fingerprint_data.to_dict()
|
result["fingerprint"] = fingerprint_data.to_dict()
|
||||||
else:
|
else:
|
||||||
result["fingerprint"] = fingerprint_data
|
result["fingerprint"] = fingerprint_data
|
||||||
|
|
||||||
self.log_signal.emit("Account erfolgreich erstellt!")
|
self.log_signal.emit("Account erfolgreich erstellt!")
|
||||||
self.finished_signal.emit(result)
|
|
||||||
self.progress_signal.emit(100)
|
self.progress_signal.emit(100)
|
||||||
|
|
||||||
# Session-Speicherung wenn verfügbar
|
# Session-Speicherung vor Benachrichtigung durchführen
|
||||||
self._save_session_if_available(result)
|
save_result = self._save_session_if_available(result)
|
||||||
|
if save_result is not None:
|
||||||
|
result["save_result"] = save_result
|
||||||
|
|
||||||
|
self.finished_signal.emit(result)
|
||||||
else:
|
else:
|
||||||
error_msg = result.get("error", "Unbekannter Fehler")
|
error_msg = result.get("error", "Unbekannter Fehler")
|
||||||
interpreted_error = self._interpret_error(error_msg)
|
interpreted_error = self._interpret_error(error_msg)
|
||||||
@ -184,12 +213,13 @@ class BaseAccountCreationWorkerThread(QThread):
|
|||||||
return f"Fehler bei der Registrierung: {error_message}"
|
return f"Fehler bei der Registrierung: {error_message}"
|
||||||
|
|
||||||
|
|
||||||
def _save_session_if_available(self, result: Dict[str, Any]):
|
def _save_session_if_available(self, result: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||||
"""Speichert Session wenn Controller verfügbar"""
|
"""Speichert Session wenn Controller verfügbar und gibt das Ergebnis zurück"""
|
||||||
|
save_result: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
# Session über SessionController speichern wenn verfügbar
|
# Session über SessionController speichern wenn verfügbar
|
||||||
if hasattr(self, 'session_controller') and self.session_controller:
|
if hasattr(self, 'session_controller') and self.session_controller:
|
||||||
try:
|
try:
|
||||||
# Verwende den SessionController direkt für Clean Architecture
|
|
||||||
if hasattr(self.session_controller, 'create_and_save_account'):
|
if hasattr(self.session_controller, 'create_and_save_account'):
|
||||||
# Account-Daten aus dem korrekten Pfad extrahieren
|
# Account-Daten aus dem korrekten Pfad extrahieren
|
||||||
if "account_data" in result:
|
if "account_data" in result:
|
||||||
@ -201,25 +231,30 @@ class BaseAccountCreationWorkerThread(QThread):
|
|||||||
'email': result.get("email"),
|
'email': result.get("email"),
|
||||||
'phone': result.get("phone")
|
'phone': result.get("phone")
|
||||||
}
|
}
|
||||||
|
|
||||||
save_result = self.session_controller.create_and_save_account(
|
save_result = self.session_controller.create_and_save_account(
|
||||||
platform=self.platform_name,
|
platform=self.platform_name,
|
||||||
account_data=account_data
|
account_data=account_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if save_result.get('success'):
|
if save_result.get('success'):
|
||||||
self.log_signal.emit(f"Session erfolgreich gespeichert")
|
self.log_signal.emit("Session erfolgreich gespeichert")
|
||||||
else:
|
else:
|
||||||
self.log_signal.emit(f"Warnung: Session konnte nicht gespeichert werden")
|
self.log_signal.emit("Warnung: Session konnte nicht gespeichert werden")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_signal.emit(f"Warnung: Session konnte nicht gespeichert werden: {e}")
|
error_msg = f"Warnung: Session konnte nicht gespeichert werden: {e}"
|
||||||
|
self.log_signal.emit(error_msg)
|
||||||
|
save_result = {
|
||||||
|
'success': False,
|
||||||
|
'error': str(e),
|
||||||
|
'message': error_msg
|
||||||
|
}
|
||||||
|
|
||||||
# Alternativ: Signal an Generator Tab senden
|
# Alternativ: Signal an Generator Tab senden
|
||||||
elif hasattr(self, 'generator_tab') and self.generator_tab:
|
elif hasattr(self, 'generator_tab') and self.generator_tab:
|
||||||
try:
|
try:
|
||||||
if hasattr(self.generator_tab, 'account_created'):
|
if hasattr(self.generator_tab, 'account_created'):
|
||||||
# Account-Daten aus dem korrekten Pfad extrahieren
|
|
||||||
if "account_data" in result:
|
if "account_data" in result:
|
||||||
account_data = result["account_data"]
|
account_data = result["account_data"]
|
||||||
else:
|
else:
|
||||||
@ -232,8 +267,10 @@ class BaseAccountCreationWorkerThread(QThread):
|
|||||||
self.generator_tab.account_created.emit(self.platform_name, account_data)
|
self.generator_tab.account_created.emit(self.platform_name, account_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_signal.emit(f"Warnung: Konnte Account-Daten nicht an UI senden: {e}")
|
self.log_signal.emit(f"Warnung: Konnte Account-Daten nicht an UI senden: {e}")
|
||||||
|
|
||||||
|
return save_result
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stoppt den Thread"""
|
"""Stoppt den Thread"""
|
||||||
self.running = False
|
self.running = False
|
||||||
self.terminate()
|
self.terminate()
|
||||||
|
|||||||
@ -180,50 +180,28 @@ class FacebookController(BasePlatformController):
|
|||||||
self.forge_dialog.start_animation()
|
self.forge_dialog.start_animation()
|
||||||
self.forge_dialog.show()
|
self.forge_dialog.show()
|
||||||
|
|
||||||
def handle_account_created(self, result: Dict[str, Any]):
|
def handle_account_created(self, result: Dict[str, Any]) -> bool:
|
||||||
"""Verarbeitet erfolgreich erstellte Accounts mit Clean Architecture."""
|
"""
|
||||||
|
Verarbeitet erfolgreich erstellte Accounts mit Clean Architecture.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True bei erfolgreicher Speicherung, False bei Fehler
|
||||||
|
"""
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
|
|
||||||
# Account-Daten aus dem Ergebnis holen
|
# Account-Daten aus dem Ergebnis holen
|
||||||
account_data = result.get("account_data", {})
|
account_data = result.get("account_data", {})
|
||||||
|
|
||||||
# Account und Session über SessionController speichern (Clean Architecture)
|
save_result = result.get("save_result")
|
||||||
if hasattr(self, 'session_controller') and self.session_controller:
|
|
||||||
|
# Account und Session nur speichern, wenn Worker es nicht bereits erledigt hat
|
||||||
|
if save_result is None and hasattr(self, 'session_controller') and self.session_controller:
|
||||||
try:
|
try:
|
||||||
session_data = result.get("session_data", {})
|
|
||||||
save_result = self.session_controller.create_and_save_account(
|
save_result = self.session_controller.create_and_save_account(
|
||||||
platform=self.platform_name,
|
platform=self.platform_name,
|
||||||
account_data=account_data
|
account_data=account_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if save_result.get('success'):
|
|
||||||
logger.info(f"Account und Session erfolgreich gespeichert")
|
|
||||||
|
|
||||||
# Erfolgsmeldung anzeigen (nur einmal!)
|
|
||||||
account_info = save_result.get('account_data', {})
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
QMessageBox.information(
|
|
||||||
generator_tab,
|
|
||||||
"Erfolg",
|
|
||||||
f"Account erfolgreich erstellt!\n\n"
|
|
||||||
f"Benutzername: {account_info.get('username', '')}\n"
|
|
||||||
f"Passwort: {account_info.get('password', '')}\n"
|
|
||||||
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Signal senden, um zur Hauptseite zurückzukehren
|
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
|
||||||
self.return_to_main_requested()
|
|
||||||
else:
|
|
||||||
error_msg = save_result.get('message', 'Unbekannter Fehler')
|
|
||||||
logger.error(f"Fehler beim Speichern: {error_msg}")
|
|
||||||
from views.widgets.modern_message_box import show_error
|
|
||||||
show_error(
|
|
||||||
generator_tab,
|
|
||||||
"Fehler beim Speichern",
|
|
||||||
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
||||||
from views.widgets.modern_message_box import show_critical
|
from views.widgets.modern_message_box import show_critical
|
||||||
@ -232,12 +210,47 @@ class FacebookController(BasePlatformController):
|
|||||||
"Unerwarteter Fehler",
|
"Unerwarteter Fehler",
|
||||||
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
||||||
)
|
)
|
||||||
|
return False # FEHLER
|
||||||
|
|
||||||
|
if save_result is not None:
|
||||||
|
if save_result.get('success'):
|
||||||
|
logger.info("Account und Session erfolgreich gespeichert")
|
||||||
|
|
||||||
|
account_info = save_result.get('account_data', account_data)
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
QMessageBox.information(
|
||||||
|
generator_tab,
|
||||||
|
"Erfolg",
|
||||||
|
f"Account erfolgreich erstellt!\n\n"
|
||||||
|
f"Benutzername: {account_info.get('username', '')}\n"
|
||||||
|
f"Passwort: {account_info.get('password', '')}\n"
|
||||||
|
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
error_msg = save_result.get('message') or save_result.get('error') or 'Unbekannter Fehler'
|
||||||
|
error_code = save_result.get('error_code', 0)
|
||||||
|
logger.error(f"Fehler beim Speichern (Code {error_code}): {error_msg}")
|
||||||
|
|
||||||
|
from views.widgets.modern_message_box import show_error
|
||||||
|
show_error(
|
||||||
|
generator_tab,
|
||||||
|
"Fehler beim Speichern",
|
||||||
|
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
||||||
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
||||||
generator_tab.account_created.emit(self.platform_name, account_data)
|
generator_tab.account_created.emit(self.platform_name, account_data)
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
self.return_to_main_requested()
|
self.return_to_main_requested()
|
||||||
|
return True # Annahme: Erfolgreich (keine Validierung möglich)
|
||||||
|
|
||||||
def _handle_error(self, error_msg: str):
|
def _handle_error(self, error_msg: str):
|
||||||
"""Behandelt Fehler während der Account-Erstellung"""
|
"""Behandelt Fehler während der Account-Erstellung"""
|
||||||
@ -253,13 +266,25 @@ class FacebookController(BasePlatformController):
|
|||||||
|
|
||||||
def _handle_finished(self, result: dict):
|
def _handle_finished(self, result: dict):
|
||||||
"""Behandelt das Ende der Account-Erstellung"""
|
"""Behandelt das Ende der Account-Erstellung"""
|
||||||
# Forge-Dialog schließen
|
# Dialog NICHT schließen - zeige Speicherstatus
|
||||||
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
self.forge_dialog.close()
|
self.forge_dialog.set_status("Speichere Account in Datenbank...")
|
||||||
self.forge_dialog = None
|
self.forge_dialog.add_log("Prüfe Account-Daten...")
|
||||||
|
|
||||||
# Normale Verarbeitung
|
# Account-Speicherung durchführen
|
||||||
self.handle_account_created(result)
|
save_success = self.handle_account_created(result)
|
||||||
|
|
||||||
|
# JETZT erst Dialog schließen (nach Speicherung)
|
||||||
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
|
if save_success:
|
||||||
|
self.forge_dialog.add_log("Account erfolgreich gespeichert!")
|
||||||
|
# Kurz warten, damit User die Meldung sieht
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
|
QTimer.singleShot(1000, self.forge_dialog.close)
|
||||||
|
else:
|
||||||
|
# Bei Fehler sofort schließen (Fehler-Dialog wird separat angezeigt)
|
||||||
|
self.forge_dialog.close()
|
||||||
|
self.forge_dialog = None
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die Facebook-Account-Erstellung."""
|
"""Stoppt die Facebook-Account-Erstellung."""
|
||||||
@ -301,4 +326,4 @@ class FacebookController(BasePlatformController):
|
|||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
"""Räumt Ressourcen auf."""
|
"""Räumt Ressourcen auf."""
|
||||||
self.stop_account_creation()
|
self.stop_account_creation()
|
||||||
logger.info("Facebook Controller aufgeräumt")
|
logger.info("Facebook Controller aufgeräumt")
|
||||||
|
|||||||
@ -290,42 +290,14 @@ class InstagramController(BasePlatformController):
|
|||||||
# Account-Daten aus dem Ergebnis holen
|
# Account-Daten aus dem Ergebnis holen
|
||||||
account_data = result.get("account_data", {})
|
account_data = result.get("account_data", {})
|
||||||
|
|
||||||
# Account und Session über SessionController speichern (Clean Architecture)
|
save_result = result.get("save_result")
|
||||||
if hasattr(self, 'session_controller') and self.session_controller:
|
|
||||||
|
if save_result is None and hasattr(self, 'session_controller') and self.session_controller:
|
||||||
try:
|
try:
|
||||||
session_data = result.get("session_data", {})
|
|
||||||
save_result = self.session_controller.create_and_save_account(
|
save_result = self.session_controller.create_and_save_account(
|
||||||
platform=self.platform_name,
|
platform=self.platform_name,
|
||||||
account_data=account_data
|
account_data=account_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if save_result.get('success'):
|
|
||||||
logger.info(f"Account und Session erfolgreich gespeichert")
|
|
||||||
|
|
||||||
# Erfolgsmeldung anzeigen (nur einmal!)
|
|
||||||
account_info = save_result.get('account_data', {})
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
QMessageBox.information(
|
|
||||||
generator_tab,
|
|
||||||
"Erfolg",
|
|
||||||
f"Account erfolgreich erstellt!\n\n"
|
|
||||||
f"Benutzername: {account_info.get('username', '')}\n"
|
|
||||||
f"Passwort: {account_info.get('password', '')}\n"
|
|
||||||
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Signal senden, um zur Hauptseite zurückzukehren
|
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
|
||||||
self.return_to_main_requested()
|
|
||||||
else:
|
|
||||||
error_msg = save_result.get('message', 'Unbekannter Fehler')
|
|
||||||
logger.error(f"Fehler beim Speichern: {error_msg}")
|
|
||||||
from views.widgets.modern_message_box import show_error
|
|
||||||
show_error(
|
|
||||||
generator_tab,
|
|
||||||
"Fehler beim Speichern",
|
|
||||||
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
||||||
from views.widgets.modern_message_box import show_critical
|
from views.widgets.modern_message_box import show_critical
|
||||||
@ -334,12 +306,41 @@ class InstagramController(BasePlatformController):
|
|||||||
"Unerwarteter Fehler",
|
"Unerwarteter Fehler",
|
||||||
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
||||||
)
|
)
|
||||||
else:
|
return
|
||||||
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
|
||||||
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
if save_result is not None:
|
||||||
generator_tab.account_created.emit(self.platform_name, account_data)
|
if save_result.get('success'):
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
logger.info("Account und Session erfolgreich gespeichert")
|
||||||
self.return_to_main_requested()
|
|
||||||
|
account_info = save_result.get('account_data', account_data)
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
QMessageBox.information(
|
||||||
|
generator_tab,
|
||||||
|
"Erfolg",
|
||||||
|
f"Account erfolgreich erstellt!\n\n"
|
||||||
|
f"Benutzername: {account_info.get('username', '')}\n"
|
||||||
|
f"Passwort: {account_info.get('password', '')}\n"
|
||||||
|
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
else:
|
||||||
|
error_msg = save_result.get('message') or save_result.get('error') or 'Unbekannter Fehler'
|
||||||
|
logger.error(f"Fehler beim Speichern: {error_msg}")
|
||||||
|
from views.widgets.modern_message_box import show_error
|
||||||
|
show_error(
|
||||||
|
generator_tab,
|
||||||
|
"Fehler beim Speichern",
|
||||||
|
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
||||||
|
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
||||||
|
generator_tab.account_created.emit(self.platform_name, account_data)
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
|
||||||
# save_account_to_db wurde entfernt - Accounts werden jetzt über SessionController gespeichert
|
# save_account_to_db wurde entfernt - Accounts werden jetzt über SessionController gespeichert
|
||||||
|
|
||||||
|
|||||||
@ -294,42 +294,14 @@ class TikTokController(BasePlatformController):
|
|||||||
# Account-Daten aus dem Ergebnis holen
|
# Account-Daten aus dem Ergebnis holen
|
||||||
account_data = result.get("account_data", {})
|
account_data = result.get("account_data", {})
|
||||||
|
|
||||||
# Account und Session über SessionController speichern (Clean Architecture)
|
save_result = result.get("save_result")
|
||||||
if hasattr(self, 'session_controller') and self.session_controller:
|
|
||||||
|
if save_result is None and hasattr(self, 'session_controller') and self.session_controller:
|
||||||
try:
|
try:
|
||||||
session_data = result.get("session_data", {})
|
|
||||||
save_result = self.session_controller.create_and_save_account(
|
save_result = self.session_controller.create_and_save_account(
|
||||||
platform=self.platform_name,
|
platform=self.platform_name,
|
||||||
account_data=account_data
|
account_data=account_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if save_result.get('success'):
|
|
||||||
logger.info(f"Account und Session erfolgreich gespeichert")
|
|
||||||
|
|
||||||
# Erfolgsmeldung anzeigen (nur einmal!)
|
|
||||||
account_info = save_result.get('account_data', {})
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
QMessageBox.information(
|
|
||||||
generator_tab,
|
|
||||||
"Erfolg",
|
|
||||||
f"Account erfolgreich erstellt!\n\n"
|
|
||||||
f"Benutzername: {account_info.get('username', '')}\n"
|
|
||||||
f"Passwort: {account_info.get('password', '')}\n"
|
|
||||||
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Signal senden, um zur Hauptseite zurückzukehren
|
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
|
||||||
self.return_to_main_requested()
|
|
||||||
else:
|
|
||||||
error_msg = save_result.get('message', 'Unbekannter Fehler')
|
|
||||||
logger.error(f"Fehler beim Speichern: {error_msg}")
|
|
||||||
from views.widgets.modern_message_box import show_error
|
|
||||||
show_error(
|
|
||||||
generator_tab,
|
|
||||||
"Fehler beim Speichern",
|
|
||||||
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
||||||
from views.widgets.modern_message_box import show_critical
|
from views.widgets.modern_message_box import show_critical
|
||||||
@ -338,12 +310,41 @@ class TikTokController(BasePlatformController):
|
|||||||
"Unerwarteter Fehler",
|
"Unerwarteter Fehler",
|
||||||
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
||||||
)
|
)
|
||||||
else:
|
return
|
||||||
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
|
||||||
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
if save_result is not None:
|
||||||
generator_tab.account_created.emit(self.platform_name, account_data)
|
if save_result.get('success'):
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
logger.info("Account und Session erfolgreich gespeichert")
|
||||||
self.return_to_main_requested()
|
|
||||||
|
account_info = save_result.get('account_data', account_data)
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
QMessageBox.information(
|
||||||
|
generator_tab,
|
||||||
|
"Erfolg",
|
||||||
|
f"Account erfolgreich erstellt!\n\n"
|
||||||
|
f"Benutzername: {account_info.get('username', '')}\n"
|
||||||
|
f"Passwort: {account_info.get('password', '')}\n"
|
||||||
|
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
else:
|
||||||
|
error_msg = save_result.get('message') or save_result.get('error') or 'Unbekannter Fehler'
|
||||||
|
logger.error(f"Fehler beim Speichern: {error_msg}")
|
||||||
|
from views.widgets.modern_message_box import show_error
|
||||||
|
show_error(
|
||||||
|
generator_tab,
|
||||||
|
"Fehler beim Speichern",
|
||||||
|
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
||||||
|
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
||||||
|
generator_tab.account_created.emit(self.platform_name, account_data)
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
|
||||||
# save_account_to_db wurde entfernt - Accounts werden jetzt über SessionController gespeichert
|
# save_account_to_db wurde entfernt - Accounts werden jetzt über SessionController gespeichert
|
||||||
|
|
||||||
|
|||||||
@ -292,42 +292,14 @@ class XController(BasePlatformController):
|
|||||||
# Account-Daten aus dem Ergebnis holen
|
# Account-Daten aus dem Ergebnis holen
|
||||||
account_data = result.get("account_data", {})
|
account_data = result.get("account_data", {})
|
||||||
|
|
||||||
# Account und Session über SessionController speichern (Clean Architecture)
|
save_result = result.get("save_result")
|
||||||
if hasattr(self, 'session_controller') and self.session_controller:
|
|
||||||
|
if save_result is None and hasattr(self, 'session_controller') and self.session_controller:
|
||||||
try:
|
try:
|
||||||
session_data = result.get("session_data", {})
|
|
||||||
save_result = self.session_controller.create_and_save_account(
|
save_result = self.session_controller.create_and_save_account(
|
||||||
platform=self.platform_name,
|
platform=self.platform_name,
|
||||||
account_data=account_data
|
account_data=account_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if save_result.get('success'):
|
|
||||||
logger.info(f"Account und Session erfolgreich gespeichert")
|
|
||||||
|
|
||||||
# Erfolgsmeldung anzeigen (nur einmal!)
|
|
||||||
account_info = save_result.get('account_data', {})
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
QMessageBox.information(
|
|
||||||
generator_tab,
|
|
||||||
"Erfolg",
|
|
||||||
f"Account erfolgreich erstellt!\n\n"
|
|
||||||
f"Benutzername: {account_info.get('username', '')}\n"
|
|
||||||
f"Passwort: {account_info.get('password', '')}\n"
|
|
||||||
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Signal senden, um zur Hauptseite zurückzukehren
|
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
|
||||||
self.return_to_main_requested()
|
|
||||||
else:
|
|
||||||
error_msg = save_result.get('message', 'Unbekannter Fehler')
|
|
||||||
logger.error(f"Fehler beim Speichern: {error_msg}")
|
|
||||||
from views.widgets.modern_message_box import show_error
|
|
||||||
show_error(
|
|
||||||
generator_tab,
|
|
||||||
"Fehler beim Speichern",
|
|
||||||
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
logger.error(f"Fehler beim Speichern des Accounts: {e}")
|
||||||
from views.widgets.modern_message_box import show_critical
|
from views.widgets.modern_message_box import show_critical
|
||||||
@ -336,12 +308,41 @@ class XController(BasePlatformController):
|
|||||||
"Unerwarteter Fehler",
|
"Unerwarteter Fehler",
|
||||||
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
f"Ein unerwarteter Fehler ist beim Speichern des Accounts aufgetreten:\n\n{str(e)}"
|
||||||
)
|
)
|
||||||
else:
|
return
|
||||||
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
|
||||||
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
if save_result is not None:
|
||||||
generator_tab.account_created.emit(self.platform_name, account_data)
|
if save_result.get('success'):
|
||||||
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
logger.info("Account und Session erfolgreich gespeichert")
|
||||||
self.return_to_main_requested()
|
|
||||||
|
account_info = save_result.get('account_data', account_data)
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
QMessageBox.information(
|
||||||
|
generator_tab,
|
||||||
|
"Erfolg",
|
||||||
|
f"Account erfolgreich erstellt!\n\n"
|
||||||
|
f"Benutzername: {account_info.get('username', '')}\n"
|
||||||
|
f"Passwort: {account_info.get('password', '')}\n"
|
||||||
|
f"E-Mail/Telefon: {account_info.get('email') or account_info.get('phone', '')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
else:
|
||||||
|
error_msg = save_result.get('message') or save_result.get('error') or 'Unbekannter Fehler'
|
||||||
|
logger.error(f"Fehler beim Speichern: {error_msg}")
|
||||||
|
from views.widgets.modern_message_box import show_error
|
||||||
|
show_error(
|
||||||
|
generator_tab,
|
||||||
|
"Fehler beim Speichern",
|
||||||
|
f"Beim Speichern des Accounts ist ein Fehler aufgetreten:\n\n{error_msg}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Fallback: Alte Methode falls SessionController nicht verfügbar
|
||||||
|
logger.warning("SessionController nicht verfügbar, verwende alte Methode")
|
||||||
|
generator_tab.account_created.emit(self.platform_name, account_data)
|
||||||
|
if hasattr(self, 'return_to_main_requested') and callable(self.return_to_main_requested):
|
||||||
|
self.return_to_main_requested()
|
||||||
|
|
||||||
# save_account_to_db wurde entfernt - Accounts werden jetzt über SessionController gespeichert
|
# save_account_to_db wurde entfernt - Accounts werden jetzt über SessionController gespeichert
|
||||||
|
|
||||||
|
|||||||
@ -146,16 +146,26 @@ class SessionController(QObject):
|
|||||||
}
|
}
|
||||||
|
|
||||||
account_id = self.db_manager.add_account(account_record)
|
account_id = self.db_manager.add_account(account_record)
|
||||||
|
|
||||||
# Prüfe ob DB-Operation erfolgreich war
|
# Prüfe DB-Operation mit spezifischen Error-Codes
|
||||||
if account_id == -1 or account_id is None:
|
if account_id is None or account_id <= 0:
|
||||||
error_msg = f"Fehler beim Speichern des Accounts {account_record['username']} in der Datenbank"
|
# Bestimme spezifischen Fehler
|
||||||
logger.error(error_msg)
|
if account_id == -1:
|
||||||
|
error_msg = f"Account-Daten unvollständig: Username oder Passwort fehlt"
|
||||||
|
elif account_id == -2:
|
||||||
|
error_msg = f"Account '{account_record['username']}' existiert bereits auf dieser Plattform"
|
||||||
|
elif account_id == -3:
|
||||||
|
error_msg = f"Datenbankfehler: Verbindung oder Schema-Problem"
|
||||||
|
else:
|
||||||
|
error_msg = f"Unbekannter Fehler beim Speichern des Accounts"
|
||||||
|
|
||||||
|
logger.error(f"DB-Speicherung fehlgeschlagen (Code: {account_id}): {error_msg}")
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'account_id': None,
|
'account_id': None,
|
||||||
'error': error_msg,
|
'error': error_msg,
|
||||||
'message': error_msg
|
'message': error_msg,
|
||||||
|
'error_code': account_id
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"Account in Datenbank gespeichert: {account_record['username']} (ID: {account_id})")
|
logger.info(f"Account in Datenbank gespeichert: {account_record['username']} (ID: {account_id})")
|
||||||
@ -252,6 +262,15 @@ class SessionController(QObject):
|
|||||||
# Callbacks setzen
|
# Callbacks setzen
|
||||||
self.automation.status_update_callback = lambda msg: self.status_update.emit(msg)
|
self.automation.status_update_callback = lambda msg: self.status_update.emit(msg)
|
||||||
self.automation.log_update_callback = lambda msg: self.log_update.emit(msg)
|
self.automation.log_update_callback = lambda msg: self.log_update.emit(msg)
|
||||||
|
elif platform == 'facebook':
|
||||||
|
from social_networks.facebook.facebook_automation import FacebookAutomation
|
||||||
|
self.automation = FacebookAutomation(
|
||||||
|
headless=False,
|
||||||
|
fingerprint=fingerprint_dict,
|
||||||
|
window_position=self.account_data.get('window_position')
|
||||||
|
)
|
||||||
|
self.automation.status_update_callback = lambda msg: self.status_update.emit(msg)
|
||||||
|
self.automation.log_update_callback = lambda msg: self.log_update.emit(msg)
|
||||||
else:
|
else:
|
||||||
self.login_failed.emit(self.account_id, f"Plattform {platform} nicht unterstützt")
|
self.login_failed.emit(self.account_id, f"Plattform {platform} nicht unterstützt")
|
||||||
return
|
return
|
||||||
@ -263,10 +282,17 @@ class SessionController(QObject):
|
|||||||
self.log_update.emit(f"Öffne {platform.title()}-Webseite...")
|
self.log_update.emit(f"Öffne {platform.title()}-Webseite...")
|
||||||
|
|
||||||
# Login durchführen
|
# Login durchführen
|
||||||
|
login_identifier = (
|
||||||
|
self.account_data.get('email')
|
||||||
|
or self.account_data.get('username')
|
||||||
|
or self.account_data.get('phone')
|
||||||
|
)
|
||||||
|
|
||||||
result = self.automation.login_account(
|
result = self.automation.login_account(
|
||||||
username_or_email=self.account_data.get('username'),
|
login_identifier,
|
||||||
password=self.account_data.get('password'),
|
self.account_data.get('password'),
|
||||||
account_id=self.account_id
|
account_id=self.account_id,
|
||||||
|
raw_account_data=self.account_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if result['success']:
|
if result['success']:
|
||||||
@ -334,4 +360,4 @@ class SessionController(QObject):
|
|||||||
f"Ein-Klick-Login für {platform} ist nicht möglich.\n\n"
|
f"Ein-Klick-Login für {platform} ist nicht möglich.\n\n"
|
||||||
f"Grund: {reason}\n\n"
|
f"Grund: {reason}\n\n"
|
||||||
"Bitte melden Sie sich manuell an, um eine neue Session zu erstellen."
|
"Bitte melden Sie sich manuell an, um eine neue Session zu erstellen."
|
||||||
)
|
)
|
||||||
|
|||||||
Binäre Datei nicht angezeigt.
@ -103,12 +103,15 @@ class DatabaseManager:
|
|||||||
def add_account(self, account_data: Dict[str, Any]) -> int:
|
def add_account(self, account_data: Dict[str, Any]) -> int:
|
||||||
"""
|
"""
|
||||||
Fügt einen Account zur Datenbank hinzu.
|
Fügt einen Account zur Datenbank hinzu.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
account_data: Dictionary mit Account-Daten
|
account_data: Dictionary mit Account-Daten
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ID des hinzugefügten Accounts oder -1 im Fehlerfall
|
ID des hinzugefügten Accounts
|
||||||
|
-1: Pflichtfeld fehlt oder ist leer
|
||||||
|
-2: Duplikat (Account existiert bereits)
|
||||||
|
-3: Datenbankverbindungsfehler
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Prüfe, ob erforderliche Felder vorhanden sind
|
# Prüfe, ob erforderliche Felder vorhanden sind
|
||||||
@ -122,35 +125,50 @@ class DatabaseManager:
|
|||||||
logger.error(f"Pflichtfeld ist leer: {field} = '{account_data[field]}'")
|
logger.error(f"Pflichtfeld ist leer: {field} = '{account_data[field]}'")
|
||||||
logger.error(f"Account-Daten: {account_data}")
|
logger.error(f"Account-Daten: {account_data}")
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
# Sicherstellen, dass created_at vorhanden ist
|
# Sicherstellen, dass created_at vorhanden ist
|
||||||
if "created_at" not in account_data:
|
if "created_at" not in account_data:
|
||||||
account_data["created_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
account_data["created_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# SQL-Anweisung vorbereiten
|
# SQL-Anweisung vorbereiten
|
||||||
fields = ", ".join(account_data.keys())
|
fields = ", ".join(account_data.keys())
|
||||||
placeholders = ", ".join(["?" for _ in account_data])
|
placeholders = ", ".join(["?" for _ in account_data])
|
||||||
|
|
||||||
query = f"INSERT INTO accounts ({fields}) VALUES ({placeholders})"
|
query = f"INSERT INTO accounts ({fields}) VALUES ({placeholders})"
|
||||||
|
|
||||||
# Anweisung ausführen
|
# Anweisung ausführen
|
||||||
cursor.execute(query, list(account_data.values()))
|
cursor.execute(query, list(account_data.values()))
|
||||||
|
|
||||||
# ID des hinzugefügten Datensatzes abrufen
|
# ID des hinzugefügten Datensatzes abrufen
|
||||||
account_id = cursor.lastrowid
|
account_id = cursor.lastrowid
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
logger.info(f"Account hinzugefügt: {account_data['username']} (ID: {account_id})")
|
logger.info(f"Account hinzugefügt: {account_data['username']} (ID: {account_id})")
|
||||||
|
|
||||||
return account_id
|
return account_id
|
||||||
|
except sqlite3.IntegrityError as e:
|
||||||
|
# UNIQUE constraint failed - Duplikat
|
||||||
|
error_str = str(e).lower()
|
||||||
|
if "unique" in error_str:
|
||||||
|
logger.error(f"Account existiert bereits (Duplikat): {e}")
|
||||||
|
logger.error(f"Account-Daten: username={account_data.get('username')}, platform={account_data.get('platform')}")
|
||||||
|
return -2
|
||||||
|
else:
|
||||||
|
logger.error(f"Integritätsfehler bei Account-Erstellung: {e}")
|
||||||
|
return -3
|
||||||
|
except sqlite3.OperationalError as e:
|
||||||
|
# Datenbankverbindungsfehler
|
||||||
|
logger.error(f"Datenbankverbindungsfehler: {e}")
|
||||||
|
return -3
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
logger.error(f"Fehler beim Hinzufügen des Accounts: {e}")
|
# Generischer DB-Fehler
|
||||||
return -1
|
logger.error(f"Datenbankfehler beim Hinzufügen des Accounts: {e}")
|
||||||
|
return -3
|
||||||
|
|
||||||
def get_account(self, account_id: int) -> Optional[Dict[str, Any]]:
|
def get_account(self, account_id: int) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -520,16 +520,21 @@ class FacebookAutomation(BaseAutomation):
|
|||||||
bool: True bei Erfolg, False bei Fehler
|
bool: True bei Erfolg, False bei Fehler
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Lade gespeicherten Fingerprint für Account
|
fingerprint = self.fingerprint_service.get_account_fingerprint(account_id)
|
||||||
saved_fingerprint = self.fingerprint_service.get_fingerprint_for_account(account_id, "facebook")
|
|
||||||
|
if fingerprint:
|
||||||
if saved_fingerprint:
|
|
||||||
logger.info(f"Verwende gespeicherten Fingerprint für Account {account_id}")
|
logger.info(f"Verwende gespeicherten Fingerprint für Account {account_id}")
|
||||||
self.provided_fingerprint = saved_fingerprint
|
|
||||||
else:
|
else:
|
||||||
logger.info(f"Kein gespeicherter Fingerprint für Account {account_id}, generiere neuen")
|
logger.info(f"Kein gespeicherter Fingerprint für Account {account_id}, generiere neuen")
|
||||||
self.provided_fingerprint = self.fingerprint_service.generate_fingerprint("facebook")
|
fingerprint = self.fingerprint_service.create_account_fingerprint(
|
||||||
|
account_id=account_id,
|
||||||
|
profile_type="desktop",
|
||||||
|
platform="facebook"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.provided_fingerprint = fingerprint.to_dict() if hasattr(fingerprint, 'to_dict') else fingerprint
|
||||||
|
self.account_fingerprint = fingerprint
|
||||||
|
|
||||||
# Browser mit Fingerprint initialisieren
|
# Browser mit Fingerprint initialisieren
|
||||||
return self._initialize_browser()
|
return self._initialize_browser()
|
||||||
|
|
||||||
@ -569,4 +574,4 @@ class FacebookAutomation(BaseAutomation):
|
|||||||
base_email += str(random.randint(1, 999))
|
base_email += str(random.randint(1, 999))
|
||||||
|
|
||||||
# Füge Domain hinzu
|
# Füge Domain hinzu
|
||||||
return f"{base_email}@{self.email_domain}"
|
return f"{base_email}@{self.email_domain}"
|
||||||
|
|||||||
@ -6,8 +6,11 @@ Placeholder für zukünftige Implementierung.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
|
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
|
||||||
|
|
||||||
from .facebook_selectors import FacebookSelectors
|
from .facebook_selectors import FacebookSelectors
|
||||||
from .facebook_workflow import FacebookWorkflow
|
from .facebook_workflow import FacebookWorkflow
|
||||||
@ -47,12 +50,205 @@ class FacebookLogin:
|
|||||||
Dict[str, Any]: Ergebnis des Logins
|
Dict[str, Any]: Ergebnis des Logins
|
||||||
"""
|
"""
|
||||||
logger.info(f"Starte Facebook-Login für {email_or_phone}")
|
logger.info(f"Starte Facebook-Login für {email_or_phone}")
|
||||||
|
|
||||||
# TODO: Implementierung sobald Login-Details verfügbar
|
automation = self.automation
|
||||||
logger.warning("Facebook-Login noch nicht vollständig implementiert")
|
browser_manager = automation.browser
|
||||||
|
|
||||||
|
if browser_manager is None or not getattr(browser_manager, "page", None):
|
||||||
|
if not automation._initialize_browser():
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Browser konnte nicht initialisiert werden",
|
||||||
|
"stage": "browser_init"
|
||||||
|
}
|
||||||
|
browser_manager = automation.browser
|
||||||
|
|
||||||
|
page = browser_manager.page
|
||||||
|
|
||||||
|
raw_account_data = kwargs.get("raw_account_data") or {}
|
||||||
|
target_email = raw_account_data.get("email")
|
||||||
|
if not target_email and email_or_phone and "@" in email_or_phone:
|
||||||
|
target_email = email_or_phone
|
||||||
|
|
||||||
|
login_url = "https://www.facebook.com/?locale=de_DE"
|
||||||
|
|
||||||
|
automation._send_status_update("Öffne Facebook")
|
||||||
|
automation._send_log_update("Navigiere zur Facebook-Startseite...")
|
||||||
|
|
||||||
|
if not browser_manager.navigate_to(login_url):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Konnte Facebook nicht öffnen",
|
||||||
|
"stage": "navigation_failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
self._reject_optional_cookies(browser_manager)
|
||||||
|
|
||||||
|
automation._send_status_update("Fülle Login-Formular aus")
|
||||||
|
automation._send_log_update("Gebe Zugangsdaten ein...")
|
||||||
|
|
||||||
|
if not browser_manager.fill_form_field("#email", email_or_phone):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "E-Mail/Telefon-Feld konnte nicht ausgefüllt werden",
|
||||||
|
"stage": "fill_email"
|
||||||
|
}
|
||||||
|
|
||||||
|
if not browser_manager.fill_form_field("#pass", password):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Passwortfeld konnte nicht ausgefüllt werden",
|
||||||
|
"stage": "fill_password"
|
||||||
|
}
|
||||||
|
|
||||||
|
automation._send_status_update("Sende Login-Daten")
|
||||||
|
if not browser_manager.click_element("button[data-testid='royal-login-button']"):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Login-Button konnte nicht geklickt werden",
|
||||||
|
"stage": "click_login"
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
page.wait_for_load_state("networkidle", timeout=15000)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.debug("Warten auf Netzwerk-Leerlauf nach Login abgelaufen")
|
||||||
|
|
||||||
|
# Prüfe auf Zwei-Faktor-Authentifizierung
|
||||||
|
if "auth_platform/codesubmit" in page.url:
|
||||||
|
automation._send_status_update("Zwei-Faktor-Verifizierung erforderlich")
|
||||||
|
automation._send_log_update("Warte auf E-Mail mit Sicherheitscode...")
|
||||||
|
|
||||||
|
if not target_email:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Zwei-Faktor-Code erforderlich, aber keine E-Mail für den Account vorhanden",
|
||||||
|
"stage": "two_factor_missing_email"
|
||||||
|
}
|
||||||
|
|
||||||
|
if not self._handle_two_factor(page, browser_manager, target_email):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Zwei-Faktor-Verifizierung fehlgeschlagen",
|
||||||
|
"stage": "two_factor_failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
page.wait_for_load_state("networkidle", timeout=15000)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.debug("Warten nach 2FA auf Netzwerk-Leerlauf abgelaufen")
|
||||||
|
|
||||||
|
# Prüfe auf Login-Erfolg oder Fehler
|
||||||
|
if self._detect_login_error(browser_manager):
|
||||||
|
error_message = self._extract_error_message(browser_manager)
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": error_message or "Login fehlgeschlagen",
|
||||||
|
"stage": "login_failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
if not self._await_login_success(page):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Login konnte nicht bestätigt werden",
|
||||||
|
"stage": "login_unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
self._dismiss_post_login_dialog(page)
|
||||||
|
|
||||||
|
automation._send_status_update("Login erfolgreich")
|
||||||
|
automation._send_log_update("Facebook-Login abgeschlossen")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": True,
|
||||||
"error": "Login-Funktion noch nicht implementiert",
|
"stage": "completed",
|
||||||
"stage": "not_implemented"
|
"username": email_or_phone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Hilfsmethoden
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _reject_optional_cookies(self, browser_manager) -> None:
|
||||||
|
"""Klickt den Button "Optionale Cookies ablehnen", falls vorhanden."""
|
||||||
|
page = browser_manager.page
|
||||||
|
try:
|
||||||
|
button = page.locator("text=Optionale Cookies ablehnen").first
|
||||||
|
button.wait_for(state="visible", timeout=5000)
|
||||||
|
button.click()
|
||||||
|
logger.info("Optionale Cookies abgelehnt")
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.debug("Cookie-Banner nicht gefunden oder bereits geschlossen")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Konnte Cookie-Banner nicht schließen: {e}")
|
||||||
|
|
||||||
|
def _handle_two_factor(self, page, browser_manager, target_email: str) -> bool:
|
||||||
|
"""Handhabt die Eingabe des Zwei-Faktor-Codes."""
|
||||||
|
self.automation._send_log_update("Versuche Sicherheitscode aus E-Mail zu lesen...")
|
||||||
|
|
||||||
|
code = self.automation.email_handler.get_verification_code(
|
||||||
|
target_email=target_email,
|
||||||
|
platform="facebook",
|
||||||
|
max_attempts=60,
|
||||||
|
delay_seconds=5
|
||||||
|
)
|
||||||
|
|
||||||
|
if not code:
|
||||||
|
logger.error("Kein Zwei-Faktor-Code gefunden")
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info("Trage Zwei-Faktor-Code ein")
|
||||||
|
self.automation._send_log_update("Zwei-Faktor-Code gefunden – trage ihn ein...")
|
||||||
|
if not browser_manager.fill_form_field("input[name='email']", code):
|
||||||
|
logger.error("Zwei-Faktor-Eingabefeld konnte nicht gefüllt werden")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
page.locator("text=Weiter").first.click()
|
||||||
|
self.automation._send_log_update("Weiter mit Zwei-Faktor-Verifizierung...")
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.error("Weiter-Button nach Zwei-Faktor-Eingabe nicht gefunden")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fehler beim Klicken auf den Weiter-Button: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _detect_login_error(self, browser_manager) -> bool:
|
||||||
|
"""Überprüft, ob ein Fehler nach dem Login angezeigt wird."""
|
||||||
|
error_selector = "div[data-testid='error_box'], div._9ay7"
|
||||||
|
element = browser_manager.wait_for_selector(error_selector, timeout=2000)
|
||||||
|
return bool(element)
|
||||||
|
|
||||||
|
def _extract_error_message(self, browser_manager) -> Optional[str]:
|
||||||
|
element = browser_manager.wait_for_selector("div[data-testid='error_box'], div._9ay7", timeout=2000)
|
||||||
|
if not element:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
text = element.inner_text().strip()
|
||||||
|
logger.error(f"Facebook-Login-Fehler: {text}")
|
||||||
|
return text
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _await_login_success(self, page) -> bool:
|
||||||
|
"""Wartet auf eine Seite, die einen erfolgreichen Login vermuten lässt."""
|
||||||
|
target_pattern = re.compile(r"https://www\.facebook\.com/(?!login|checkpoint).*")
|
||||||
|
try:
|
||||||
|
page.wait_for_url(target_pattern, timeout=15000)
|
||||||
|
return True
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.debug(f"Aktuelle URL nach Login: {page.url}")
|
||||||
|
return bool(target_pattern.match(page.url))
|
||||||
|
|
||||||
|
def _dismiss_post_login_dialog(self, page) -> None:
|
||||||
|
"""Schließt nach dem Login auftauchende Dialoge."""
|
||||||
|
try:
|
||||||
|
close_button = page.locator("button:has-text('Schließen')").first
|
||||||
|
close_button.click(timeout=3000)
|
||||||
|
logger.info("Post-Login-Dialog geschlossen")
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.debug("Kein Post-Login-Dialog zum Schließen gefunden")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|||||||
@ -124,22 +124,69 @@ class FacebookRegistration:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# 7. Erfolgreiche Registrierung überprüfen
|
# 7. Erfolgreiche Registrierung überprüfen
|
||||||
if not self._check_registration_success():
|
success_check = self._check_registration_success()
|
||||||
return {
|
|
||||||
"success": False,
|
# 8. Wenn nicht erfolgreich: Prüfe auf Cookie-Consent oder andere Zwischen-Schritte
|
||||||
"error": "Registrierung fehlgeschlagen",
|
if not success_check:
|
||||||
"stage": "final_check"
|
current_url = self.automation.browser.page.url
|
||||||
}
|
logger.info(f"Success-Check fehlgeschlagen, prüfe Zwischen-Schritte: {current_url}")
|
||||||
|
|
||||||
|
# Behandle Cookie-Consent falls vorhanden
|
||||||
|
if "privacy/consent" in current_url or "user_cookie_choice" in current_url:
|
||||||
|
logger.info("Cookie-Consent Dialog erkannt (nach Verifikation)")
|
||||||
|
self.automation._send_log_update("Behandle Cookie-Einstellungen...")
|
||||||
|
|
||||||
|
if self._handle_cookie_consent():
|
||||||
|
logger.info("Cookie-Consent erfolgreich behandelt")
|
||||||
|
# Warte nach Cookie-Ablehnung
|
||||||
|
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
|
||||||
|
|
||||||
|
# Prüfe auf finalen Dialog/Layer mit "Schließen"-Button
|
||||||
|
if self._handle_final_dialogs():
|
||||||
|
logger.info("Finale Dialogs behandelt")
|
||||||
|
|
||||||
|
# Erneuter Success-Check
|
||||||
|
success_check = self._check_registration_success()
|
||||||
|
|
||||||
|
if not success_check:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "Registrierung fehlgeschlagen (nach Zwischen-Schritten)",
|
||||||
|
"stage": "final_check"
|
||||||
|
}
|
||||||
|
|
||||||
# Registrierung erfolgreich
|
# Registrierung erfolgreich
|
||||||
logger.info(f"Facebook-Account erfolgreich erstellt")
|
logger.info(f"Facebook-Account erfolgreich erstellt")
|
||||||
self.automation._send_status_update("Registrierung erfolgreich!")
|
self.automation._send_status_update("Registrierung erfolgreich!")
|
||||||
self.automation._send_log_update("Account wurde erfolgreich erstellt")
|
self.automation._send_log_update("Account wurde erfolgreich erstellt")
|
||||||
|
|
||||||
# Account-Daten für Rückgabe vorbereiten
|
# Account-Daten für Rückgabe vorbereiten
|
||||||
account_data["platform"] = "facebook"
|
account_data["platform"] = "facebook"
|
||||||
account_data["created_at"] = time.time()
|
account_data["created_at"] = time.time()
|
||||||
|
|
||||||
|
# Username generieren falls nicht vorhanden (Facebook gibt keinen zurück)
|
||||||
|
if not account_data.get("username"):
|
||||||
|
username = self._generate_username_from_email(
|
||||||
|
account_data.get("email", ""),
|
||||||
|
account_data.get("first_name", ""),
|
||||||
|
account_data.get("last_name", "")
|
||||||
|
)
|
||||||
|
# Username ist GARANTIERT vorhanden (Fallback-Strategien)
|
||||||
|
account_data["username"] = username
|
||||||
|
logger.info(f"Username generiert: {username}")
|
||||||
|
|
||||||
|
# KRITISCHE VALIDIERUNG: Stelle sicher dass Username vorhanden ist
|
||||||
|
if not account_data.get("username") or account_data["username"] == "":
|
||||||
|
error_msg = "KRITISCHER FEHLER: Username konnte nicht generiert werden"
|
||||||
|
logger.error(error_msg)
|
||||||
|
logger.error(f"Account-Daten: {account_data}")
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": error_msg,
|
||||||
|
"stage": "username_validation_failed",
|
||||||
|
"account_data": account_data
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"stage": "completed",
|
"stage": "completed",
|
||||||
@ -672,11 +719,15 @@ class FacebookRegistration:
|
|||||||
logger.info("E-Mail-Verifikation erforderlich (Input-Field gefunden)")
|
logger.info("E-Mail-Verifikation erforderlich (Input-Field gefunden)")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Prüfe auf Erfolgs-Indikatoren (dann keine Verifikation nötig)
|
# Prüfe auf Erfolgs-Indikatoren NUR wenn URL eindeutig KEINE Verifikations-URL ist
|
||||||
for indicator in self.selectors.SUCCESS_INDICATORS:
|
# WICHTIG: Verifikationsseiten haben auch div[role='navigation'], deshalb URL-Check zuerst!
|
||||||
if self.automation.browser.is_element_visible(indicator, timeout=500):
|
if "privacy/consent" not in current_url and "user_cookie_choice" not in current_url:
|
||||||
logger.info(f"Keine Verifikation nötig (Erfolgs-Indikator gefunden: {indicator})")
|
for indicator in self.selectors.SUCCESS_INDICATORS:
|
||||||
return False
|
if self.automation.browser.is_element_visible(indicator, timeout=500):
|
||||||
|
# Finale Prüfung: Ist es wirklich eine Erfolgsseite?
|
||||||
|
if "facebook.com/?" in current_url or "facebook.com/home" in current_url or "feed" in current_url:
|
||||||
|
logger.info(f"Keine Verifikation nötig (Erfolgs-Indikator gefunden: {indicator})")
|
||||||
|
return False
|
||||||
|
|
||||||
# Kurze Pause vor nächstem Versuch
|
# Kurze Pause vor nächstem Versuch
|
||||||
time.sleep(check_interval)
|
time.sleep(check_interval)
|
||||||
@ -797,48 +848,182 @@ class FacebookRegistration:
|
|||||||
|
|
||||||
# Warte auf Navigation/Verarbeitung
|
# Warte auf Navigation/Verarbeitung
|
||||||
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
|
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
|
||||||
|
|
||||||
# Prüfe auf OK-Button (Popup nach erfolgreicher Verifikation)
|
# Prüfe auf OK-Button (Popup nach erfolgreicher Verifikation)
|
||||||
|
# Warte länger, da das Popup verzögert erscheinen kann
|
||||||
|
self.automation.human_behavior.random_delay(1.0, 2.0)
|
||||||
|
|
||||||
ok_selectors = [
|
ok_selectors = [
|
||||||
self.selectors.VERIFICATION_OK_BUTTON,
|
self.selectors.VERIFICATION_OK_BUTTON, # a.layerCancel:has-text('OK')
|
||||||
self.selectors.VERIFICATION_OK_BUTTON_ALT,
|
self.selectors.VERIFICATION_OK_BUTTON_ALT, # a[role='button']:has-text('OK')
|
||||||
"a:has-text('OK')",
|
"a.layerCancel", # Nur Klasse (falls Text-Match fehlschlägt)
|
||||||
"button:has-text('OK')"
|
"a[role='button']._42ft._42fu.layerCancel", # Spezifische Klassen
|
||||||
|
"a:has-text('OK')", # Allgemeiner Link
|
||||||
|
"button:has-text('OK')" # Button-Fallback
|
||||||
]
|
]
|
||||||
|
|
||||||
|
ok_button_clicked = False
|
||||||
for selector in ok_selectors:
|
for selector in ok_selectors:
|
||||||
try:
|
try:
|
||||||
if self.automation.browser.is_element_visible(selector, timeout=2000):
|
if self.automation.browser.is_element_visible(selector, timeout=5000):
|
||||||
self.automation.browser.click_element(selector)
|
logger.info(f"OK-Button gefunden mit: {selector}")
|
||||||
logger.info(f"OK-Button nach Verifikation geklickt: {selector}")
|
if self.automation.browser.click_element(selector, timeout=2000):
|
||||||
break
|
logger.info(f"OK-Button nach Verifikation erfolgreich geklickt: {selector}")
|
||||||
except:
|
ok_button_clicked = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logger.warning(f"OK-Button Click fehlgeschlagen für: {selector}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Fehler beim OK-Button Click mit {selector}: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if ok_button_clicked:
|
||||||
|
# Warte nach OK-Click auf finale Navigation
|
||||||
|
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
|
||||||
|
else:
|
||||||
|
logger.warning("OK-Button nach Verifikation nicht gefunden oder Click fehlgeschlagen")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Eingeben des Verifikationscodes: {e}")
|
logger.error(f"Fehler beim Eingeben des Verifikationscodes: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _handle_final_dialogs(self) -> bool:
|
||||||
|
"""
|
||||||
|
Behandelt finale Dialogs/Layer nach Cookie-Consent.
|
||||||
|
Z.B. "Schließen"-Button.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True wenn Dialog behandelt wurde
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.automation.human_behavior.random_delay(0.5, 1.0)
|
||||||
|
|
||||||
|
close_button_selectors = [
|
||||||
|
"button:has-text('Schließen')",
|
||||||
|
"button:has-text('Close')",
|
||||||
|
self.selectors.DIALOG_CLOSE_BUTTON, # div[aria-label='Schließen']
|
||||||
|
self.selectors.DIALOG_CLOSE_BUTTON_EN, # div[aria-label='Close']
|
||||||
|
"div[role='button']:has-text('Schließen')",
|
||||||
|
"div[role='button']:has-text('Close')",
|
||||||
|
"a[role='button']:has-text('Schließen')",
|
||||||
|
"a[role='button']:has-text('Close')"
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in close_button_selectors:
|
||||||
|
try:
|
||||||
|
if self.automation.browser.is_element_visible(selector, timeout=2000):
|
||||||
|
if self.automation.browser.click_element(selector, timeout=1000):
|
||||||
|
logger.info(f"Finaler Dialog geschlossen mit: {selector}")
|
||||||
|
self.automation._send_log_update("Schließe Dialog...")
|
||||||
|
# Kurze Pause nach Schließen
|
||||||
|
self.automation.human_behavior.random_delay(0.5, 1.0)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Fehler beim Schließen-Button mit {selector}: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.debug("Kein finaler Dialog gefunden")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fehler beim Behandeln finaler Dialogs: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _generate_username_from_email(self, email: str, first_name: str = "", last_name: str = "") -> str:
|
||||||
|
"""
|
||||||
|
Generiert einen Username aus der E-Mail-Adresse.
|
||||||
|
Facebook gibt keinen Username während der Registrierung zurück.
|
||||||
|
Mit Fallback-Strategien falls E-Mail ungültig ist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
email: E-Mail-Adresse
|
||||||
|
first_name: Vorname als Fallback
|
||||||
|
last_name: Nachname als Fallback
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Generierter Username (GARANTIERT nicht leer!)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Strategie 1: Aus E-Mail generieren
|
||||||
|
if email and "@" in email:
|
||||||
|
# Extrahiere Teil vor @
|
||||||
|
username_part = email.split("@")[0]
|
||||||
|
|
||||||
|
# Ersetze Punkte durch Underscores
|
||||||
|
username = username_part.replace(".", "_")
|
||||||
|
|
||||||
|
# Stelle sicher, dass es gültige Zeichen sind
|
||||||
|
import re
|
||||||
|
username = re.sub(r'[^a-zA-Z0-9_]', '_', username)
|
||||||
|
|
||||||
|
if username and len(username) >= 3: # Mindestens 3 Zeichen
|
||||||
|
logger.debug(f"Username aus E-Mail generiert: {email} -> {username}")
|
||||||
|
return username
|
||||||
|
|
||||||
|
# Strategie 2: Aus Vor- und Nachnamen generieren
|
||||||
|
if first_name and last_name:
|
||||||
|
import re
|
||||||
|
clean_first = re.sub(r'[^a-zA-Z0-9]', '', first_name.lower())
|
||||||
|
clean_last = re.sub(r'[^a-zA-Z0-9]', '', last_name.lower())
|
||||||
|
|
||||||
|
if clean_first and clean_last:
|
||||||
|
import random
|
||||||
|
username = f"{clean_first}_{clean_last}_{random.randint(100, 999)}"
|
||||||
|
logger.info(f"Username aus Namen generiert (Fallback): {username}")
|
||||||
|
return username
|
||||||
|
|
||||||
|
# Strategie 3: Timestamp-basierter Name (letzter Fallback)
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
timestamp = int(time.time() * 1000) % 1000000 # Letzte 6 Stellen
|
||||||
|
random_suffix = random.randint(100, 999)
|
||||||
|
username = f"fb_user_{timestamp}_{random_suffix}"
|
||||||
|
logger.warning(f"Username mit Timestamp generiert (Notfall-Fallback): {username}")
|
||||||
|
return username
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# ABSOLUTER NOTFALL: Garantiere IMMER einen Username
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
timestamp = int(time.time() * 1000) % 1000000
|
||||||
|
random_suffix = random.randint(100, 999)
|
||||||
|
emergency_username = f"fb_emergency_{timestamp}_{random_suffix}"
|
||||||
|
logger.error(f"Fehler beim Generieren des Usernames: {e}")
|
||||||
|
logger.error(f"Notfall-Username generiert: {emergency_username}")
|
||||||
|
return emergency_username
|
||||||
|
|
||||||
def _check_registration_success(self) -> bool:
|
def _check_registration_success(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Überprüft ob die Registrierung erfolgreich war.
|
Überprüft ob die Registrierung erfolgreich war.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True bei Erfolg
|
bool: True bei Erfolg
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Warte auf finale Navigation
|
# Warte auf finale Navigation
|
||||||
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
|
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
|
||||||
|
|
||||||
# Screenshot
|
# Screenshot
|
||||||
self.automation._take_screenshot("registration_final")
|
self.automation._take_screenshot("registration_final")
|
||||||
|
|
||||||
# Prüfe URL
|
# Prüfe URL
|
||||||
current_url = self.automation.browser.page.url
|
current_url = self.automation.browser.page.url
|
||||||
logger.info(f"Finale URL: {current_url}")
|
logger.info(f"Finale URL: {current_url}")
|
||||||
|
|
||||||
|
# WICHTIG: Prüfe ZUERST auf Zwischen-Schritte die KEINE Erfolgs-Indikatoren sind
|
||||||
|
intermediate_patterns = [
|
||||||
|
"privacy/consent",
|
||||||
|
"user_cookie_choice",
|
||||||
|
"confirmemail"
|
||||||
|
]
|
||||||
|
|
||||||
|
for pattern in intermediate_patterns:
|
||||||
|
if pattern in current_url:
|
||||||
|
logger.info(f"Zwischen-Schritt erkannt (noch nicht fertig): {pattern}")
|
||||||
|
return False # Noch nicht erfolgreich, weitere Schritte nötig
|
||||||
|
|
||||||
# Erfolgs-URLs
|
# Erfolgs-URLs
|
||||||
success_patterns = [
|
success_patterns = [
|
||||||
"facebook.com/?",
|
"facebook.com/?",
|
||||||
@ -847,12 +1032,12 @@ class FacebookRegistration:
|
|||||||
"welcome",
|
"welcome",
|
||||||
"onboarding"
|
"onboarding"
|
||||||
]
|
]
|
||||||
|
|
||||||
for pattern in success_patterns:
|
for pattern in success_patterns:
|
||||||
if pattern in current_url:
|
if pattern in current_url:
|
||||||
logger.info(f"Registrierung erfolgreich (URL-Pattern: {pattern})")
|
logger.info(f"Registrierung erfolgreich (URL-Pattern: {pattern})")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Prüfe auf Erfolgs-Indikatoren
|
# Prüfe auf Erfolgs-Indikatoren
|
||||||
for indicator in self.selectors.SUCCESS_INDICATORS:
|
for indicator in self.selectors.SUCCESS_INDICATORS:
|
||||||
if self.automation.browser.is_element_visible(indicator, timeout=2000):
|
if self.automation.browser.is_element_visible(indicator, timeout=2000):
|
||||||
|
|||||||
@ -587,7 +587,12 @@ class EmailHandler:
|
|||||||
r"Facebook-Code: (\d{5})",
|
r"Facebook-Code: (\d{5})",
|
||||||
r"Facebook code: (\d{5})",
|
r"Facebook code: (\d{5})",
|
||||||
r"Facebook: (\d{5})",
|
r"Facebook: (\d{5})",
|
||||||
r"[^\d](\d{5})[^\d]" # 5-stellige Zahl umgeben von Nicht-Ziffern
|
r"Der Sicherheitscode lautet (\d{8})",
|
||||||
|
r"Security code is (\d{8})",
|
||||||
|
r"(\d{8}) ist dein Facebook-Code",
|
||||||
|
r"(\d{8}) is your Facebook code",
|
||||||
|
r"[^\d](\d{8})[^\d]",
|
||||||
|
r"[^\d](\d{5})[^\d]" # Zahl umgeben von Nicht-Ziffern
|
||||||
],
|
],
|
||||||
"twitter": [
|
"twitter": [
|
||||||
r"Code: (\d{6})",
|
r"Code: (\d{6})",
|
||||||
@ -650,18 +655,18 @@ class EmailHandler:
|
|||||||
|
|
||||||
# Generische Suche nach Zahlen (für die jeweilige Plattform typische Länge)
|
# Generische Suche nach Zahlen (für die jeweilige Plattform typische Länge)
|
||||||
code_length = 6 # Standard
|
code_length = 6 # Standard
|
||||||
|
possible_lengths = [code_length]
|
||||||
if platform.lower() == "facebook":
|
if platform.lower() == "facebook":
|
||||||
code_length = 5
|
possible_lengths = [8, 5]
|
||||||
|
|
||||||
# Suche nach alleinstehenden Zahlen der richtigen Länge
|
for length in possible_lengths:
|
||||||
generic_pattern = r"\b(\d{" + str(code_length) + r"})\b"
|
generic_pattern = r"\b(\d{" + str(length) + r"})\b"
|
||||||
matches = re.findall(generic_pattern, text)
|
matches = re.findall(generic_pattern, text)
|
||||||
|
|
||||||
if matches:
|
if matches:
|
||||||
# Nehme die erste gefundene Zahl
|
code = matches[0]
|
||||||
code = matches[0]
|
logger.debug(f"Code gefunden mit generischem Muster (Länge {length}): {code}")
|
||||||
logger.debug(f"Code gefunden mit generischem Muster: {code}")
|
return code
|
||||||
return code
|
|
||||||
|
|
||||||
logger.debug("Kein Code gefunden")
|
logger.debug("Kein Code gefunden")
|
||||||
return None
|
return None
|
||||||
@ -686,4 +691,4 @@ class EmailHandler:
|
|||||||
platform = "instagram" # Standard
|
platform = "instagram" # Standard
|
||||||
|
|
||||||
# Bestätigungscode abrufen
|
# Bestätigungscode abrufen
|
||||||
return self.get_verification_code(expected_email, platform, max_attempts, delay_seconds)
|
return self.get_verification_code(expected_email, platform, max_attempts, delay_seconds)
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren