From 5d82dfa2892057b66360a1e077e7d296c34da4d5 Mon Sep 17 00:00:00 2001 From: Thomas Kerpe Date: Wed, 10 Jun 2026 17:21:29 +0200 Subject: [PATCH] Added automatic topic reopening and renaming last_message_timestamp to lastseen_timestamp --- bot.py | 81 ++++++++++++++++++++++++++++++++++++++++----- config_example.yaml | 7 ++++ setup_venv.sh | 0 3 files changed, 79 insertions(+), 9 deletions(-) mode change 100644 => 100755 setup_venv.sh diff --git a/bot.py b/bot.py index f0171cb..c02be63 100644 --- a/bot.py +++ b/bot.py @@ -38,6 +38,9 @@ WRITE_ACTIVITY_TO_FILE = config['logging']['write_to_file'] LOGGING_FILE = config['logging']['file_name'] LOG_LEVEL = getattr(logging, config['logging']['level'], logging.INFO) +# Forum Topics: Ausnahlmeliste (nicht zu reopening) +NOT_REOPEN_TOPICS = config.get('forum_topics', {}).get('not_reopen_topics', []) + # Logging konfigurieren logging.basicConfig(level=LOG_LEVEL, format='%(asctime)s - %(levelname)s - %(message)s') @@ -76,7 +79,7 @@ class DatabaseManager: last_name TEXT, username TEXT, is_bot INTEGER DEFAULT 0, - last_message_timestamp TEXT NULL + lastseen_timestamp TEXT NULL ) """) @@ -150,7 +153,7 @@ class DatabaseManager: """ try: self.cursor.execute(""" - INSERT INTO user_profile (user_id, first_name, last_name, username, is_bot, last_message_timestamp) + INSERT INTO user_profile (user_id, first_name, last_name, username, is_bot, lastseen_timestamp) VALUES (?, ?, ?, ?, ?, NULL) ON CONFLICT(user_id) DO UPDATE SET first_name = excluded.first_name, @@ -162,19 +165,19 @@ class DatabaseManager: except Exception as e: logging.error(f"Fehler beim Aktualisieren des Benutzerprofils {user_id}: {e}") - def update_user_stats(self, user_id: int, last_message_timestamp: str, first_name: str = None, last_name: str = None, username: str = None, is_bot: bool = False): + def update_user_stats(self, user_id: int, lastseen_timestamp: str, first_name: str = None, last_name: str = None, username: str = None, is_bot: bool = False): """Aktualisiert die Statistiken und das letzte bekannte Profil des Benutzers.""" try: self.cursor.execute(""" - INSERT INTO user_profile (user_id, first_name, last_name, username, is_bot, last_message_timestamp) + INSERT INTO user_profile (user_id, first_name, last_name, username, is_bot, lastseen_timestamp) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(user_id) DO UPDATE SET - last_message_timestamp = excluded.last_message_timestamp, + lastseen_timestamp = excluded.lastseen_timestamp, first_name = COALESCE(excluded.first_name, user_profile.first_name), last_name = COALESCE(excluded.last_name, user_profile.last_name), username = COALESCE(excluded.username, user_profile.username), is_bot = COALESCE(NULLIF(excluded.is_bot, 0), user_profile.is_bot) - """, (user_id, first_name, last_name, username, int(is_bot), last_message_timestamp)) + """, (user_id, first_name, last_name, username, int(is_bot), lastseen_timestamp)) self.conn.commit() except Exception as e: logging.error(f"Fehler beim Aktualisieren der User Stats für {user_id}: {e}") @@ -228,6 +231,63 @@ 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 1B: FORUM TOPIC GESCHLOSSEN --- + async def handle_forum_topic_closed(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Überwacht das Schließen von Forum-Topics und öffnet sie wieder (außer in der Ausnahlmeliste).""" + if not update or not update.message or not update.effective_chat: + return + + chat_id = update.effective_chat.id + + # Prüfe, ob ein Topic-Close-Event vorliegt + if hasattr(update.message, 'forum_topic_closed') and update.message.forum_topic_closed: + topic_id = self._get_topic_id(update) + + details = f"Forum-Topic wurde geschlossen (Topic ID: {topic_id})" + self._log_event( + client=update, context=context, chat_id=chat_id, topic_id=topic_id, + activity_type="TOPIC_CLOSED", user_id=0, username="system", + details=details + ) + + # Prüfe, ob dieses Topic in der Ausnahlmeliste ist + should_skip = any( + item['group_id'] == chat_id and str(item['topic_id']) == topic_id + for item in NOT_REOPEN_TOPICS + ) + + if should_skip: + skip_details = f"Topic-Reopening übersprungen (in Ausnahmeliste)" + self._log_event( + client=update, context=context, chat_id=chat_id, topic_id=topic_id, + activity_type="TOPIC_REOPEN_SKIPPED", user_id=0, username="system", + details=skip_details + ) + logging.info(f"⏭️ Topic {topic_id} in Chat {chat_id} wird nicht wiedereröffnet (Ausnahlmeliste)") + return + + # Versuche das Topic wieder zu öffnen + try: + await context.bot.reopen_forum_topic(chat_id=chat_id, message_thread_id=int(topic_id)) + + reopen_details = f"Forum-Topic automatisch wiedereröffnet (Topic ID: {topic_id})" + self._log_event( + client=update, context=context, chat_id=chat_id, topic_id=topic_id, + activity_type="TOPIC_REOPENED", user_id=0, username="system", + details=reopen_details + ) + logging.info(f"✅ Topic {topic_id} in Chat {chat_id} wurde wiedereröffnet") + + except Exception as e: + error_details = f"Fehler beim Wiedereröffnen von Topic {topic_id}: {str(e)}" + self._log_event( + client=update, context=context, chat_id=chat_id, topic_id=topic_id, + activity_type="TOPIC_REOPEN_FAILED", user_id=0, username="system", + details=error_details + ) + logging.error(f"❌ {error_details}") + + # --- EVENT HANDLER 2: PROFILDÄNDERUNG (Profilvergleich mit DB) --- async def handle_profile_update(self, update: Update, context: ContextTypes.DEFAULT_TYPE): @@ -308,6 +368,9 @@ class MonitoringBot: if not update or not update.effective_chat or not update.effective_user: return + # -1. Überwache Forum-Topic-Closes + await self.handle_forum_topic_closed(update, context) + # 0. Erkenne Profiländerungen BEVOR die Stats aktualisiert werden await self.handle_profile_update(update, context) @@ -322,7 +385,7 @@ class MonitoringBot: # 2. Statistik-Update: Profildaten speichern und Timestamp aktualisieren self._update_user_stats( user_id=user.id, - last_message_timestamp=timestamp_str, + lastseen_timestamp=timestamp_str, first_name=user.first_name, last_name=user.last_name or None, username=getattr(user, 'username', None), @@ -353,9 +416,9 @@ class MonitoringBot: with open(LOGGING_FILE, 'a', encoding='utf-8') as f: f.write(log_message) - def _update_user_stats(self, user_id: int, last_message_timestamp: str, first_name: str = None, last_name: str = None, username: str = None, is_bot: bool = False): + def _update_user_stats(self, user_id: int, lastseen_timestamp: str, first_name: str = None, last_name: str = None, username: str = None, is_bot: bool = False): """Wrapper für DatabaseManager.update_user_stats().""" - self.db.update_user_stats(user_id, last_message_timestamp, first_name, last_name, username, is_bot) + self.db.update_user_stats(user_id, lastseen_timestamp, first_name, last_name, username, is_bot) # --- HAUPT-RUN FUNKTION (Bleibt gleich) --- diff --git a/config_example.yaml b/config_example.yaml index 57e02d1..3d63770 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -18,3 +18,10 @@ logging: file_name: "activity_log.txt" # Python Logging Level (DEBUG, INFO, WARNING, ERROR, CRITICAL) level: "INFO" + +# Forum-Topic Management +forum_topics: + # Topics, die NICHT automatisch wiedereröffnet werden sollen + # Format: [{"group_id": 123456, "topic_id": "1"}, {"group_id": 123456, "topic_id": "2"}] + not_reopen_topics: [] + diff --git a/setup_venv.sh b/setup_venv.sh old mode 100644 new mode 100755