diff --git a/edu_master/webinar-checker/checker.py b/edu_master/webinar-checker/checker.py index 60c3dbb..65043cf 100644 --- a/edu_master/webinar-checker/checker.py +++ b/edu_master/webinar-checker/checker.py @@ -15,6 +15,11 @@ logging.basicConfig( ) logger = logging.getLogger(__name__) +# Suppress HTTP request logs +logging.getLogger('urllib3').setLevel(logging.WARNING) +logging.getLogger('httpx').setLevel(logging.WARNING) +logging.getLogger('telegram.ext._application').setLevel(logging.WARNING) + # Load environment variables def _env(key, default=None): v = os.getenv(key, default) @@ -39,7 +44,7 @@ KEY_WHITELIST = "bot:whitelist" KEY_WHITELIST_ENABLED = "bot:whitelist_enabled" KEY_SUBSCRIBERS = "bot:subscribers" KEY_PHPSESSID = "EDU_PHPSESSID" -KEY_WEBINAR_HISTORY = "bot:webinar_history" # Stores last 5 webinars +KEY_WEBINAR_HISTORY = "bot:webinar_history" # Stores last 3 webinars # Initialize Redis try: @@ -89,6 +94,8 @@ TRANSLATIONS = { 'flag_ru': "🇷🇺 Русский", 'flag_uk': "🇺🇦 Українська", 'flag_en': "🇬🇧 English", + 'history_cleared': "✅ История вебинаров очищена", + 'history_clear_failed': "❌ Ошибка при очистке истории", }, 'uk': { 'welcome': "👋 Привіт, {name}!\n\nЯ бот-сповіщувач про вебінари. Я повідомлятиму вас, коли з'явиться новий вебінар.\nВи підписані на сповіщення.", @@ -126,6 +133,8 @@ TRANSLATIONS = { 'flag_ru': "🇷🇺 Русский", 'flag_uk': "🇺🇦 Українська", 'flag_en': "🇬🇧 English", + 'history_cleared': "✅ Історія вебінарів очищена", + 'history_clear_failed': "❌ Помилка при очищенні історії", }, 'en': { 'welcome': "👋 Hello, {name}!\n\nI am the Webinar Checker Bot. I will notify you when a new webinar appears.\nYou have been subscribed to notifications.", @@ -163,6 +172,8 @@ TRANSLATIONS = { 'flag_ru': "🇷🇺 Русский", 'flag_uk': "🇺🇦 Українська", 'flag_en': "🇬🇧 English", + 'history_cleared': "✅ Webinar history cleared", + 'history_clear_failed': "❌ Error clearing history", } } @@ -350,6 +361,21 @@ async def remove_user(update: Update, context: ContextTypes.DEFAULT_TYPE): except ValueError: await update.message.reply_text(t(admin_id, 'invalid_user_id')) +async def clear_history(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Clear webinar history (admin only).""" + admin_id = update.effective_user.id + if admin_id != ADMIN_ID: + await update.message.reply_text(t(admin_id, 'admin_only')) + return + + try: + redis_client.delete(KEY_WEBINAR_HISTORY) + await update.message.reply_text(t(admin_id, 'history_cleared')) + logger.info("Admin cleared webinar history") + except Exception as e: + logger.error(f"Failed to clear history: {e}") + await update.message.reply_text(t(admin_id, 'history_clear_failed')) + # --- Admin Callbacks --- async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): @@ -410,9 +436,9 @@ async def language_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): # --- Webinar Checking Job --- -def get_webinar_key(name: str, url: str) -> str: - """Generate unique key for a webinar based on name and URL.""" - return f"{name}|{url}" +def get_webinar_key(url: str) -> str: + """Generate unique key for a webinar based on URL.""" + return url def get_stored_webinars() -> list: """Get list of stored webinar keys from Redis.""" @@ -425,9 +451,9 @@ def get_stored_webinars() -> list: return [] def store_webinars(webinar_keys: list): - """Store up to 5 most recent webinar keys in Redis.""" - # Keep only last 5 - webinar_keys = webinar_keys[-5:] + """Store up to 3 most recent webinar keys in Redis.""" + # Keep only last 3 + webinar_keys = webinar_keys[-3:] try: redis_client.set(KEY_WEBINAR_HISTORY, json.dumps(webinar_keys)) logger.info(f"Stored {len(webinar_keys)} webinar(s) in history") @@ -562,7 +588,7 @@ async def check_webinars_job(context: ContextTypes.DEFAULT_TYPE): current_keys = [] for webinar in current_webinars: - key = get_webinar_key(webinar['name'], webinar['url']) + key = get_webinar_key(webinar['url']) current_keys.append(key) if key not in stored_keys: @@ -622,6 +648,7 @@ def main(): app.add_handler(CommandHandler("language", language_command)) app.add_handler(CommandHandler("adduser", add_user)) app.add_handler(CommandHandler("removeuser", remove_user)) + app.add_handler(CommandHandler("clearhistory", clear_history)) # Callback handlers - language selection first, then admin panel app.add_handler(CallbackQueryHandler(language_callback, pattern="^lang_"))