From 2af4603ba306677e168e3bec187755d567deb784 Mon Sep 17 00:00:00 2001 From: Thomas Kerpe Date: Tue, 9 Jun 2026 20:32:35 +0200 Subject: [PATCH] Implement profile change detection and persistence - Enhance topic detection with message_thread_id (primary) and reply_to_topic_id (fallback) - Add DatabaseManager.get_user_profile() to load stored user profiles - Add DatabaseManager.update_user_profile() for profile-only updates (without affecting message_count) - Refactor handle_profile_update() to compare stored vs current profiles - Automatically detect name and username changes in handle_message() - Persist detected profile changes to user_stats and profile_history tables - Log profile changes with before/after details in activity logging --- .gitignore | 1 + activity_log.txt | 72 ++++++++++++++++++++++++ bot.py | 143 ++++++++++++++++++++++++++++++++++++----------- 3 files changed, 183 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 0fc3ffa..8902f25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ config.yaml venv +.venv *.db *.pyc diff --git a/activity_log.txt b/activity_log.txt index 0a51a76..97f9da5 100644 --- a/activity_log.txt +++ b/activity_log.txt @@ -12,3 +12,75 @@ Хотелось бы ...' [2026-06-09 18:28:43] | CHAT_ID=-1001465084814 | TOPIC=MAIN | TYPE=MESSAGE | USER=93813065 (chrisarnu) | DETAILS=Nachricht gesendet: '@admin...' [2026-06-09 18:28:43] | CHAT_ID=-1001465084814 | TOPIC=MAIN | TYPE=MESSAGE | USER=93813065 (chrisarnu) | DETAILS=Nachricht gesendet: '@admin...' +[2026-06-09 19:36:03] | CHAT_ID=-1001465084814 | TOPIC=MAIN | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:36:03] | CHAT_ID=-1001465084814 | TOPIC=MAIN | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:38:04] | CHAT_ID=-1001465084814 | TOPIC=MAIN | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:38:04] | CHAT_ID=-1001465084814 | TOPIC=MAIN | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:47:37] | CHAT_ID=-1001465084814 | TOPIC=84696 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:47:37] | CHAT_ID=-1001465084814 | TOPIC=84696 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:49:05] | CHAT_ID=-1001465084814 | TOPIC=84696 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:49:05] | CHAT_ID=-1001465084814 | TOPIC=84696 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: '....' +[2026-06-09 19:54:35] | CHAT_ID=-1001202289941 | TOPIC=MAIN | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'hi...' +[2026-06-09 19:54:35] | CHAT_ID=-1001202289941 | TOPIC=MAIN | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'hi...' +[2026-06-09 19:54:55] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'test...' +[2026-06-09 19:54:55] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'test...' +[2026-06-09 19:55:53] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 19:55:53] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 19:56:20] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'b...' +[2026-06-09 19:56:20] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'b...' +[2026-06-09 19:56:50] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 's...' +[2026-06-09 19:56:50] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 's...' +[2026-06-09 19:57:21] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 19:57:21] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 19:58:47] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'b...' +[2026-06-09 19:58:47] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'b...' +[2026-06-09 20:14:31] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:31] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:38] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:38] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:52] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:52] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:59] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:14:59] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:15:36] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'ah ok...' +[2026-06-09 20:15:36] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'ah ok...' +[2026-06-09 20:16:36] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'hmm...' +[2026-06-09 20:16:36] | CHAT_ID=-1001202289941 | TOPIC=976 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'hmm...' +[2026-06-09 20:17:53] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:17:53] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:18:13] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'OK?...' +[2026-06-09 20:18:13] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'OK?...' +[2026-06-09 20:21:32] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:21:32] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:21:32] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:21:32] | CHAT_ID=-1001202289941 | TOPIC=757 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'a...' +[2026-06-09 20:22:38] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:22:38] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:22:38] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'geht das?...' +[2026-06-09 20:22:38] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'geht das?...' +[2026-06-09 20:23:31] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:23:31] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:23:31] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'aha...' +[2026-06-09 20:23:31] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'aha...' +[2026-06-09 20:24:05] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:24:05] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:24:05] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'aber...' +[2026-06-09 20:24:05] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'aber...' +[2026-06-09 20:24:57] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:24:57] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:24:57] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'nun?...' +[2026-06-09 20:24:57] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'nun?...' +[2026-06-09 20:25:14] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:25:14] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:25:14] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'grummel...' +[2026-06-09 20:25:14] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'grummel...' +[2026-06-09 20:27:30] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:27:30] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke 🌻' → 'Toke. 🌻' +[2026-06-09 20:27:30] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'asd...' +[2026-06-09 20:27:30] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'asd...' +[2026-06-09 20:27:34] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'sad...' +[2026-06-09 20:27:34] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'sad...' +[2026-06-09 20:28:04] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke. 🌻' → 'Toke 🌻' +[2026-06-09 20:28:04] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=PROFILE_CHANGE | USER=151261436 (tokelemma) | DETAILS=Profiländerung erkannt | Name: 'Toke. 🌻' → 'Toke 🌻' +[2026-06-09 20:28:04] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'Und back...' +[2026-06-09 20:28:04] | CHAT_ID=-1001202289941 | TOPIC=761 | TYPE=MESSAGE | USER=151261436 (tokelemma) | DETAILS=Nachricht gesendet: 'Und back...' diff --git a/bot.py b/bot.py index 117fc13..9209bb5 100644 --- a/bot.py +++ b/bot.py @@ -140,6 +140,35 @@ class DatabaseManager: except Exception as e: logging.error(f"Fehler beim Aktualisieren der User Stats für {user_id}: {e}") + def get_user_profile(self, user_id: int) -> dict: + """Lädt das gespeicherte Profil eines Benutzers aus der Datenbank.""" + try: + self.cursor.execute(""" + SELECT full_name, username FROM user_stats WHERE user_id = ? + """, (user_id,)) + result = self.cursor.fetchone() + if result: + return {'full_name': result[0], 'username': result[1]} + return None + except Exception as e: + logging.error(f"Fehler beim Laden des Benutzerprofils {user_id}: {e}") + return None + + def update_user_profile(self, user_id: int, full_name: str, username: str): + """Aktualisiert nur die Profilinformationen (Name/Username) eines Benutzers. + + Erstellt den Benutzer automatisch, falls er noch nicht existiert. + """ + try: + self.cursor.execute(""" + INSERT INTO user_stats (user_id, full_name, username, message_count, last_message_timestamp) + VALUES (?, ?, ?, 0, NULL) + ON CONFLICT(user_id) DO UPDATE SET full_name = excluded.full_name, username = excluded.username + """, (user_id, full_name, username)) + self.conn.commit() + except Exception as e: + logging.error(f"Fehler beim Aktualisieren des Benutzerprofils {user_id}: {e}") + def close(self): """Schließt die Datenbankverbindung.""" self.conn.close() @@ -157,11 +186,25 @@ class MonitoringBot: # --- HILFSFUNKTIONEN ZUR TOPIC-ERKENNUNG --- def _get_topic_id(self, update: Update) -> str: - """Extrahiert die Topic ID aus dem Update (Topic Aware).""" - if update.effective_chat and hasattr(update.message, 'reply_to_topic'): - # Dies ist ein sehr spezifischer API-Pfad und muss je nach PTB-Version/Update angepasst werden. - return str(update.message.reply_to_topic) - # Fallback: Hauptthema (MAIN). + """Extrahiert die Topic ID aus dem Update (Topic Aware). + + Versucht verschiedene Attribute je nach Telegram PTB-Version: + - message_thread_id: Für Nachrichten in Topics/Threads + - forum_topic_created: Wenn ein neues Topic erstellt wurde + - reply_to_topic_id: Fallback für explizite Topic-Antworten + """ + if not update.message: + return 'MAIN' + + # Versuche message_thread_id (Standard für Topics) + if hasattr(update.message, 'message_thread_id') and update.message.message_thread_id: + return str(update.message.message_thread_id) + + # Versuche reply_to_topic_id (Fallback) + if hasattr(update.message, 'reply_to_topic_id') and update.message.reply_to_topic_id: + return str(update.message.reply_to_topic_id) + + # Fallback: Hauptthema (MAIN) return 'MAIN' # --- EVENT HANDLER 1: BEITRITT/AUSSTIEG --- @@ -176,42 +219,76 @@ class MonitoringBot: self._log_event(client, context, chat_id, topic_id, "JOIN", new_member.id, new_member.full_name, f"Beitritt von {new_member.full_name}") - # --- EVENT HANDLER 2: PROFILDÄNDERUNG (Jetzt History Loggend) --- - async def handle_profile_update(self, client: Update, context: ContextTypes.DEFAULT_TYPE): - """Verarbeitet simulierte Profiländerungen und protokolliert sie.""" - user = client.effective_user - chat_id = client.effective_chat.id - topic_id = self._get_topic_id(client.update) + # --- EVENT HANDLER 2: PROFILDÄNDERUNG (Profilvergleich mit DB) --- + async def handle_profile_update(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Erkennt Profiländerungen durch Vergleich des gespeicherten Profils mit dem aktuellen.""" + + #if not update or not update.effective_user or not update.effective_chat: + # return - # Da PTB keine direkten Profile-Update Events liefert, simulieren wir das Loggen eines - # gewünschten Change-Events basierend auf einem Trigger (z.B. /changename). - if context.args: - new_name = " ".join(context.args) # Annahme: Der User sendet den neuen Namen als Argument - # Hier müsste die Logik für alte vs neue Werte komplexer sein, - # aber wir loggen das gewünschte Ergebnis: - old_details = "N/A" - new_details = new_name - self._log_event(client, context, chat_id, topic_id, "PROFILE_CHANGE", user.id, user.full_name, f"Profiländerung: {old_details} -> {new_details}") + user = update.effective_user + chat_id = update.effective_chat.id + topic_id = self._get_topic_id(update) + current_full_name = user.full_name + current_username = getattr(user, 'username', None) - # Speichern der Änderung im dedizierten History Log - self.db.log_profile_change( - group_chat_id=chat_id, - user_id=user.id, - topic_id=topic_id, - old_name="Simulated Old Name", - new_name=new_details, - old_user="Simulated Old User", - new_user=getattr(user, 'username', 'N/A'), - details="Profil manuell via Bot-Befehl geändert." - ) + # Lade das alte Profil aus der Datenbank + old_profile = self.db.get_user_profile(user.id) + + # Vergleiche mit dem aktuellen Profil + if old_profile: + old_full_name = old_profile['full_name'] + old_username = old_profile['username'] + + # Prüfe auf Änderungen + has_name_changed = old_full_name != current_full_name + has_username_changed = old_username != current_username + + if has_name_changed or has_username_changed: + details = f"Profiländerung erkannt" + if has_name_changed: + details += f" | Name: '{old_full_name}' → '{current_full_name}'" + if has_username_changed: + details += f" | Username: '{old_username}' → '{current_username}'" + + self._log_event( + client=update, context=context, chat_id=chat_id, topic_id=topic_id, + activity_type="PROFILE_CHANGE", user_id=user.id, + username=current_username or user.id, details=details + ) + + # Speichere die Änderung im History Log + self.db.log_profile_change( + group_chat_id=chat_id, + user_id=user.id, + topic_id=topic_id, + old_name=old_full_name or "N/A", + new_name=current_full_name, + old_user=old_username or "N/A", + new_user=current_username or "N/A", + details=details + ) + + # Persistiere die neuen Profilinformationen in user_stats + self.db.update_user_profile( + user_id=user.id, + full_name=current_full_name, + username=current_username + ) - # --- EVENT HANDLER 3: MESSAGE (Statistik & Topic Aware) --- + # --- EVENT HANDLER 3: MESSAGE (Statistik & Topic Aware & Profiländerungserkennung) --- async def handle_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE): - """Verarbeitet jede Nachricht und aktualisiert die Statistiken des ABSENDERS.""" + """Verarbeitet jede Nachricht und aktualisiert die Statistiken des ABSENDERS. + + Erkennt auch automatisch Profiländerungen durch Vergleich mit der Datenbank. + """ if not update or not update.effective_chat or not update.effective_user: return + # 0. Erkenne Profiländerungen BEVOR die Stats aktualisiert werden + await self.handle_profile_update(update, context) + # 1. TOPIC ID EXTRAHIEREN topic_id = self._get_topic_id(update)