From 23824dc5fe4acdfc1aa126532ebd01d6f488ccca Mon Sep 17 00:00:00 2001 From: UdoChudo Date: Wed, 10 Jul 2024 22:48:51 +0500 Subject: [PATCH] Add Logging of sub/unsub/register Add Russian localization --- telezab.py | 192 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 137 insertions(+), 55 deletions(-) diff --git a/telezab.py b/telezab.py index 668c49e..c6c49fe 100644 --- a/telezab.py +++ b/telezab.py @@ -63,11 +63,12 @@ def init_db(): data TEXT, delivered BOOLEAN)''') - # Create subscriptions table with username + # Create subscriptions table with username and active flag cursor.execute('''CREATE TABLE IF NOT EXISTS subscriptions ( chat_id INTEGER, region_id TEXT, username TEXT, + active BOOLEAN DEFAULT TRUE, skip BOOLEAN DEFAULT FALSE, UNIQUE(chat_id, region_id))''') @@ -75,10 +76,19 @@ def init_db(): cursor.execute('''CREATE TABLE IF NOT EXISTS whitelist ( chat_id INTEGER PRIMARY KEY)''') - # Create regions table + # Create regions table with active flag cursor.execute('''CREATE TABLE IF NOT EXISTS regions ( region_id TEXT PRIMARY KEY, - region_name TEXT)''') + region_name TEXT, + active BOOLEAN DEFAULT TRUE)''') + + # Create user events table for logging + cursor.execute('''CREATE TABLE IF NOT EXISTS user_events ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + chat_id INTEGER, + username TEXT, + action TEXT, + timestamp TEXT)''') # Insert sample regions cursor.execute('''INSERT OR IGNORE INTO regions (region_id, region_name) VALUES @@ -133,7 +143,7 @@ def get_regions(): with db_lock: conn = sqlite3.connect('telezab.db') cursor = conn.cursor() - cursor.execute('SELECT region_id, region_name FROM regions ORDER BY region_id') + cursor.execute('SELECT region_id, region_name FROM regions WHERE active = TRUE ORDER BY region_id') regions = cursor.fetchall() conn.close() return regions @@ -147,7 +157,7 @@ def get_user_subscribed_regions(chat_id): SELECT regions.region_id, regions.region_name FROM subscriptions JOIN regions ON subscriptions.region_id = regions.region_id - WHERE subscriptions.chat_id = ? AND subscriptions.skip = FALSE + WHERE subscriptions.chat_id = ? AND subscriptions.active = TRUE AND subscriptions.skip = FALSE ORDER BY regions.region_id ''', (chat_id,)) regions = cursor.fetchall() @@ -158,13 +168,25 @@ def get_user_subscribed_regions(chat_id): def format_regions_list(regions): return '\n'.join([f"{region_id} - {region_name}" for region_id, region_name in regions]) +# Log user events +def log_user_event(chat_id, username, action): + timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + with db_lock: + conn = sqlite3.connect('telezab.db') + cursor = conn.cursor() + query = 'INSERT INTO user_events (chat_id, username, action, timestamp) VALUES (?, ?, ?, ?)' + app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}, action={action}, timestamp={timestamp}") + cursor.execute(query, (chat_id, username, action, timestamp)) + conn.commit() + conn.close() + # Main menu for users def show_main_menu(chat_id, is_whitelisted_user): markup = telebot.types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True) if is_whitelisted_user: - markup.add('Подписаться', 'Отписаться', 'Помощь', 'Add Region', 'Remove Region', 'Add Whitelist', 'Remove Whitelist') + markup.add('Подписаться', 'Отписаться', 'Мои подписки', 'Активные регионы', 'Помощь', 'Добавить регион', 'Удалить регион', 'Добавить в белый список', 'Удалить из белого списка') else: - markup.add('Register') + markup.add('Регистрация') bot.send_message(chat_id, "Выберите действие:", reply_markup=markup) # Handle /start command @@ -182,7 +204,7 @@ def handle_start(message): else: show_main_menu(chat_id, is_whitelisted_user=False) - app.logger.info(f"User {chat_id} ({username}) started with command /start.") + app.logger.info(f"User {chat_id} (@{username}) started with command /start.") # Handle menu button presses @bot.message_handler(func=lambda message: True) @@ -190,31 +212,36 @@ def handle_menu_selection(message): chat_id = message.chat.id text = message.text.strip().lower() - if text == 'register': + if text == 'регистрация': handle_register(message) elif text == 'подписаться': handle_subscribe(message) elif text == 'отписаться': handle_unsubscribe(message) + elif text == 'мои подписки': + handle_my_subscriptions(message) + elif text == 'активные регионы': + handle_active_regions(message) elif text == 'помощь': handle_help(message) - elif text == 'add region' and str(chat_id) in ADMIN_CHAT_IDS: + elif text == 'добавить регион' and str(chat_id) in ADMIN_CHAT_IDS: prompt_admin_for_region(chat_id, 'add') - elif text == 'remove region' and str(chat_id) in ADMIN_CHAT_IDS: + elif text == 'удалить регион' and str(chat_id) in ADMIN_CHAT_IDS: prompt_admin_for_region(chat_id, 'remove') - elif text == 'add whitelist' and str(chat_id) in ADMIN_CHAT_IDS: + elif text == 'добавить в белый список' and str(chat_id) in ADMIN_CHAT_IDS: prompt_admin_for_whitelist(chat_id, 'add') - elif text == 'remove whitelist' and str(chat_id) in ADMIN_CHAT_IDS: + elif text == 'удалить из белого списка' and str(chat_id) in ADMIN_CHAT_IDS: prompt_admin_for_whitelist(chat_id, 'remove') else: bot.send_message(chat_id, "Команда не распознана или у вас нет прав для выполнения этой команды.") show_main_menu(chat_id, is_whitelisted(chat_id)) # Handle /subscribe command to subscribe to a region +@bot.message_handler(commands=['subscribe', 'sub']) def handle_subscribe(message): chat_id = message.chat.id if not is_whitelisted(chat_id): - bot.send_message(chat_id, "You are not authorized to use this bot.") + bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") app.logger.info(f"Unauthorized access attempt by {chat_id}") return @@ -225,7 +252,7 @@ def handle_subscribe(message): username = "N/A" regions_list = format_regions_list(get_regions()) - bot.send_message(chat_id, f"Отправьте номер или номера регионов на которые хотите подписаться (через запятую):\n{regions_list}\n\nНапишите 'отмена' для отмены.") + bot.send_message(chat_id, f"Отправьте номер или номера регионов, на которые хотите подписаться (через запятую):\n{regions_list}\n\nНапишите 'отмена' для отмены.") bot.register_next_step_handler(message, process_subscription, chat_id, username) def process_subscription(message, chat_id, username): @@ -240,29 +267,35 @@ def process_subscription(message, chat_id, username): cursor = conn.cursor() for region_id in region_ids: region_id = region_id.strip() - query = 'INSERT OR IGNORE INTO subscriptions (chat_id, region_id, username) VALUES (?, ?, ?)' + query = 'INSERT OR IGNORE INTO subscriptions (chat_id, region_id, username, active) VALUES (?, ?, ?, TRUE)' app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}, username={username}") cursor.execute(query, (chat_id, region_id, username)) + if cursor.rowcount == 0: + query = 'UPDATE subscriptions SET active = TRUE WHERE chat_id = ? AND region_id = ?' + app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}") + cursor.execute(query, (chat_id, region_id)) conn.commit() conn.close() - bot.send_message(chat_id, f"Subscribed to regions: {', '.join(region_ids)}.") - app.logger.info(f"User {chat_id} ({username}) subscribed to regions: {', '.join(region_ids)}.") + bot.send_message(chat_id, f"Подписка на регионы: {', '.join(region_ids)} оформлена.") + app.logger.info(f"User {chat_id} (@{username}) subscribed to regions: {', '.join(region_ids)}.") + log_user_event(chat_id, username, f"Subscribed to regions: {', '.join(region_ids)}") show_main_menu(chat_id, is_whitelisted(chat_id)) # Handle /unsubscribe command to unsubscribe from a region +@bot.message_handler(commands=['unsubscribe']) def handle_unsubscribe(message): chat_id = message.chat.id if not is_whitelisted(chat_id): - bot.send_message(chat_id, "You are not authorized to use this bot.") + bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") app.logger.info(f"Unauthorized access attempt by {chat_id}") return user_regions = get_user_subscribed_regions(chat_id) if not user_regions: - bot.send_message(chat_id, "You are not subscribed to any regions.") + bot.send_message(chat_id, "Вы не подписаны ни на один регион.") else: regions_list = format_regions_list(user_regions) - bot.send_message(chat_id, f"Отправьте номер или номера регионов от которых хотите отписаться (через запятую):\n{regions_list}\n\nНапишите 'отмена' для отмены.") + bot.send_message(chat_id, f"Отправьте номер или номера регионов, от которых хотите отписаться (через запятую):\n{regions_list}\n\nНапишите 'отмена' для отмены.") bot.register_next_step_handler(message, process_unsubscription, chat_id) def process_unsubscription(message, chat_id): @@ -277,27 +310,35 @@ def process_unsubscription(message, chat_id): cursor = conn.cursor() for region_id in region_ids: region_id = region_id.strip() - query = 'DELETE FROM subscriptions WHERE chat_id = ? AND region_id = ?' + query = 'UPDATE subscriptions SET active = FALSE WHERE chat_id = ? AND region_id = ?' app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}") cursor.execute(query, (chat_id, region_id)) conn.commit() conn.close() - bot.send_message(chat_id, f"Unsubscribed from regions: {', '.join(region_ids)}.") - app.logger.info(f"User {chat_id} unsubscribed from regions: {', '.join(region_ids)}.") + bot.send_message(chat_id, f"Отписка от регионов: {', '.join(region_ids)} оформлена.") + username = message.from_user.username + if username: + username = f"@{username}" + else: + username = "N/A" + app.logger.info(f"User {chat_id} (@{username}) unsubscribed from regions: {', '.join(region_ids)}.") + log_user_event(chat_id, username, f"Unsubscribed from regions: {', '.join(region_ids)}") show_main_menu(chat_id, is_whitelisted(chat_id)) # Handle /help command to provide instructions +@bot.message_handler(commands=['help']) def handle_help(message): help_text = ( "/start - Начать работу с ботом\n" - "/subscribe - Подписаться на рассылку событий по региону. Необходимо указать номер региона пример /subscribe 01 - Адыгея\n" - "/unsubscribe - Отписаться от рассылки событий по региону. Необходимо указать номер региона пример /unsubscribe 01 - Адыгея\n" + "/subscribe (/sub) - Подписаться на рассылку событий по региону. Укажите номер региона, например, /subscribe 01 - Адыгея\n" + "/unsubscribe - Отписаться от рассылки событий по региону. Укажите номер региона, например, /unsubscribe 01 - Адыгея\n" "/register - Запросить регистрацию в боте" ) bot.send_message(message.chat.id, help_text) show_main_menu(message.chat.id, is_whitelisted(message.chat.id)) # Handle /register command for new user registration +@bot.message_handler(commands=['register']) def handle_register(message): chat_id = message.chat.id username = message.from_user.username @@ -308,7 +349,8 @@ def handle_register(message): markup = telebot.types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True) markup.add('Подтвердить регистрацию', 'Отмена') - bot.send_message(chat_id, f"Your chat ID is {chat_id} and your username is {username}. Requesting admin approval...", reply_markup=markup) + bot.send_message(chat_id, f"Ваш chat ID: {chat_id}, ваше имя пользователя: @{username}. Запрос на одобрение отправлен администратору.", reply_markup=markup) + log_user_event(chat_id, username, "Requested registration") bot.register_next_step_handler(message, process_register, chat_id, username) def process_register(message, chat_id, username): @@ -323,12 +365,12 @@ def process_register(message, chat_id, username): markup.add(f'/add_whitelist {chat_id}', 'Отмена') bot.send_message( admin_chat_id, - f"User {username} ({chat_id}) is requesting to register.\n" - f"Do you approve this action?", + f"Пользователь {username} ({chat_id}) запрашивает регистрацию.\n" + f"Вы подтверждаете это действие?", reply_markup=markup ) bot.send_message(chat_id, "Запрос отправлен администратору для одобрения.") - app.logger.info(f"User {chat_id} ({username}) requested registration.") + app.logger.info(f"User {chat_id} (@{username}) requested registration.") else: bot.send_message(chat_id, "Некорректный выбор. Регистрация отменена.") show_main_menu(chat_id, is_whitelisted(chat_id)) @@ -339,7 +381,7 @@ def prompt_admin_for_region(chat_id, action): bot.send_message(chat_id, "Введите ID и название региона в формате: ") bot.register_next_step_handler_by_chat_id(chat_id, process_add_region) elif action == 'remove': - bot.send_message(chat_id, "Введите ID региона, который хотите удалить") + bot.send_message(chat_id, "Введите ID региона, который хотите сделать неактивным") bot.register_next_step_handler_by_chat_id(chat_id, process_remove_region) def process_add_region(message): @@ -354,10 +396,10 @@ def process_add_region(message): cursor.execute(query, (region_id, region_name)) conn.commit() conn.close() - bot.send_message(chat_id, f"Region {region_id} - {region_name} added.") + bot.send_message(chat_id, f"Регион {region_id} - {region_name} добавлен.") app.logger.info(f"Admin {chat_id} added region {region_id} - {region_name}.") except (IndexError, ValueError): - bot.send_message(chat_id, "Invalid format. Use: ") + bot.send_message(chat_id, "Неверный формат. Используйте: ") show_main_menu(chat_id, is_whitelisted(chat_id)) def process_remove_region(message): @@ -367,27 +409,27 @@ def process_remove_region(message): with db_lock: conn = sqlite3.connect('telezab.db') cursor = conn.cursor() - query = 'DELETE FROM regions WHERE region_id = ?' + query = 'UPDATE regions SET active = FALSE WHERE region_id = ?' app.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) - query = 'UPDATE subscriptions SET skip = TRUE WHERE region_id = ?' + query = 'UPDATE subscriptions SET active = FALSE WHERE region_id = ? AND active = TRUE' app.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) conn.commit() conn.close() - bot.send_message(chat_id, f"Region {region_id} removed and all subscriptions updated.") - app.logger.info(f"Admin {chat_id} removed region {region_id} and updated subscriptions.") + bot.send_message(chat_id, f"Регион {region_id} теперь неактивен и все активные подписки обновлены.") + app.logger.info(f"Admin {chat_id} set region {region_id} to inactive and updated subscriptions.") except IndexError: - bot.send_message(chat_id, "Invalid format. Use: ") + bot.send_message(chat_id, "Неверный формат. Используйте: ") show_main_menu(chat_id, is_whitelisted(chat_id)) # Handle admin whitelist management commands def prompt_admin_for_whitelist(chat_id, action): if action == 'add': - bot.send_message(chat_id, "Введите ID пользователя, которого хотите добавить в whitelist") + bot.send_message(chat_id, "Введите ID пользователя, которого хотите добавить в белый список") bot.register_next_step_handler_by_chat_id(chat_id, process_add_whitelist) elif action == 'remove': - bot.send_message(chat_id, "Введите ID пользователя, которого хотите удалить из whitelist") + bot.send_message(chat_id, "Введите ID пользователя, которого хотите удалить из белого списка") bot.register_next_step_handler_by_chat_id(chat_id, process_remove_whitelist) def process_add_whitelist(message): @@ -395,10 +437,11 @@ def process_add_whitelist(message): try: new_chat_id = int(message.text.split()[0]) add_to_whitelist(new_chat_id) - bot.send_message(chat_id, f"Chat ID {new_chat_id} added to the whitelist.") + bot.send_message(chat_id, f"Chat ID {new_chat_id} добавлен в белый список.") app.logger.info(f"Admin {chat_id} added {new_chat_id} to the whitelist.") + log_user_event(new_chat_id, "N/A", f"Added to whitelist by {chat_id} (@{message.from_user.username})") except (IndexError, ValueError): - bot.send_message(chat_id, "Invalid format. Use: ") + bot.send_message(chat_id, "Неверный формат. Используйте: ") show_main_menu(chat_id, is_whitelisted(chat_id)) def process_remove_whitelist(message): @@ -406,10 +449,43 @@ def process_remove_whitelist(message): try: remove_chat_id = int(message.text.split()[0]) remove_from_whitelist(remove_chat_id) - bot.send_message(chat_id, f"Chat ID {remove_chat_id} removed from the whitelist.") + bot.send_message(chat_id, f"Chat ID {remove_chat_id} удален из белого списка.") app.logger.info(f"Admin {chat_id} removed {remove_chat_id} from the whitelist.") + log_user_event(remove_chat_id, "N/A", f"Removed from whitelist by {chat_id} (@{message.from_user.username})") except (IndexError, ValueError): - bot.send_message(chat_id, "Invalid format. Use: ") + bot.send_message(chat_id, "Неверный формат. Используйте: ") + show_main_menu(chat_id, is_whitelisted(chat_id)) + +# Handle displaying active subscriptions for a user +def handle_my_subscriptions(message): + chat_id = message.chat.id + if not is_whitelisted(chat_id): + bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") + app.logger.info(f"Unauthorized access attempt by {chat_id}") + return + + user_regions = get_user_subscribed_regions(chat_id) + if not user_regions: + bot.send_message(chat_id, "Вы не подписаны ни на один регион.") + else: + regions_list = format_regions_list(user_regions) + bot.send_message(chat_id, f"Ваши активные подписки:\n{regions_list}") + show_main_menu(chat_id, is_whitelisted(chat_id)) + +# Handle displaying all active regions +def handle_active_regions(message): + chat_id = message.chat.id + if not is_whitelisted(chat_id): + bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") + app.logger.info(f"Unauthorized access attempt by {chat_id}") + return + + regions = get_regions() + if not regions: + bot.send_message(chat_id, "Нет активных регионов.") + else: + regions_list = format_regions_list(regions) + bot.send_message(chat_id, f"Активные регионы:\n{regions_list}") show_main_menu(chat_id, is_whitelisted(chat_id)) @app.route('/webhook', methods=['POST']) @@ -436,21 +512,27 @@ def webhook(): # Fetch chat_ids to send the alert region_id = data.get("region") - query = 'SELECT chat_id, username FROM subscriptions WHERE region_id = ? AND skip = FALSE' + query = 'SELECT chat_id, username FROM subscriptions WHERE region_id = ? AND active = TRUE AND skip = FALSE' app.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) results = cursor.fetchall() - message = format_message(data) - for chat_id, username in results: - try: - app.logger.debug(f"Sending message: {message} to chat_id={chat_id}, username={username}") - bot.send_message(chat_id, message) - app.logger.info(f"Sent alert to {chat_id} ({username}) for region {region_id}") - except telebot.apihelper.ApiTelegramException as e: - app.logger.error(f"Failed to send message to {chat_id} ({username}): {e}") - except Exception as e: - app.logger.error(f"Error sending message to {chat_id} ({username}): {e}") + # Check if the region is active + query = 'SELECT active FROM regions WHERE region_id = ?' + cursor.execute(query, (region_id,)) + region_active = cursor.fetchone()[0] + + if region_active: + message = format_message(data) + for chat_id, username in results: + try: + app.logger.debug(f"Sending message: {message} to chat_id={chat_id}, username={username}") + bot.send_message(chat_id, message) + app.logger.info(f"Sent alert to {chat_id} ({username}) for region {region_id}") + except telebot.apihelper.ApiTelegramException as e: + app.logger.error(f"Failed to send message to {chat_id} ({username}): {e}") + except Exception as e: + app.logger.error(f"Error sending message to {chat_id} ({username}): {e}") conn.commit() conn.close()