Initial commit
Dieser Commit ist enthalten in:
402
controllers/main_controller.py
Normale Datei
402
controllers/main_controller.py
Normale Datei
@ -0,0 +1,402 @@
|
||||
"""
|
||||
Hauptcontroller für die Social Media Account Generator Anwendung.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QMessageBox, QApplication
|
||||
|
||||
from views.main_window import MainWindow
|
||||
from views.dialogs.license_activation_dialog import LicenseActivationDialog
|
||||
from controllers.platform_controllers.instagram_controller import InstagramController
|
||||
from controllers.platform_controllers.tiktok_controller import TikTokController
|
||||
from controllers.account_controller import AccountController
|
||||
from controllers.settings_controller import SettingsController
|
||||
from controllers.session_controller import SessionController
|
||||
|
||||
from database.db_manager import DatabaseManager
|
||||
from utils.proxy_rotator import ProxyRotator
|
||||
from utils.email_handler import EmailHandler
|
||||
from utils.theme_manager import ThemeManager
|
||||
from localization.language_manager import LanguageManager
|
||||
from licensing.license_manager import LicenseManager
|
||||
from updates.update_checker import UpdateChecker
|
||||
|
||||
logger = logging.getLogger("main")
|
||||
|
||||
class MainController:
|
||||
"""Hauptcontroller, der die Anwendung koordiniert."""
|
||||
|
||||
def __init__(self, app):
|
||||
# QApplication Referenz speichern
|
||||
self.app = app
|
||||
|
||||
# Theme Manager initialisieren
|
||||
self.theme_manager = ThemeManager(app)
|
||||
|
||||
# Language Manager initialisieren
|
||||
self.language_manager = LanguageManager(app)
|
||||
|
||||
# Lizenz Manager als erstes initialisieren
|
||||
self.license_manager = LicenseManager()
|
||||
|
||||
# Lizenz prüfen bevor andere Komponenten geladen werden
|
||||
if not self._check_and_activate_license():
|
||||
logger.error("Keine gültige Lizenz - Anwendung wird beendet")
|
||||
sys.exit(1)
|
||||
|
||||
# Modelle initialisieren
|
||||
self.db_manager = DatabaseManager()
|
||||
self.proxy_rotator = ProxyRotator()
|
||||
self.email_handler = EmailHandler()
|
||||
self.update_checker = UpdateChecker(self.license_manager.api_client)
|
||||
|
||||
# Haupt-View erstellen
|
||||
self.view = MainWindow(self.theme_manager, self.language_manager, self.db_manager)
|
||||
|
||||
# Untercontroller erstellen
|
||||
self.account_controller = AccountController(self.db_manager)
|
||||
self.account_controller.set_parent_view(self.view)
|
||||
self.settings_controller = SettingsController(
|
||||
self.proxy_rotator,
|
||||
self.email_handler,
|
||||
self.license_manager
|
||||
)
|
||||
self.session_controller = SessionController(self.db_manager)
|
||||
|
||||
# Plattform-Controller initialisieren
|
||||
self.platform_controllers = {}
|
||||
|
||||
# Instagram Controller hinzufügen
|
||||
instagram_controller = InstagramController(
|
||||
self.db_manager,
|
||||
self.proxy_rotator,
|
||||
self.email_handler,
|
||||
self.language_manager
|
||||
)
|
||||
# Signal für Rückkehr zur Hauptseite verbinden
|
||||
instagram_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
|
||||
# SessionController referenz hinzufügen
|
||||
instagram_controller.session_controller = self.session_controller
|
||||
self.platform_controllers["instagram"] = instagram_controller
|
||||
|
||||
# TikTok Controller hinzufügen
|
||||
tiktok_controller = TikTokController(
|
||||
self.db_manager,
|
||||
self.proxy_rotator,
|
||||
self.email_handler,
|
||||
self.language_manager
|
||||
)
|
||||
# Signal für Rückkehr zur Hauptseite verbinden
|
||||
tiktok_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
|
||||
# SessionController referenz hinzufügen
|
||||
tiktok_controller.session_controller = self.session_controller
|
||||
self.platform_controllers["tiktok"] = tiktok_controller
|
||||
|
||||
# X (Twitter) Controller hinzufügen
|
||||
from controllers.platform_controllers.x_controller import XController
|
||||
x_controller = XController(
|
||||
self.db_manager,
|
||||
self.proxy_rotator,
|
||||
self.email_handler,
|
||||
self.language_manager
|
||||
)
|
||||
# Signal für Rückkehr zur Hauptseite verbinden
|
||||
x_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
|
||||
# SessionController referenz hinzufügen
|
||||
x_controller.session_controller = self.session_controller
|
||||
self.platform_controllers["x"] = x_controller
|
||||
|
||||
# Gmail Controller hinzufügen
|
||||
from controllers.platform_controllers.gmail_controller import GmailController
|
||||
gmail_controller = GmailController(
|
||||
self.db_manager,
|
||||
self.proxy_rotator,
|
||||
self.email_handler,
|
||||
self.language_manager
|
||||
)
|
||||
# Signal für Rückkehr zur Hauptseite verbinden
|
||||
gmail_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
|
||||
# SessionController referenz hinzufügen
|
||||
gmail_controller.session_controller = self.session_controller
|
||||
self.platform_controllers["gmail"] = gmail_controller
|
||||
|
||||
# Hier können in Zukunft weitere Controller hinzugefügt werden:
|
||||
# self.platform_controllers["facebook"] = FacebookController(...)
|
||||
|
||||
# Signals verbinden
|
||||
self.connect_signals()
|
||||
|
||||
# Platform Selector Signal-Verbindungen
|
||||
if hasattr(self.view.platform_selector, 'export_requested'):
|
||||
self.view.platform_selector.export_requested.connect(
|
||||
lambda accounts: self.account_controller.export_accounts(None, accounts)
|
||||
)
|
||||
|
||||
if hasattr(self.view.platform_selector, 'login_requested'):
|
||||
self.view.platform_selector.login_requested.connect(
|
||||
self.session_controller.perform_one_click_login
|
||||
)
|
||||
|
||||
# Session-Status-Update Signal entfernt (Session-Funktionalität deaktiviert)
|
||||
|
||||
# Login-Result Signals verbinden
|
||||
self.session_controller.login_successful.connect(self._on_login_successful)
|
||||
self.session_controller.login_failed.connect(self._on_login_failed)
|
||||
|
||||
# Session starten
|
||||
self._start_license_session()
|
||||
|
||||
# Auf Updates prüfen
|
||||
self.check_for_updates()
|
||||
|
||||
# Hauptfenster anzeigen
|
||||
self.view.show()
|
||||
|
||||
def _on_login_successful(self, account_id: str, session_data: dict):
|
||||
"""Behandelt erfolgreiches Login"""
|
||||
# GEÄNDERT: Kein Popup mehr - User sieht Erfolg direkt im Browser
|
||||
try:
|
||||
account = self.db_manager.get_account(int(account_id))
|
||||
username = account.get('username', 'Unknown') if account else 'Unknown'
|
||||
platform = account.get('platform', 'Unknown') if account else 'Unknown'
|
||||
|
||||
logger.info(f"Login erfolgreich für Account {account_id} ({username}) - Browser bleibt offen")
|
||||
# Popup entfernt - User hat direktes Feedback über Browser-Status
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error showing success message: {e}")
|
||||
|
||||
def _on_login_failed(self, account_id: str, error_message: str):
|
||||
"""Behandelt fehlgeschlagenes Login"""
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
# Account-Details für die Nachricht holen
|
||||
try:
|
||||
account = self.db_manager.get_account(int(account_id))
|
||||
username = account.get('username', 'Unknown') if account else 'Unknown'
|
||||
|
||||
msg = QMessageBox(self.view)
|
||||
msg.setIcon(QMessageBox.Warning)
|
||||
msg.setWindowTitle("Login Fehlgeschlagen")
|
||||
msg.setText(f"Ein-Klick-Login fehlgeschlagen!")
|
||||
msg.setInformativeText(f"Account: {username}\nFehler: {error_message}")
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.exec_()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error showing failure message: {e}")
|
||||
|
||||
def connect_signals(self):
|
||||
"""Verbindet alle Signale mit den entsprechenden Slots."""
|
||||
# Plattformauswahl-Signal verbinden
|
||||
self.view.platform_selected.connect(self.on_platform_selected)
|
||||
|
||||
# Zurück-Button verbinden
|
||||
self.view.back_to_selector_requested.connect(self.show_platform_selector)
|
||||
|
||||
# Theme-Toggle verbinden
|
||||
self.view.theme_toggled.connect(self.on_theme_toggled)
|
||||
|
||||
def on_platform_selected(self, platform: str):
|
||||
"""Wird aufgerufen, wenn eine Plattform ausgewählt wird."""
|
||||
logger.info(f"Plattform ausgewählt: {platform}")
|
||||
|
||||
# Aktuelle Plattform setzen
|
||||
self.current_platform = platform.lower()
|
||||
|
||||
# Prüfen, ob die Plattform unterstützt wird
|
||||
if self.current_platform not in self.platform_controllers:
|
||||
logger.error(f"Plattform '{platform}' wird nicht unterstützt")
|
||||
QMessageBox.critical(
|
||||
self.view,
|
||||
"Nicht unterstützt",
|
||||
f"Die Plattform '{platform}' ist noch nicht implementiert."
|
||||
)
|
||||
return
|
||||
|
||||
# Plattformspezifischen Controller abrufen
|
||||
platform_controller = self.platform_controllers.get(self.current_platform)
|
||||
|
||||
# Plattform-View initialisieren
|
||||
self.view.init_platform_ui(platform, platform_controller)
|
||||
|
||||
# Tab-Hooks verbinden
|
||||
self.connect_tab_hooks(platform_controller)
|
||||
|
||||
# Plattformspezifische Ansicht anzeigen
|
||||
self.view.show_platform_ui()
|
||||
|
||||
def on_theme_toggled(self):
|
||||
"""Wird aufgerufen, wenn das Theme gewechselt wird."""
|
||||
if self.theme_manager:
|
||||
theme_name = self.theme_manager.get_current_theme()
|
||||
logger.info(f"Theme gewechselt zu: {theme_name}")
|
||||
|
||||
# Hier kann zusätzliche Logik für Theme-Wechsel hinzugefügt werden
|
||||
# z.B. UI-Elemente aktualisieren, die nicht automatisch aktualisiert werden
|
||||
|
||||
def connect_tab_hooks(self, platform_controller):
|
||||
"""Verbindet die Tab-Hooks mit dem Plattform-Controller."""
|
||||
# Generator-Tab-Hooks
|
||||
# HINWEIS: account_created Signal ist nicht mehr verbunden, da Accounts
|
||||
# jetzt über SessionController mit Clean Architecture gespeichert werden
|
||||
if hasattr(platform_controller, "get_generator_tab"):
|
||||
generator_tab = platform_controller.get_generator_tab()
|
||||
# generator_tab.account_created.connect(self.account_controller.on_account_created) # Deaktiviert
|
||||
|
||||
|
||||
# Einstellungen-Tab-Hooks
|
||||
if hasattr(platform_controller, "get_settings_tab"):
|
||||
settings_tab = platform_controller.get_settings_tab()
|
||||
settings_tab.proxy_settings_saved.connect(self.settings_controller.save_proxy_settings)
|
||||
settings_tab.proxy_tested.connect(self.settings_controller.test_proxy)
|
||||
settings_tab.email_settings_saved.connect(self.settings_controller.save_email_settings)
|
||||
settings_tab.email_tested.connect(self.settings_controller.test_email)
|
||||
settings_tab.license_activated.connect(self.settings_controller.activate_license)
|
||||
|
||||
def show_platform_selector(self):
|
||||
"""Zeigt den Plattform-Selektor an."""
|
||||
logger.info("Zurück zur Plattformauswahl")
|
||||
self.view.show_platform_selector()
|
||||
if hasattr(self.view, "platform_selector"):
|
||||
self.view.platform_selector.load_accounts()
|
||||
|
||||
def show_platform_selector_and_reset(self):
|
||||
"""Zeigt den Plattform-Selektor an und setzt die Eingabefelder zurück."""
|
||||
logger.info("Zurück zur Plattformauswahl mit Reset der Eingabefelder")
|
||||
|
||||
# Eingabefelder des aktuellen Platform-Controllers zurücksetzen
|
||||
if hasattr(self, 'current_platform') and self.current_platform in self.platform_controllers:
|
||||
controller = self.platform_controllers[self.current_platform]
|
||||
if hasattr(controller, '_generator_tab') and controller._generator_tab:
|
||||
# Tab auf None setzen, damit beim nächsten Öffnen ein neuer erstellt wird
|
||||
controller._generator_tab = None
|
||||
|
||||
# Zur Plattformauswahl zurückkehren
|
||||
self.show_platform_selector()
|
||||
|
||||
def _check_and_activate_license(self):
|
||||
"""
|
||||
Prüft die Lizenz und zeigt den Aktivierungsdialog wenn nötig.
|
||||
|
||||
Returns:
|
||||
True wenn Lizenz gültig, False wenn Benutzer abbricht
|
||||
"""
|
||||
# Versuche Session fortzusetzen
|
||||
if self.license_manager.resume_session():
|
||||
logger.info("Bestehende Session fortgesetzt")
|
||||
return True
|
||||
|
||||
# Prüfe ob Lizenz vorhanden ist
|
||||
if self.license_manager.is_licensed():
|
||||
# Starte neue Session
|
||||
if self.license_manager.start_session():
|
||||
logger.info("Neue Session gestartet")
|
||||
return True
|
||||
else:
|
||||
logger.error("Session konnte nicht gestartet werden")
|
||||
# Zeige Fehlermeldung statt Aktivierungsdialog
|
||||
# Hole detaillierte Fehlermeldung
|
||||
session_result = self.license_manager.session_manager.start_session(
|
||||
self.license_manager.license_data["key"],
|
||||
self.license_manager.license_data.get("activation_id")
|
||||
)
|
||||
error_msg = session_result.get("error", "Unbekannter Fehler")
|
||||
|
||||
QMessageBox.critical(
|
||||
None,
|
||||
"Session-Fehler",
|
||||
f"Die Lizenz ist gültig, aber es konnte keine Session gestartet werden.\n\n"
|
||||
f"Grund: {error_msg}\n\n"
|
||||
"Mögliche Lösungen:\n"
|
||||
"- Schließen Sie andere laufende Instanzen\n"
|
||||
"- Warten Sie einen Moment und versuchen Sie es erneut\n"
|
||||
"- Kontaktieren Sie den Support",
|
||||
QMessageBox.Ok
|
||||
)
|
||||
return False
|
||||
|
||||
# Keine gültige Lizenz - zeige Aktivierungsdialog
|
||||
logger.info("Keine gültige Lizenz gefunden - zeige Aktivierungsdialog")
|
||||
|
||||
dialog = LicenseActivationDialog(self.license_manager)
|
||||
dialog.activation_successful.connect(self._on_license_activated)
|
||||
|
||||
result = dialog.exec_()
|
||||
return result == dialog.Accepted
|
||||
|
||||
def _on_license_activated(self):
|
||||
"""Wird aufgerufen wenn Lizenz erfolgreich aktiviert wurde."""
|
||||
logger.info("Lizenz wurde erfolgreich aktiviert")
|
||||
|
||||
def _start_license_session(self):
|
||||
"""Startet die Lizenz-Session für die laufende Anwendung."""
|
||||
if not self.license_manager.session_manager.is_session_active():
|
||||
if self.license_manager.is_licensed():
|
||||
self.license_manager.start_session()
|
||||
|
||||
def check_license(self):
|
||||
"""Überprüft den Lizenzstatus (für UI Updates)."""
|
||||
is_licensed = self.license_manager.is_licensed()
|
||||
license_info = self.license_manager.get_license_info()
|
||||
status_text = self.license_manager.get_status_text()
|
||||
|
||||
# UI kann hier aktualisiert werden basierend auf Lizenzstatus
|
||||
logger.info(f"Lizenzstatus: {status_text}")
|
||||
|
||||
return is_licensed
|
||||
|
||||
def check_for_updates(self):
|
||||
"""Prüft auf Updates."""
|
||||
try:
|
||||
# Mit Lizenzschlüssel prüfen wenn vorhanden
|
||||
license_key = self.license_manager.get_license_info().get("key")
|
||||
update_info = self.update_checker.check_for_updates(license_key=license_key)
|
||||
|
||||
if update_info["has_update"]:
|
||||
reply = QMessageBox.question(
|
||||
self.view,
|
||||
"Update verfügbar",
|
||||
f"Eine neue Version ist verfügbar: {update_info['latest_version']}\n"
|
||||
f"(Aktuelle Version: {update_info['current_version']})\n\n"
|
||||
f"Release-Datum: {update_info['release_date']}\n"
|
||||
f"Release-Notes:\n{update_info['release_notes']}\n\n"
|
||||
"Möchten Sie das Update jetzt herunterladen?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.Yes
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.download_update(update_info)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Update-Prüfung: {e}")
|
||||
|
||||
def download_update(self, update_info):
|
||||
"""Lädt ein Update herunter."""
|
||||
try:
|
||||
download_result = self.update_checker.download_update(
|
||||
update_info["download_url"],
|
||||
update_info["latest_version"]
|
||||
)
|
||||
|
||||
if download_result["success"]:
|
||||
QMessageBox.information(
|
||||
self.view,
|
||||
"Download erfolgreich",
|
||||
f"Update wurde heruntergeladen: {download_result['file_path']}\n\n"
|
||||
"Bitte schließen Sie die Anwendung und führen Sie das Update aus."
|
||||
)
|
||||
else:
|
||||
QMessageBox.warning(
|
||||
self.view,
|
||||
"Download fehlgeschlagen",
|
||||
f"Fehler beim Herunterladen des Updates:\n{download_result['error']}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Herunterladen des Updates: {e}")
|
||||
QMessageBox.critical(
|
||||
self.view,
|
||||
"Fehler",
|
||||
f"Fehler beim Herunterladen des Updates:\n{str(e)}"
|
||||
)
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren