From 9a80c2b902a259253fc60aa5a7377e0e4a640d23 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Jun 2024 00:23:34 +0300 Subject: [PATCH 01/10] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D1=81=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D0=B8.=20=D0=92=D1=8B=D1=82=D0=B0=D1=89=D0=B8=D0=BB=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=B8=D0=B7=20=D0=B1=D0=B0?= =?UTF-8?q?=D0=B7=D1=8B=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=20?= =?UTF-8?q?=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db.py | 2 + main.py | 169 ++++++++++++++++++++++--------------------- messages.py | 40 ++++++++++ settings_example.ini | 18 +++-- 4 files changed, 141 insertions(+), 88 deletions(-) create mode 100644 messages.py diff --git a/db.py b/db.py index 62bfc72..9ed2342 100644 --- a/db.py +++ b/db.py @@ -16,6 +16,7 @@ class BotDB: self.conn = sqlite3.connect(db_file, check_same_thread=False) self.cursor = self.conn.cursor() + # TODO: Deprecated, удалить def get_message_from_db(self, type: str, username): """Функция для запроса к базе данных и получения сообщений для бота. В аргументы передаются: type - тип получаемой обратной связи, строковое значение, сохраненное в БД @@ -35,6 +36,7 @@ class BotDB: except sqlite3.Error as error: print(error) + # TODO: Deprecated. Остался только в voice боте, удалить и оттуда def get_error_message_from_db(self, id: int): """Функция для запроса к базе данных и получения сообщений ошибки. В аргументы передаются: id - идентификатор ошибки diff --git a/main.py b/main.py index 08ee2da..bd9488b 100644 --- a/main.py +++ b/main.py @@ -10,12 +10,14 @@ from datetime import datetime import time from telebot import types from telebot.apihelper import ApiTelegramException +import messages +import traceback -#Настройки +# Настройки config_path = os.path.join(sys.path[0], 'settings.ini') config = configparser.ConfigParser() config.read(config_path) -#TELEGRAM +# TELEGRAM BOT_TOKEN = config.get('Telegram', 'BOT_TOKEN') GROUP_FOR_POST = config.get('Telegram', 'group_for_posts') GROUP_FOR_MESSAGE = config.get('Telegram', 'group_for_message') @@ -23,35 +25,34 @@ MAIN_PUBLIC = config.get('Telegram', 'main_public') GROUP_FOR_LOGS = config.get('Telegram', 'group_for_logs') IMPORTANT_LOGS = config.get('Telegram', 'important_logs') PREVIEW_LINK = config.getboolean('Telegram', 'PREVIEW_LINK') -#SETTINGS +# SETTINGS LOGS = config.getboolean('Settings', 'logs') TEST = config.getboolean('Settings', 'test') - -#Инициализируем бота и базку +# Инициализируем бота и базку bot = telebot.TeleBot(BOT_TOKEN, parse_mode=None) BotDB = BotDB('tg-bot-database') + def telegram_bot(): @bot.message_handler(commands=['start']) def send_welcome(message): - #TODO: Здесь переписать через randint - #TODO: Тексты приветствий вынести в отдельный файл + # TODO: Здесь переписать через randint + # TODO: Тексты приветствий вынести в отдельный файл try: name_stick_hello = list(Path('Stick').rglob('Hello_*')) number_stick_hello = random.randint(1, len(name_stick_hello)) random_stick_hello = open(name_stick_hello[number_stick_hello], 'rb') - #logging + # logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) + from_chat_id=message.chat.id, + message_id=message.message_id) bot.send_sticker(message.chat.id, random_stick_hello) sleep(0.3) - except: + except Exception as e: if LOGS: - bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(7)) - + bot.send_message(IMPORTANT_LOGS, f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") try: user_id = message.from_user.id first_name = message.from_user.first_name @@ -59,15 +60,15 @@ def telegram_bot(): is_bot = message.from_user.is_bot username = message.from_user.username language_code = message.from_user.language_code - time_UTC = int(time.time()) - date_added = datetime.fromtimestamp(time_UTC) - date_changed = datetime.fromtimestamp(time_UTC) + time_utc = int(time.time()) + date_added = datetime.fromtimestamp(time_utc) + date_changed = datetime.fromtimestamp(time_utc) markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) item1 = types.KeyboardButton("📢Предложить свой пост") item2 = types.KeyboardButton("📩Связаться с админами") # TODO: Выпилил, удалить - #item3 = types.KeyboardButton("❌Удалить пост") + # item3 = types.KeyboardButton("❌Удалить пост") if BotDB.user_exists(user_id): is_need_sticker = BotDB.get_info_about_stickers(user_id=message.from_user.id) if is_need_sticker == 0: @@ -77,7 +78,8 @@ def telegram_bot(): else: markup.add(item1, item2) else: - BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date_added, date_changed) + BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date_added, + date_changed) is_need_sticker = BotDB.get_info_about_stickers(user_id=message.from_user.id) if is_need_sticker == 0: item5 = types.KeyboardButton("🤪Хочу стикеры") @@ -85,11 +87,12 @@ def telegram_bot(): markup.add(item1, item2, item5) else: markup.add(item1, item2) - hello_message = BotDB.get_message_from_db('start_message', first_name) - bot.send_message(message.chat.id, hello_message, parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) - except: + hello_message = messages.get_message(__get_first_name(message), 'HELLO_MESSAGE') + bot.send_message(message.chat.id, hello_message, parse_mode='html', reply_markup=markup, + disable_web_page_preview=not PREVIEW_LINK) + except Exception as e: if LOGS: - bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(8)) + bot.send_message(IMPORTANT_LOGS, f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") bot.register_next_step_handler(message, go_send_messages) @bot.message_handler(commands=['end_command']) @@ -98,7 +101,7 @@ def telegram_bot(): item1 = types.KeyboardButton("📢Предложить свой пост") item2 = types.KeyboardButton("📩Связаться с админами") # TODO: Скрыл, удалить обработчик - #item3 = types.KeyboardButton("❌Удалить пост") + # item3 = types.KeyboardButton("❌Удалить пост") item5 = types.KeyboardButton("👋🏼Сказать пока!") markup.add(item1, item2, item5) bot.send_message(message.chat.id, @@ -112,17 +115,16 @@ def telegram_bot(): if message.text == '📢Предложить свой пост': try: markup = types.ReplyKeyboardRemove() - first_name = message.from_user.first_name - suggest_news = BotDB.get_message_from_db('suggest_news', first_name) + suggest_news = messages.get_message(__get_first_name(message), 'SUGGEST_NEWS') bot.send_message(message.chat.id, suggest_news, parse_mode='html') sleep(0.3) - first_name = message.from_user.first_name - suggest_news_2 = BotDB.get_message_from_db('suggest_news_2', first_name) - msg = bot.send_message(message.chat.id, suggest_news_2,parse_mode='html', reply_markup=markup) - except: + suggest_news_2 = messages.get_message(__get_first_name(message), 'SUGGEST_NEWS_2') + msg = bot.send_message(message.chat.id, suggest_news_2, parse_mode='html', reply_markup=markup) + except Exception as e: if LOGS: - bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(10)) - #logging + bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + # logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, @@ -130,23 +132,20 @@ def telegram_bot(): bot.register_next_step_handler(msg, resend_message_in_group_for_post) elif message.text == "📩Связаться с админами": - first_name = message.from_user.first_name - connect_with_admin = BotDB.get_message_from_db('connect_with_admin', first_name) + connect_with_admin = messages.get_message(__get_first_name(message), 'CONNECT_WITH_ADMIN') msg = bot.send_message(message.chat.id, connect_with_admin, parse_mode="html") - #logging + # logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, message_id=message.message_id) bot.register_next_step_handler(msg, resend_message_in_group_for_message) - elif message.text == "❌Удалить пост": - #TODO: требует автоматизации. На входе говорим пришли мне пост, на выходе получаем идентификатор поста, удаляем из ТГ. Насчет удаления из ВК надо подумать - first_name = message.from_user.first_name - del_message = BotDB.get_message_from_db('del_message', first_name) + # TODO: требует автоматизации. На входе говорим пришли мне пост, на выходе получаем идентификатор поста, удаляем из ТГ. Насчет удаления из ВК надо подумать + del_message = messages.get_message(__get_first_name(message), 'DEL_MESSAGE') msg = bot.send_message(message.chat.id, del_message, parse_mode="html") - #logging + # logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, @@ -159,22 +158,22 @@ def telegram_bot(): number_stick_bye = random.randint(1, len(name_stick_bye)) random_stick_bye = open(name_stick_bye[number_stick_bye], 'rb') bot.send_sticker(message.chat.id, random_stick_bye) - except ApiTelegramException: + except ApiTelegramException as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(11)) - + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") markup = types.ReplyKeyboardRemove() try: - first_name = message.from_user.first_name - bye_message = BotDB.get_message_from_db('bye_message', first_name) + bye_message = messages.get_message(__get_first_name(message), 'BYE_MESSAGE') bot.send_message(message.chat.id, bye_message, parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) - except: + except Exception as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(6)) + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") if LOGS: - #logging + # logging bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, message_id=message.message_id) @@ -183,7 +182,7 @@ def telegram_bot(): item1 = types.KeyboardButton("📢Предложить свой пост") item2 = types.KeyboardButton("📩Связаться с админами") # TODO: Скрыл кнопку, убрать обработчик позднее - #item3 = types.KeyboardButton("❌Удалить пост") + # item3 = types.KeyboardButton("❌Удалить пост") item5 = types.KeyboardButton("👋🏼Сказать пока!") markup.add(item1, item2, item5) try: @@ -191,20 +190,24 @@ def telegram_bot(): bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, message_id=message.message_id) - bot.send_message(message.chat.id, text='Хорошо, лови, добавить можно отсюда: https://t.me/addstickers/love_biysk', reply_markup=markup) + bot.send_message(message.chat.id, + text='Хорошо, лови, добавить можно отсюда: https://t.me/addstickers/love_biysk', + reply_markup=markup) bot.register_next_step_handler(message, callback=go_send_messages) - except ApiTelegramException: + except ApiTelegramException as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(12)) + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") else: try: - first_name = message.from_user.first_name - user_error = BotDB.get_message_from_db('user_error', first_name) - bot.send_message(message.chat.id, user_error, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK) - except: + user_error = messages.get_message(__get_first_name(message), 'USER_ERROR') + bot.send_message(message.chat.id, user_error, parse_mode='html', + disable_web_page_preview=not PREVIEW_LINK) + except Exception as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(9)) - #logging + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + # logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, @@ -221,7 +224,7 @@ def telegram_bot(): post_text = message.text.lower() if post_text.find('неанон') != -1 or post_text.find('не анон') != -1: bot.send_message( - #TODO: GROUP_FOR_POST + # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, text=f'Пост из ТГ:\n{post_text}\n\nАвтор поста: {message.from_user.first_name} @{message.from_user.username}', reply_markup=markup @@ -240,7 +243,7 @@ def telegram_bot(): text=f'Пост из ТГ:\n{post_text}\n\nАвтор поста: {message.from_user.first_name} @{message.from_user.username}', reply_markup=markup ) - elif message.content_type == 'photo' and message.media_group_id == None: + elif message.content_type == 'photo' and message.media_group_id is None: post_text_for_photo = message.caption.lower() if post_text_for_photo.find('неанон') != -1 or post_text_for_photo.find('не анон') != -1: bot.send_photo( @@ -266,21 +269,20 @@ def telegram_bot(): photo=message.photo[-1].file_id, reply_markup=markup ) - #TODO: Не понятна реализация с альбомами от слова совсем - #elif message.content_type == 'photo' and message.media_group_id != None: + # TODO: Не понятна реализация с альбомами от слова совсем + # elif message.content_type == 'photo' and message.media_group_id != None: # bot.forward_message(chat_id=IMPORTANT_LOGS, from_chat_id=message.chat.id, message_id=message.message_id ) else: pass - except: + except Exception as e: if LOGS: - username = message.from_user.first_name - error_message = str(BotDB.get_error_message_from_db(5)).replace('username', username) - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message) + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - username = message.from_user.first_name - success_send_message = BotDB.get_message_from_db('success_send_message', username) + success_send_message = messages.get_message(__get_first_name(message), 'SUCCESS_SEND_MESSAGE') - bot.send_message(message.chat.id, success_send_message, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK) + bot.send_message(message.chat.id, success_send_message, parse_mode='html', + disable_web_page_preview=not PREVIEW_LINK) after_post(message=message) def resend_message_in_group_for_message(message): @@ -288,27 +290,27 @@ def telegram_bot(): from_chat_id=message.chat.id, message_id=message.message_id ) - username = message.from_user.first_name - question = BotDB.get_message_from_db('question', username) + question = messages.get_message(__get_first_name(message), 'QUESTION') bot.send_message(message.chat.id, question, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK) try: pass - except: + except Exception as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(4)) + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") after_post(message=message) - - #Админка + # Админка @bot.callback_query_handler(func=lambda call: True) def post_for_group(call): if call.data == 'post_post_post' and call.message.content_type == 'text': try: bot.send_message(chat_id=MAIN_PUBLIC, text=call.message.text) bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) - except: + except Exception as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(3)) + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") elif call.data == 'post_post_post' and call.message.content_type == 'photo': try: bot.send_photo( @@ -317,15 +319,20 @@ def telegram_bot(): photo=call.message.photo[-1].file_id, ) bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) - except: + except Exception as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(2)) + bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") elif call.data == 'decline': try: bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) - except: + except Exception as e: if LOGS: - bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(1)) + bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + + def __get_first_name(message): + return message.from_user.first_name if __name__ == '__main__': @@ -336,4 +343,4 @@ if __name__ == '__main__': bot.enable_save_next_step_handlers(delay=2) bot.load_next_step_handlers() except (ConnectionError, Exception): - print("Произошла ошибка, перезапуск бота") \ No newline at end of file + print(f"Произошла ошибка: {str(Exception)}\n\nTraceback:\n{traceback.format_exc()}") diff --git a/messages.py b/messages.py new file mode 100644 index 0000000..26c4824 --- /dev/null +++ b/messages.py @@ -0,0 +1,40 @@ + + +def get_message(username: str, type_message: str): + constants = { + 'HELLO_MESSAGE': "Привет, username!👋🏼&Меня зовут Виби, я бот канала 'Влюбленный Бийск'❤🤖" + "&Я был создан для того, чтобы помочь тебе выложить пост в наш канал и если это необходимо, связаться с админами ✍✉" + "&Так же я могу выдать тебе набор стикеров, где я буду главным героем🦸‍♂" + "&Дать возможность высказаться в нашем стендап режиме🎤&Послушать о чем говорит наш город🎧" + "&Предлагай свой пост мне и я обязательно его опубликую😉" + "&Для продолжения взаимодействия воспользуйся меню внизу твоего дисплея⬇" + "&&P.S. Иногда я зависаю по неизвестным причинам, если от меня нет ответа, введи в чат команду /start, это перезапустит сценарий." + "&&Основная группа в ВК: https://vk.com/love_bsk" + "&Основной канал в ТГ: https://t.me/love_bsk", + 'SUGGEST_NEWS': "username, окей, жду от тебя текст поста🙌🏼" + "&В данный момент я работаю в тестовом режиме, поэтому к посту можно прикрепить не более одного фото и никаких аудио или видео👻" + "&&Обещаю, я научусь их обрабатывать, но позже🤝🤖", + 'SUGGEST_NEWS_2': "Обрати внимание, что я умный и смогу из твоего текста понять команды указанные ниже😉" + "&Если хочешь чтобы пост был опубликован анонимно, напиши в любом месте своего поста слово 'анон'." + "&Если хочешь опубликовать пост не анонимно, то напиши 'не анон', 'неанон' или не пиши ничего." + "&&Я обучен только на команды, указанные мной выше👆" + "&‼Проверь, чтобы указание авторства было выполнено так как я попросил." + "&Пост будет опубликован только в группе ТГ📩", + "CONNECT_WITH_ADMIN": "username, напиши свое обращение или предложение✍️" + "&Мы рассмотрим и ответим тебе в ближайшее время☺️❤️", + "DEL_MESSAGE": "username, напиши свое обращение или предложение✍" + "&Мы рассмотрим и ответим тебе в ближайшее время☺❤", + "BYE_MESSAGE": "Если позднее захочешь предложить еще один пост или обратиться к админам с вопросом, то просто пришли в чат команду 👉 /start" + "&&И тебе пока!👋🏼❤️", + "USER_ERROR": "Увы, я не понимаю тебя😐💔 Выбери один из пунктов в нижнем меню, а затем пиши.", + "QUESTION": "Сообщение успешно отправлено❤️ Ответим, как только сможем😉", + "SUCCESS_SEND_MESSAGE": "Пост успешно отправлен❤️ Ожидай одобрения😊", + "MESSAGE_FOR_STANDUP": "Отлично, ты вошел в режим стендапа 📣" + "&Это свободное пространство, в котором может высказаться каждый житель нашего города, и он будет услышан🙌🏼" + "&Для того чтобы высказаться, нажми кнопку: 'Высказаться' и запиши голосовое сообщение, оно выпадет анонимно кому-то другому🗣" + "&Для того чтобы послушать о чем говорит наш город, нажми кнопку: 'Послушать'👂" + "&Ты можешь анонимно пообщаться, поделиться чем-то важным, обратиться напрямую к жителям🤝 Также можешь выступить перед аудиторией (спеть песню, рассказать стихотворение, шутку)🎤" + "&❗️Но пожалуйста не оскорбляй никого, и будь вежлив." + } + message = constants[type_message] + return message.replace('username', username).replace('&', '\n') diff --git a/settings_example.ini b/settings_example.ini index b088ac8..6a953a6 100644 --- a/settings_example.ini +++ b/settings_example.ini @@ -1,9 +1,13 @@ [Telegram] -bot_token = 5719450198:AAEI6hQgwiIcxMLGvVrPdopWqVlwHqR0QoU +bot_token = 000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA preview_link = false -main_public = @love_biysk -group_for_posts = -793789724 -group_for_message = -736077298 -group_for_logs = -721685792 -important_logs = -625900899 -test_channel = -1001725605158 \ No newline at end of file +main_public = @test +group_for_posts = -00000000 +group_for_message = -00000000 +group_for_logs = -00000000 +important_logs = -00000000 +test_channel = -000000000000 + +[Settings] +logs = true +test = false \ No newline at end of file From 908682d05a964e5d3112c73c93046a1789c975fc Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 1 Jul 2024 20:42:48 +0300 Subject: [PATCH 02/10] add blacklist --- db.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- main.py | 34 ++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/db.py b/db.py index 9ed2342..7445f69 100644 --- a/db.py +++ b/db.py @@ -1,7 +1,10 @@ +import datetime import sqlite3 import configparser import os import sys +import logging +from logging.handlers import RotatingFileHandler config_path = os.path.join(sys.path[0], 'settings.ini') config = configparser.ConfigParser() @@ -9,6 +12,34 @@ config.read(config_path) LOGS = config.getboolean('Settings', 'logs') IMPORTANT_LOGS = config.get('Telegram', 'important_logs') +# Инициализация логгера +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +# Формат записи логов +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(message)s') + +# Получение сегодняшней даты для имени файла +today = datetime.date.today().strftime('%Y-%m-%d') +filename = f'helper_bot_{today}.log' + +# Создание обработчика для файла логов +file_handler = RotatingFileHandler( + filename, + mode='a', + maxBytes=10 * 1024 * 1024, # Максимальный размер файла (10 МБ) + backupCount=3 # Количество резервных файлов +) +file_handler.setFormatter(formatter) + +# Добавление обработчика к логгеру +logger.addHandler(file_handler) + +# Добавление стандартного обработчика +# чтобы сообщения также отображались на консоли +console_handler = logging.StreamHandler() +console_handler.setFormatter(formatter) +logger.addHandler(console_handler) class BotDB: @@ -200,7 +231,45 @@ class BotDB: except sqlite3.Error as error: print(error) + def get_users_blacklist(self): + """Возвращает список пользователей в черном списке""" + try: + result = self.cursor.execute("SELECT user_id, user_name FROM `blacklist`") + fetch_all = result.fetchall() + list_of_users = {} + for i in fetch_all: + list_of_users[i[0]] = i[1] + return list_of_users + except sqlite3.Error as error: + print(error) + + + def get_blacklist_users_by_filters(self): + """Возвращает список пользователей в черном списке по фильтру""" + return None + + def set_user_blacklist(self, user_id, user_name=None, message_for_user=None, date_to_unban=None): + """Добавляет пользователя в черный список""" + try: + result = self.cursor.execute("INSERT INTO 'blacklist' ('user_id', 'user_name'," + " 'message_for_user', 'date_to_unban') VALUES (?, ?, ?, ?)", + (user_id, user_name, message_for_user, date_to_unban,)) + return self.conn.commit() + except sqlite3.Error as error: + print(error) + + def delete_user_blacklist(self, user_id): + """Удаляет пользователя из черного списка""" + try: + #TODO: Функция всегда возвращает true, даже если такого id нет в таблице + self.cursor.execute("DELETE FROM blacklist WHERE user_id = ?", (user_id,)) + self.conn.commit() + logger.info(f"User with ID {user_id} successfull delete.") + return True + except sqlite3.Error as error: + logger.error(f"Error delete user with ID {user_id} from blacklist table: {error}") + return False + def close(self): """Закрываем соединение с БД""" self.conn.close() - diff --git a/main.py b/main.py index bd9488b..d1da16f 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,8 @@ import os import sys from pathlib import Path from time import sleep + +import db from db import BotDB import telebot import random @@ -35,9 +37,39 @@ BotDB = BotDB('tg-bot-database') def telegram_bot(): + # Черный список + + @bot.message_handler(commands=['admin'], user_id=842766148) + def admin_panel(message): + try: + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("Забанить пользователя из списка") + item2 = types.KeyboardButton("Забанить пользователя по ID") + markup.add(item1, item2) + bot.send_message(message.chat.id,"Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) + bot.register_next_step_handler(message, ban_user) + except Exception as e: + bot.register_next_step_handler(message, admin_panel) + + + def ban_user(message): + # проверяем, что ID передан правильно + #TODO: остановился где-то тут, функция не дописана. Хотел сделать админку + бан пользователей + try: + if message.text == "Забанить пользователя из списка": + pass + elif message.text == "Забанить пользователя по ID": + bot.send_message(message.chat.id, "Пришли ID юзера") + BotDB.set_user_blacklist(ban_user_id) + bot.reply_to(message, f"Пользователь {ban_user_id} заблокирован.") + except Exception as e: + bot.reply_to(message, f"Укажи ID пользователя. Ошибка\n\n {e}") + bot.register_next_step_handler(message, ban_user) + + + @bot.message_handler(commands=['start']) def send_welcome(message): - # TODO: Здесь переписать через randint # TODO: Тексты приветствий вынести в отдельный файл try: name_stick_hello = list(Path('Stick').rglob('Hello_*')) From 20d92856b44538b981db0df2af4e10bf2b8acaf3 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Wed, 3 Jul 2024 23:06:10 +0300 Subject: [PATCH 03/10] refactor bot --- db.py | 61 +++++--- main.py | 473 ++++++++++++++++++++++++++++++-------------------------- 2 files changed, 298 insertions(+), 236 deletions(-) diff --git a/db.py b/db.py index 7445f69..1430be4 100644 --- a/db.py +++ b/db.py @@ -41,6 +41,7 @@ console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) logger.addHandler(console_handler) + class BotDB: def __init__(self, db_file): @@ -81,18 +82,18 @@ class BotDB: except sqlite3.Error as error: print(error) - def add_new_user_in_db(self, user_id, first_name, full_name, username, is_bot, language_code, date_added, date_changed): + def add_new_user_in_db(self, user_id, first_name, full_name, username, is_bot, language_code, date_added, + date_changed): """Добавляем юзера в базу""" try: self.cursor.execute("INSERT INTO 'our_users' ('user_id', 'first_name', 'full_name', 'username', 'is_bot', " "'language_code', 'date_added', 'date_changed') VALUES (?, ?, ?, ?, ?, ?, ?, ?)", (user_id, first_name, full_name, - username,is_bot,language_code,date_added,date_changed)) + username, is_bot, language_code, date_added, date_changed)) return self.conn.commit() except sqlite3.Error as error: print(error) - def user_exists(self, user_id): """Проверяем, есть ли юзер в базе""" try: @@ -101,7 +102,6 @@ class BotDB: except sqlite3.Error as error: print(error) - def get_user_id(self, user_id): """Достаем id юзера в базе по его user_id""" try: @@ -110,7 +110,6 @@ class BotDB: except sqlite3.Error as error: print(error) - def get_username(self, user_id): """Достаем id юзера в базе по его user_id""" try: @@ -122,7 +121,7 @@ class BotDB: def get_all_user_id(self): """Достаем все айдишники юзеров из БД и преобразуем их в список""" try: - result = self.cursor.execute("SELECT `user_id` FROM `our_users`",) + result = self.cursor.execute("SELECT `user_id` FROM `our_users`", ) fetch_all = result.fetchall() list_of_users = [] for i in fetch_all: @@ -138,7 +137,6 @@ class BotDB: except sqlite3.Error as error: print(error) - def change_name(self, user_id): #TODO: реализовать функцию изменения имени пользователя по которому к нему обращается бот. ОБновляем поля first_name, date_changed #result = self.cursor.execute("UPDATE 'our_users' SET (?) WHERE user_id = (?)", (new_user_name), ) @@ -147,7 +145,9 @@ class BotDB: def add_audio_record(self, file_name, author_id, date_added, listen_count, file_id): """Добавляет информацию о войсе юзера в БД""" try: - result = self.cursor.execute("INSERT INTO `audio_message_reference` (file_name, author_id, date_added, listen_count, file_id) VALUES (?, ?, ?, ?, ?)", (file_name, author_id, date_added, listen_count, file_id)) + result = self.cursor.execute( + "INSERT INTO `audio_message_reference` (file_name, author_id, date_added, listen_count, file_id) VALUES (?, ?, ?, ?, ?)", + (file_name, author_id, date_added, listen_count, file_id)) return self.conn.commit() except sqlite3.Error as error: print(error) @@ -161,11 +161,11 @@ class BotDB: except sqlite3.Error as error: print(error) - def get_last_user_audio_record(self, user_id): """Получает данные о количестве записей пользователя""" try: - result = self.cursor.execute("SELECT `file_id` FROM `audio_message_reference` WHERE `author_id` = ?", (user_id,)) + result = self.cursor.execute("SELECT `file_id` FROM `audio_message_reference` WHERE `author_id` = ?", + (user_id,)) return bool(len(result.fetchall())) except sqlite3.Error as error: print(error) @@ -173,8 +173,9 @@ class BotDB: def get_id_for_audio_record(self, user_id): """Получает ID аудио сообщения пользователя""" try: - result = self.cursor.execute("SELECT `file_id` FROM `audio_message_reference` WHERE `author_id` = ? ORDER BY date_added DESC LIMIT 1", - (user_id,)) + result = self.cursor.execute( + "SELECT `file_id` FROM `audio_message_reference` WHERE `author_id` = ? ORDER BY date_added DESC LIMIT 1", + (user_id,)) return result.fetchone()[0] except sqlite3.Error as error: print(error) @@ -182,7 +183,9 @@ class BotDB: def get_path_for_audio_record(self, user_id): """Получает данные о названии файла""" try: - result = self.cursor.execute("SELECT `file_name` FROM `audio_message_reference` WHERE `author_id` = ? ORDER BY date_added DESC LIMIT 1", (user_id,)) + result = self.cursor.execute( + "SELECT `file_name` FROM `audio_message_reference` WHERE `author_id` = ? ORDER BY date_added DESC LIMIT 1", + (user_id,)) return result.fetchone()[0] except sqlite3.Error as error: print(error) @@ -195,9 +198,10 @@ class BotDB: FROM audio_message_reference a LEFT JOIN listen_audio_users l ON l.file_name = a.file_name WHERE l.user_id = ? - AND l.file_name IS NOT NULL""" , (user_id,)) + AND l.file_name IS NOT NULL""", (user_id,)) check_sign = query_listen_audio.fetchall() - query_all_audio = self.cursor.execute('SELECT file_name FROM audio_message_reference WHERE author_id <> ?', (user_id,)) + query_all_audio = self.cursor.execute('SELECT file_name FROM audio_message_reference WHERE author_id <> ?', + (user_id,)) sign_all_audio = query_all_audio.fetchall() new_sign1 = list(set(sign_all_audio) - set(check_sign)) new_sign = [] @@ -210,7 +214,9 @@ class BotDB: def mark_listened_audio(self, file_name, user_id): """Отмечает аудио прослушанным для конкретного пользователя.""" try: - result = self.cursor.execute("INSERT INTO `listen_audio_users` (file_name, user_id, is_listen) VALUES (?, ?, ?)", (file_name, user_id, 1)) + result = self.cursor.execute( + "INSERT INTO `listen_audio_users` (file_name, user_id, is_listen) VALUES (?, ?, ?)", + (file_name, user_id, 1)) return self.conn.commit() except sqlite3.Error as error: print(error) @@ -219,7 +225,8 @@ class BotDB: """Получает данные о получении стикеров пользователем""" try: result = self.cursor.execute("SELECT `has_stickers` FROM `our_users` WHERE `user_id` = ?", (user_id,)) - return result.fetchone()[0] + return result.fetchone()[0] == 1 + #return result.fetchone()[0] except sqlite3.Error as error: print(error) @@ -243,7 +250,6 @@ class BotDB: except sqlite3.Error as error: print(error) - def get_blacklist_users_by_filters(self): """Возвращает список пользователей в черном списке по фильтру""" return None @@ -270,6 +276,25 @@ class BotDB: logger.error(f"Error delete user with ID {user_id} from blacklist table: {error}") return False + def add_new_message_in_db(self, message_text, user_id, message_id, date, has_answer): + """Добавляем сообщение юзера в базу""" + try: + + self.cursor.execute( + "INSERT INTO `user_messages` (message_text, user_id, message_id, date, has_answer) VALUES (?, ?, ?, ?, ?)", + (message_text, message_id, user_id, date, has_answer)) + return self.conn.commit() + except sqlite3.Error as error: + print(error) + + def get_user_by_message_id(self, message_id): + """Возвращает идентификатор пользователя по идентификатору сообщения""" + try: + result = self.cursor.execute("SELECT user_id FROM `user_messages` WHERE message_id = ?", (message_id,)) + return result.fetchone()[0] + except sqlite3.Error as error: + print(error) + def close(self): """Закрываем соединение с БД""" self.conn.close() diff --git a/main.py b/main.py index d1da16f..d3a46ee 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,7 @@ import os import sys from pathlib import Path from time import sleep - +from enum import Enum import db from db import BotDB import telebot @@ -32,59 +32,122 @@ LOGS = config.getboolean('Settings', 'logs') TEST = config.getboolean('Settings', 'test') # Инициализируем бота и базку -bot = telebot.TeleBot(BOT_TOKEN, parse_mode=None) BotDB = BotDB('tg-bot-database') -def telegram_bot(): - # Черный список +#TODO: state хранить в базе +#TODO: Перенести обработчик коллбэков - @bot.message_handler(commands=['admin'], user_id=842766148) - def admin_panel(message): - try: +class State(Enum): + START = "START" + SUGGEST = "SUGGEST" + ADMIN = "ADMIN" + CHAT = "CHAT" + PRE_CHAT = "PRE_CHAT" + + +class TelegramHelperBot: + def __init__(self, token): + self.bot = telebot.TeleBot(token) + self.state = State.START + + # Router for user + @self.bot.message_handler(func=lambda message: True, chat_types=['private']) + def handle_message(message): + if self.state == State.START: + if message.text == '/start': + print(f'Внутри функции handle_message // Команда /start // state - {self.state.value}') + self.start_message(message) + elif message.text == '📢Предложить свой пост': + print(f'Внутри функции handle_message // Команда /suggest // state - {self.state.value}') + self.suggest_post(message) + self.state = State.SUGGEST + elif message.text == '🤪Хочу стикеры': + print(f'Внутри функции handle_message // Команда /stickers // state - {self.state.value}') + self.stickers(message) + self.state = State.START + elif message.text == '📩Связаться с админами': + print(f'Внутри функции handle_message // Команда /connect // state - {self.state.value}') + self.connect_with_admin(message) + self.state = State.PRE_CHAT + print(f'В state.START - {self.state.value}') + elif message.text == '👋🏼Сказать пока!': + print(f'Внутри функции handle_message // Команда /end // state - {self.state.value}') + self.end_message(message) + self.state = State.START + elif message.text == 'Выйти из чата': + print(f'Внутри функции handle_message // Команда /end // state - {self.state.value}') + self.end_message(message) + elif message.text == '/admin': + self.state = State.ADMIN + #TODO: Админку сделать! + self.bot.send_message(message.chat.id, + "Ты в админке, Ура! Делай что хочешь") + elif message.text == '/state': + print(f'Внутри функции handle_message // Команда /state // state - {self.state.value}') + self.bot.send_message(message.chat.id, + f'Твой state == {self.state.value}') + else: + self.bot.send_message(message.chat.id, + "Не понимаю где ты находишься. Нажми /state, и я расскажу что ты можешь " + "сделать") + + if self.state == State.SUGGEST: + self.bot.register_next_step_handler(message, self.resend_message_in_group_for_post) + self.state = State.START + elif self.state == State.PRE_CHAT: + self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) + self.state = State.START + + if self.state == State.CHAT: + print(f'В state.CHAT - {self.state.value}') + if message.text == 'Выйти из чата': + self.state = State.START + self.end_message(message) + print(f'Обработчик в CHAT - {self.state.value}') + else: + print(f'Обработчик чата в чате CHAT - {self.state.value}') + self.resend_message_in_group_for_message(message) + + @self.bot.message_handler(func=lambda message: True, chat_types=['group']) + def handle_message(message): + """Функция ответа админа пользователю через закрытый чат""" + self.state = State.CHAT markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("Забанить пользователя из списка") - item2 = types.KeyboardButton("Забанить пользователя по ID") - markup.add(item1, item2) - bot.send_message(message.chat.id,"Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) - bot.register_next_step_handler(message, ban_user) - except Exception as e: - bot.register_next_step_handler(message, admin_panel) + item1 = types.KeyboardButton("Выйти из чата") + markup.add(item1) + message_id = message.reply_to_message.id + message_from_admin = message.text + chat_id = BotDB.get_user_by_message_id(message_id) + self.bot.send_message(chat_id, message_from_admin, reply_markup=markup) + def register_chat_handler(self, message): + self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) - def ban_user(message): - # проверяем, что ID передан правильно - #TODO: остановился где-то тут, функция не дописана. Хотел сделать админку + бан пользователей - try: - if message.text == "Забанить пользователя из списка": - pass - elif message.text == "Забанить пользователя по ID": - bot.send_message(message.chat.id, "Пришли ID юзера") - BotDB.set_user_blacklist(ban_user_id) - bot.reply_to(message, f"Пользователь {ban_user_id} заблокирован.") - except Exception as e: - bot.reply_to(message, f"Укажи ID пользователя. Ошибка\n\n {e}") - bot.register_next_step_handler(message, ban_user) + def start(self): + while True: + try: + self.bot.polling(none_stop=True) + except (ConnectionError, Exception): + print(f"Произошла ошибка: {str(Exception)}\n\nTraceback:\n{traceback.format_exc()}") - - - @bot.message_handler(commands=['start']) - def send_welcome(message): - # TODO: Тексты приветствий вынести в отдельный файл + def start_message(self, message): try: name_stick_hello = list(Path('Stick').rglob('Hello_*')) - number_stick_hello = random.randint(1, len(name_stick_hello)) - random_stick_hello = open(name_stick_hello[number_stick_hello], 'rb') + random_stick_hello = open(random.choice(name_stick_hello), 'rb') # logging if LOGS: - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - bot.send_sticker(message.chat.id, random_stick_hello) + self.bot.forward_message(chat_id=GROUP_FOR_LOGS, + from_chat_id=message.chat.id, + message_id=message.message_id) + self.bot.send_sticker(message.chat.id, random_stick_hello) sleep(0.3) except Exception as e: + print(f'{str(e)}') if LOGS: - bot.send_message(IMPORTANT_LOGS, f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + self.bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + try: user_id = message.from_user.id first_name = message.from_user.first_name @@ -92,161 +155,103 @@ def telegram_bot(): is_bot = message.from_user.is_bot username = message.from_user.username language_code = message.from_user.language_code - time_utc = int(time.time()) - date_added = datetime.fromtimestamp(time_utc) - date_changed = datetime.fromtimestamp(time_utc) + date_added = datetime.now() + date_changed = date_added - markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("📢Предложить свой пост") - item2 = types.KeyboardButton("📩Связаться с админами") - # TODO: Выпилил, удалить - # item3 = types.KeyboardButton("❌Удалить пост") - if BotDB.user_exists(user_id): - is_need_sticker = BotDB.get_info_about_stickers(user_id=message.from_user.id) - if is_need_sticker == 0: - item5 = types.KeyboardButton("🤪Хочу стикеры") - BotDB.update_info_about_stickers(user_id=message.from_user.id) - markup.add(item1, item2, item5) - else: - markup.add(item1, item2) - else: + if not BotDB.user_exists(user_id): BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date_added, date_changed) - is_need_sticker = BotDB.get_info_about_stickers(user_id=message.from_user.id) - if is_need_sticker == 0: - item5 = types.KeyboardButton("🤪Хочу стикеры") - BotDB.update_info_about_stickers(user_id=message.from_user.id) - markup.add(item1, item2, item5) - else: - markup.add(item1, item2) - hello_message = messages.get_message(__get_first_name(message), 'HELLO_MESSAGE') - bot.send_message(message.chat.id, hello_message, parse_mode='html', reply_markup=markup, - disable_web_page_preview=not PREVIEW_LINK) + markup = self.get_reply_keyboard(message) + hello_message = messages.get_message(self.__get_first_name(message), 'HELLO_MESSAGE') + self.bot.send_message(message.chat.id, hello_message, parse_mode='html', reply_markup=markup, + disable_web_page_preview=not PREVIEW_LINK) + except Exception as e: + print(f'{str(e)}') + if LOGS: + self.bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + + #TODO: При отправке более одного сообщения, не пересылает сообщение в чат, БАГ!!!! + def resend_message_in_group_for_message(self, message): + self.bot.forward_message(chat_id=GROUP_FOR_MESSAGE, + from_chat_id=message.chat.id, + message_id=message.message_id + ) + print(f'Кладу в базу: {message.message_id}') + BotDB.add_new_message_in_db(message.text, message.message_id + 1, message.from_user.id, datetime.now(), 0) + question = messages.get_message(self.__get_first_name(message), 'QUESTION') + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("Выйти из чата") + markup.add(item1) + self.bot.send_message(message.chat.id, question, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK, + reply_markup=markup) + + def suggest_post(self, message): + try: + markup = types.ReplyKeyboardRemove() + suggest_news = messages.get_message(self.__get_first_name(message), 'SUGGEST_NEWS') + self.bot.send_message(message.chat.id, suggest_news, parse_mode='html') + sleep(0.3) + suggest_news_2 = messages.get_message(self.__get_first_name(message), 'SUGGEST_NEWS_2') + self.bot.send_message(message.chat.id, suggest_news_2, parse_mode='html', reply_markup=markup) except Exception as e: if LOGS: - bot.send_message(IMPORTANT_LOGS, f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - bot.register_next_step_handler(message, go_send_messages) - - @bot.message_handler(commands=['end_command']) - def after_post(message): - markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("📢Предложить свой пост") - item2 = types.KeyboardButton("📩Связаться с админами") - # TODO: Скрыл, удалить обработчик - # item3 = types.KeyboardButton("❌Удалить пост") - item5 = types.KeyboardButton("👋🏼Сказать пока!") - markup.add(item1, item2, item5) - bot.send_message(message.chat.id, - "Выбери нужную кнопку внизу экрана".format( - message.from_user, bot.get_me()), - parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) - bot.register_next_step_handler(message, go_send_messages) - - def go_send_messages(message): - global msg - if message.text == '📢Предложить свой пост': - try: - markup = types.ReplyKeyboardRemove() - suggest_news = messages.get_message(__get_first_name(message), 'SUGGEST_NEWS') - bot.send_message(message.chat.id, suggest_news, parse_mode='html') - sleep(0.3) - suggest_news_2 = messages.get_message(__get_first_name(message), 'SUGGEST_NEWS_2') - msg = bot.send_message(message.chat.id, suggest_news_2, parse_mode='html', reply_markup=markup) - except Exception as e: - if LOGS: - bot.send_message(IMPORTANT_LOGS, - f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - # logging - if LOGS: - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - bot.register_next_step_handler(msg, resend_message_in_group_for_post) - - elif message.text == "📩Связаться с админами": - connect_with_admin = messages.get_message(__get_first_name(message), 'CONNECT_WITH_ADMIN') - msg = bot.send_message(message.chat.id, connect_with_admin, parse_mode="html") + self.bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") # logging - if LOGS: - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - bot.register_next_step_handler(msg, resend_message_in_group_for_message) + if LOGS: + self.bot.forward_message(chat_id=GROUP_FOR_LOGS, + from_chat_id=message.chat.id, + message_id=message.message_id) - elif message.text == "❌Удалить пост": - # TODO: требует автоматизации. На входе говорим пришли мне пост, на выходе получаем идентификатор поста, удаляем из ТГ. Насчет удаления из ВК надо подумать - del_message = messages.get_message(__get_first_name(message), 'DEL_MESSAGE') - msg = bot.send_message(message.chat.id, del_message, parse_mode="html") + def stickers(self, message): + BotDB.update_info_about_stickers(user_id=message.from_user.id) + markup = self.get_reply_keyboard(message) + try: + self.bot.forward_message(chat_id=GROUP_FOR_LOGS, + from_chat_id=message.chat.id, + message_id=message.message_id) + self.bot.send_message(message.chat.id, + text='Хорошо, лови, добавить можно отсюда: https://t.me/addstickers/love_biysk', + reply_markup=markup) + except ApiTelegramException as e: + self.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + + def connect_with_admin(self, message): + connect_with_admin = messages.get_message(self.__get_first_name(message), 'CONNECT_WITH_ADMIN') + self.bot.send_message(message.chat.id, connect_with_admin, parse_mode="html") + # logging + if LOGS: + self.bot.forward_message(chat_id=GROUP_FOR_LOGS, + from_chat_id=message.chat.id, + message_id=message.message_id) + + def end_message(self, message): + try: + name_stick_bye = list(Path('Stick').rglob('Universal_*')) + random_stick_bye = open(random.choice(name_stick_bye), 'rb') + self.bot.send_sticker(message.chat.id, random_stick_bye) + except ApiTelegramException as e: + if LOGS: + self.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + markup = types.ReplyKeyboardRemove() + try: + bye_message = messages.get_message(self.__get_first_name(message), 'BYE_MESSAGE') + self.bot.send_message(message.chat.id, bye_message, + parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) + except Exception as e: + if LOGS: + self.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + if LOGS: # logging - if LOGS: - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - bot.register_next_step_handler(msg, resend_message_in_group_for_message) + self.bot.forward_message(chat_id=GROUP_FOR_LOGS, + from_chat_id=message.chat.id, + message_id=message.message_id) - elif message.text == "👋🏼Сказать пока!": - try: - name_stick_bye = list(Path('Stick').rglob('Universal_*')) - number_stick_bye = random.randint(1, len(name_stick_bye)) - random_stick_bye = open(name_stick_bye[number_stick_bye], 'rb') - bot.send_sticker(message.chat.id, random_stick_bye) - except ApiTelegramException as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - markup = types.ReplyKeyboardRemove() - try: - bye_message = messages.get_message(__get_first_name(message), 'BYE_MESSAGE') - bot.send_message(message.chat.id, bye_message, - parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) - except Exception as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - - if LOGS: - # logging - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - elif message.text == "🤪Хочу стикеры": - markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("📢Предложить свой пост") - item2 = types.KeyboardButton("📩Связаться с админами") - # TODO: Скрыл кнопку, убрать обработчик позднее - # item3 = types.KeyboardButton("❌Удалить пост") - item5 = types.KeyboardButton("👋🏼Сказать пока!") - markup.add(item1, item2, item5) - try: - if LOGS: - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - bot.send_message(message.chat.id, - text='Хорошо, лови, добавить можно отсюда: https://t.me/addstickers/love_biysk', - reply_markup=markup) - bot.register_next_step_handler(message, callback=go_send_messages) - except ApiTelegramException as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - else: - try: - user_error = messages.get_message(__get_first_name(message), 'USER_ERROR') - bot.send_message(message.chat.id, user_error, parse_mode='html', - disable_web_page_preview=not PREVIEW_LINK) - except Exception as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - # logging - if LOGS: - bot.forward_message(chat_id=GROUP_FOR_LOGS, - from_chat_id=message.chat.id, - message_id=message.message_id) - bot.register_next_step_handler(message, callback=go_send_messages) - - def resend_message_in_group_for_post(message): + def resend_message_in_group_for_post(self, message): markup = types.InlineKeyboardMarkup(row_width=1) item1 = types.InlineKeyboardButton("Опубликовать", callback_data='post_post_post') item2 = types.InlineKeyboardButton("Отклонить", callback_data='decline') @@ -255,21 +260,21 @@ def telegram_bot(): if message.content_type == 'text': post_text = message.text.lower() if post_text.find('неанон') != -1 or post_text.find('не анон') != -1: - bot.send_message( + self.bot.send_message( # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, text=f'Пост из ТГ:\n{post_text}\n\nАвтор поста: {message.from_user.first_name} @{message.from_user.username}', reply_markup=markup ) elif post_text.find('анон') != -1: - bot.send_message( + self.bot.send_message( # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, text=f'Пост из ТГ:\n{message.text}\n\nПост опубликован анонимно', reply_markup=markup ) else: - bot.send_message( + self.bot.send_message( # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, text=f'Пост из ТГ:\n{post_text}\n\nАвтор поста: {message.from_user.first_name} @{message.from_user.username}', @@ -278,7 +283,7 @@ def telegram_bot(): elif message.content_type == 'photo' and message.media_group_id is None: post_text_for_photo = message.caption.lower() if post_text_for_photo.find('неанон') != -1 or post_text_for_photo.find('не анон') != -1: - bot.send_photo( + self.bot.send_photo( # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, caption=f'Пост из ТГ:\n{post_text_for_photo}\n\nАвтор поста: {message.from_user.first_name} @{message.from_user.username}', @@ -286,7 +291,7 @@ def telegram_bot(): reply_markup=markup ) elif post_text_for_photo.find('анон') != -1 or post_text_for_photo.find('анон') != -1: - bot.send_photo( + self.bot.send_photo( # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, caption=f'Пост из ТГ:\n{post_text_for_photo}\n\nПост опубликован анонимно', @@ -294,7 +299,7 @@ def telegram_bot(): reply_markup=markup ) else: - bot.send_photo( + self.bot.send_photo( # TODO: GROUP_FOR_POST chat_id=GROUP_FOR_POST, caption=f'Пост из ТГ:\n{post_text_for_photo}\n\nАвтор поста: {message.from_user.first_name} @{message.from_user.username}', @@ -308,29 +313,67 @@ def telegram_bot(): pass except Exception as e: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + self.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + markup_for_user = self.get_reply_keyboard(message) + success_send_message = messages.get_message(self.__get_first_name(message), 'SUCCESS_SEND_MESSAGE') + self.bot.send_message(message.chat.id, success_send_message, parse_mode='html', + disable_web_page_preview=not PREVIEW_LINK, reply_markup=markup_for_user) - success_send_message = messages.get_message(__get_first_name(message), 'SUCCESS_SEND_MESSAGE') + @staticmethod + def get_reply_keyboard(message): + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("📢Предложить свой пост") + item2 = types.KeyboardButton("📩Связаться с админами") + item3 = types.KeyboardButton("👋🏼Сказать пока!") + #TODO: Есть ощущение что не совсем так работает как надо + item4 = types.KeyboardButton("🤪Хочу стикеры") if not BotDB.get_info_about_stickers( + user_id=message.from_user.id) else None - bot.send_message(message.chat.id, success_send_message, parse_mode='html', - disable_web_page_preview=not PREVIEW_LINK) - after_post(message=message) + if item4: + markup.add(item1, item2, item3, item4) + else: + markup.add(item1, item2, item3) - def resend_message_in_group_for_message(message): - bot.forward_message(chat_id=GROUP_FOR_MESSAGE, - from_chat_id=message.chat.id, - message_id=message.message_id - ) - question = messages.get_message(__get_first_name(message), 'QUESTION') - bot.send_message(message.chat.id, question, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK) + return markup + + @staticmethod + def __get_first_name(message): + return message.from_user.first_name + + +bot = TelegramHelperBot(BOT_TOKEN) + + +def telegram_bot(): + # Черный список + + @bot.message_handler(commands=['admin'], user_id=842766148) + def admin_panel(message): try: - pass + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("Забанить пользователя из списка") + item2 = types.KeyboardButton("Забанить пользователя по ID") + markup.add(item1, item2) + bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) + bot.register_next_step_handler(message, ban_user) except Exception as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - after_post(message=message) + bot.register_next_step_handler(message, admin_panel) + + def ban_user(message): + # проверяем, что ID передан правильно + #TODO: остановился где-то тут, функция не дописана. Хотел сделать админку + бан пользователей + try: + if message.text == "Забанить пользователя из списка": + pass + elif message.text == "Забанить пользователя по ID": + bot.send_message(message.chat.id, "Пришли ID юзера") + #BotDB.set_user_blacklist(ban_user_id) + #bot.reply_to(message, f"Пользователь {ban_user_id} заблокирован.") + except Exception as e: + bot.reply_to(message, f"Укажи ID пользователя. Ошибка\n\n {e}") + bot.register_next_step_handler(message, ban_user) + # Админка @bot.callback_query_handler(func=lambda call: True) @@ -367,12 +410,6 @@ def telegram_bot(): return message.from_user.first_name -if __name__ == '__main__': - telegram_bot() - while True: - try: - bot.polling(none_stop=True) - bot.enable_save_next_step_handlers(delay=2) - bot.load_next_step_handlers() - except (ConnectionError, Exception): - print(f"Произошла ошибка: {str(Exception)}\n\nTraceback:\n{traceback.format_exc()}") +if __name__ == "__main__": + # Запускаем бота + bot.start() \ No newline at end of file From fb70c9b1dbec77d30ed931019ddd97a470e96bf1 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Thu, 4 Jul 2024 00:53:41 +0300 Subject: [PATCH 04/10] some refactoring, add all function from old bot --- db.py | 7 +++ main.py | 140 +++++++++++++++++++++++++++----------------------------- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/db.py b/db.py index 1430be4..0b9f437 100644 --- a/db.py +++ b/db.py @@ -287,6 +287,13 @@ class BotDB: except sqlite3.Error as error: print(error) + def update_date_for_user(self, date, user_id: int): + try: + result = self.cursor.execute("UPDATE `our_users` SET `date_changed` = ? WHERE `user_id` = ?", (date, user_id,)) + return self.conn.commit() + except sqlite3.Error as error: + print(error) + def get_user_by_message_id(self, message_id): """Возвращает идентификатор пользователя по идентификатору сообщения""" try: diff --git a/main.py b/main.py index d3a46ee..83c5902 100644 --- a/main.py +++ b/main.py @@ -83,6 +83,7 @@ class TelegramHelperBot: #TODO: Админку сделать! self.bot.send_message(message.chat.id, "Ты в админке, Ура! Делай что хочешь") + self.admin_panel(message) elif message.text == '/state': print(f'Внутри функции handle_message // Команда /state // state - {self.state.value}') self.bot.send_message(message.chat.id, @@ -121,6 +122,37 @@ class TelegramHelperBot: chat_id = BotDB.get_user_by_message_id(message_id) self.bot.send_message(chat_id, message_from_admin, reply_markup=markup) + # Админка + @self.bot.callback_query_handler(func=lambda call: True) + def post_for_group(call): + if call.data == 'publish' and call.message.content_type == 'text': + try: + self.bot.send_message(chat_id=MAIN_PUBLIC, text=call.message.text) + self.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) + except Exception as e: + if LOGS: + self.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + elif call.data == 'publish' and call.message.content_type == 'photo': + try: + self.bot.send_photo( + chat_id=MAIN_PUBLIC, + caption=call.message.caption, + photo=call.message.photo[-1].file_id, + ) + self.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) + except Exception as e: + if LOGS: + self.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + elif call.data == 'decline': + try: + self.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) + except Exception as e: + if LOGS: + self.bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + def register_chat_handler(self, message): self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) @@ -131,6 +163,33 @@ class TelegramHelperBot: except (ConnectionError, Exception): print(f"Произошла ошибка: {str(Exception)}\n\nTraceback:\n{traceback.format_exc()}") + # Черный список + def admin_panel(self, message): + try: + #Добавить админа: 842766148 + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("Забанить пользователя из списка") + item2 = types.KeyboardButton("Забанить пользователя по ID") + markup.add(item1, item2) + self.bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) + self.bot.register_next_step_handler(message, self.ban_user) + except Exception as e: + self.bot.register_next_step_handler(message, self.admin_panel) + + def ban_user(self, message): + # проверяем, что ID передан правильно + #TODO: остановился где-то тут, функция не дописана. Хотел сделать админку + бан пользователей + try: + if message.text == "Забанить пользователя из списка": + pass + elif message.text == "Забанить пользователя по ID": + self.bot.send_message(message.chat.id, "Пришли ID юзера") + #BotDB.set_user_blacklist(ban_user_id) + #bot.reply_to(message, f"Пользователь {ban_user_id} заблокирован.") + except Exception as e: + self.bot.reply_to(message, f"Укажи ID пользователя. Ошибка\n\n {e}") + self.bot.register_next_step_handler(message, self.ban_user) + def start_message(self, message): try: name_stick_hello = list(Path('Stick').rglob('Hello_*')) @@ -155,12 +214,12 @@ class TelegramHelperBot: is_bot = message.from_user.is_bot username = message.from_user.username language_code = message.from_user.language_code - date_added = datetime.now() - date_changed = date_added - + current_date = datetime.now() + date = current_date.strftime("%Y-%m-%d %H:%M:%S") if not BotDB.user_exists(user_id): - BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date_added, - date_changed) + BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date, + date) + BotDB.update_date_for_user(date, user_id) markup = self.get_reply_keyboard(message) hello_message = messages.get_message(self.__get_first_name(message), 'HELLO_MESSAGE') self.bot.send_message(message.chat.id, hello_message, parse_mode='html', reply_markup=markup, @@ -177,8 +236,9 @@ class TelegramHelperBot: from_chat_id=message.chat.id, message_id=message.message_id ) - print(f'Кладу в базу: {message.message_id}') - BotDB.add_new_message_in_db(message.text, message.message_id + 1, message.from_user.id, datetime.now(), 0) + current_date = datetime.now() + date = current_date.strftime("%Y-%m-%d %H:%M:%S") + BotDB.add_new_message_in_db(message.text, message.message_id + 1, message.from_user.id, date, 0) question = messages.get_message(self.__get_first_name(message), 'QUESTION') markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) item1 = types.KeyboardButton("Выйти из чата") @@ -253,7 +313,7 @@ class TelegramHelperBot: def resend_message_in_group_for_post(self, message): markup = types.InlineKeyboardMarkup(row_width=1) - item1 = types.InlineKeyboardButton("Опубликовать", callback_data='post_post_post') + item1 = types.InlineKeyboardButton("Опубликовать", callback_data='publish') item2 = types.InlineKeyboardButton("Отклонить", callback_data='decline') markup.add(item1, item2) try: @@ -345,70 +405,6 @@ class TelegramHelperBot: bot = TelegramHelperBot(BOT_TOKEN) -def telegram_bot(): - # Черный список - - @bot.message_handler(commands=['admin'], user_id=842766148) - def admin_panel(message): - try: - markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("Забанить пользователя из списка") - item2 = types.KeyboardButton("Забанить пользователя по ID") - markup.add(item1, item2) - bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) - bot.register_next_step_handler(message, ban_user) - except Exception as e: - bot.register_next_step_handler(message, admin_panel) - - def ban_user(message): - # проверяем, что ID передан правильно - #TODO: остановился где-то тут, функция не дописана. Хотел сделать админку + бан пользователей - try: - if message.text == "Забанить пользователя из списка": - pass - elif message.text == "Забанить пользователя по ID": - bot.send_message(message.chat.id, "Пришли ID юзера") - #BotDB.set_user_blacklist(ban_user_id) - #bot.reply_to(message, f"Пользователь {ban_user_id} заблокирован.") - except Exception as e: - bot.reply_to(message, f"Укажи ID пользователя. Ошибка\n\n {e}") - bot.register_next_step_handler(message, ban_user) - - - # Админка - @bot.callback_query_handler(func=lambda call: True) - def post_for_group(call): - if call.data == 'post_post_post' and call.message.content_type == 'text': - try: - bot.send_message(chat_id=MAIN_PUBLIC, text=call.message.text) - bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) - except Exception as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - elif call.data == 'post_post_post' and call.message.content_type == 'photo': - try: - bot.send_photo( - chat_id=MAIN_PUBLIC, - caption=call.message.caption, - photo=call.message.photo[-1].file_id, - ) - bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) - except Exception as e: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - elif call.data == 'decline': - try: - bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) - except Exception as e: - if LOGS: - bot.send_message(IMPORTANT_LOGS, - f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - - def __get_first_name(message): - return message.from_user.first_name - if __name__ == "__main__": # Запускаем бота From 1aed0c0c4ff4cc09427020c4b9a3ef6caaea94a6 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Thu, 4 Jul 2024 21:54:06 +0300 Subject: [PATCH 05/10] blacklist --- db.py | 93 ++++++++++++++++++++------------- main.py | 158 ++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 175 insertions(+), 76 deletions(-) diff --git a/db.py b/db.py index 0b9f437..efd2395 100644 --- a/db.py +++ b/db.py @@ -1,10 +1,8 @@ -import datetime import sqlite3 import configparser import os import sys -import logging -from logging.handlers import RotatingFileHandler +import custom_logger config_path = os.path.join(sys.path[0], 'settings.ini') config = configparser.ConfigParser() @@ -12,34 +10,7 @@ config.read(config_path) LOGS = config.getboolean('Settings', 'logs') IMPORTANT_LOGS = config.get('Telegram', 'important_logs') -# Инициализация логгера -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - -# Формат записи логов -formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(message)s') - -# Получение сегодняшней даты для имени файла -today = datetime.date.today().strftime('%Y-%m-%d') -filename = f'helper_bot_{today}.log' - -# Создание обработчика для файла логов -file_handler = RotatingFileHandler( - filename, - mode='a', - maxBytes=10 * 1024 * 1024, # Максимальный размер файла (10 МБ) - backupCount=3 # Количество резервных файлов -) -file_handler.setFormatter(formatter) - -# Добавление обработчика к логгеру -logger.addHandler(file_handler) - -# Добавление стандартного обработчика -# чтобы сообщения также отображались на консоли -console_handler = logging.StreamHandler() -console_handler.setFormatter(formatter) -logger.addHandler(console_handler) +db_logger = custom_logger.Logger('database') class BotDB: @@ -254,6 +225,12 @@ class BotDB: """Возвращает список пользователей в черном списке по фильтру""" return None + def check_user_in_blacklist(self, user_id): + """Проверяет, существует ли запись с данным user_id в blacklist.""" + self.cursor.execute("SELECT 1 FROM blacklist WHERE user_id = ?", (user_id,)) + result = self.cursor.fetchone() + return bool(result) + def set_user_blacklist(self, user_id, user_name=None, message_for_user=None, date_to_unban=None): """Добавляет пользователя в черный список""" try: @@ -262,7 +239,7 @@ class BotDB: (user_id, user_name, message_for_user, date_to_unban,)) return self.conn.commit() except sqlite3.Error as error: - print(error) + return error def delete_user_blacklist(self, user_id): """Удаляет пользователя из черного списка""" @@ -270,10 +247,10 @@ class BotDB: #TODO: Функция всегда возвращает true, даже если такого id нет в таблице self.cursor.execute("DELETE FROM blacklist WHERE user_id = ?", (user_id,)) self.conn.commit() - logger.info(f"User with ID {user_id} successfull delete.") + db_logger.info(f"User with ID {user_id} successfull delete.") return True except sqlite3.Error as error: - logger.error(f"Error delete user with ID {user_id} from blacklist table: {error}") + db_logger.error(f"Error delete user with ID {user_id} from blacklist table: {str(error)}") return False def add_new_message_in_db(self, message_text, user_id, message_id, date, has_answer): @@ -281,7 +258,8 @@ class BotDB: try: self.cursor.execute( - "INSERT INTO `user_messages` (message_text, user_id, message_id, date, has_answer) VALUES (?, ?, ?, ?, ?)", + "INSERT INTO `user_messages` (message_text, user_id, message_id, date, has_answer) " + "VALUES (?, ?, ?, ?, ?)", (message_text, message_id, user_id, date, has_answer)) return self.conn.commit() except sqlite3.Error as error: @@ -289,11 +267,44 @@ class BotDB: def update_date_for_user(self, date, user_id: int): try: - result = self.cursor.execute("UPDATE `our_users` SET `date_changed` = ? WHERE `user_id` = ?", (date, user_id,)) + result = self.cursor.execute("UPDATE `our_users` SET `date_changed` = ? WHERE `user_id` = ?", + (date, user_id,)) return self.conn.commit() except sqlite3.Error as error: print(error) + def is_admin(self, user_id): + """ + Проверяет, является ли пользователь администратором. + Args: + user_id: ID пользователя Telegram. + Returns: + True, если пользователь администратор, иначе False. + """ + self.cursor.execute("SELECT 1 FROM admins WHERE user_id = ?", (user_id,)) + result = self.cursor.fetchone() + return bool(result) + + def add_admin(self, user_id, username=None): + """ + Добавляет пользователя в список администраторов. + Args: + user_id: ID пользователя Telegram. + username: Username пользователя (необязательно). + """ + self.cursor.execute("INSERT INTO admins (user_id, username) VALUES (?, ?)", (user_id, username)) + return self.conn.commit() + + def remove_admin(self, user_id): + """ + Удаляет пользователя из списка администраторов. + + Args: + user_id: ID пользователя Telegram. + """ + self.cursor.execute("DELETE FROM admins WHERE user_id = ?", (user_id,)) + return self.conn.commit() + def get_user_by_message_id(self, message_id): """Возвращает идентификатор пользователя по идентификатору сообщения""" try: @@ -302,6 +313,16 @@ class BotDB: except sqlite3.Error as error: print(error) + def get_last_users_from_bot(self): + """Возвращает список идентификаторов последних 10 пользователей обращавшихся в бот""" + try: + result = self.cursor.execute("SELECT full_name, user_id FROM our_users ORDER BY date_changed DESC LIMIT 10") + users = result.fetchall() + user_dict = {user[1]: user[0] for user in users} + return user_dict + except sqlite3.Error as error: + print(error) + def close(self): """Закрываем соединение с БД""" self.conn.close() diff --git a/main.py b/main.py index 83c5902..9f16088 100644 --- a/main.py +++ b/main.py @@ -8,7 +8,7 @@ import db from db import BotDB import telebot import random -from datetime import datetime +from datetime import datetime, timedelta import time from telebot import types from telebot.apihelper import ApiTelegramException @@ -56,36 +56,29 @@ class TelegramHelperBot: def handle_message(message): if self.state == State.START: if message.text == '/start': - print(f'Внутри функции handle_message // Команда /start // state - {self.state.value}') self.start_message(message) elif message.text == '📢Предложить свой пост': - print(f'Внутри функции handle_message // Команда /suggest // state - {self.state.value}') self.suggest_post(message) self.state = State.SUGGEST elif message.text == '🤪Хочу стикеры': - print(f'Внутри функции handle_message // Команда /stickers // state - {self.state.value}') self.stickers(message) self.state = State.START elif message.text == '📩Связаться с админами': - print(f'Внутри функции handle_message // Команда /connect // state - {self.state.value}') self.connect_with_admin(message) self.state = State.PRE_CHAT - print(f'В state.START - {self.state.value}') elif message.text == '👋🏼Сказать пока!': - print(f'Внутри функции handle_message // Команда /end // state - {self.state.value}') self.end_message(message) self.state = State.START elif message.text == 'Выйти из чата': - print(f'Внутри функции handle_message // Команда /end // state - {self.state.value}') self.end_message(message) elif message.text == '/admin': - self.state = State.ADMIN - #TODO: Админку сделать! - self.bot.send_message(message.chat.id, - "Ты в админке, Ура! Делай что хочешь") - self.admin_panel(message) + access = self.check_access(message.from_user.id) + if access: + self.admin_panel(message) + self.state = State.ADMIN + else: + self.bot.send_message(message.chat.id, 'Доступ запрещен, досвидания!') elif message.text == '/state': - print(f'Внутри функции handle_message // Команда /state // state - {self.state.value}') self.bot.send_message(message.chat.id, f'Твой state == {self.state.value}') else: @@ -101,15 +94,20 @@ class TelegramHelperBot: self.state = State.START if self.state == State.CHAT: - print(f'В state.CHAT - {self.state.value}') if message.text == 'Выйти из чата': self.state = State.START self.end_message(message) - print(f'Обработчик в CHAT - {self.state.value}') else: - print(f'Обработчик чата в чате CHAT - {self.state.value}') self.resend_message_in_group_for_message(message) + if self.state == State.ADMIN: + if message == '/admin' or message == '/restart': + access = self.check_access(message.from_user.id) + if access: + self.admin_panel(message) + else: + self.bot.send_message(message.chat.id, 'Доступ запрещен, досвидания!') + @self.bot.message_handler(func=lambda message: True, chat_types=['group']) def handle_message(message): """Функция ответа админа пользователю через закрытый чат""" @@ -132,7 +130,7 @@ class TelegramHelperBot: except Exception as e: if LOGS: self.bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") elif call.data == 'publish' and call.message.content_type == 'photo': try: self.bot.send_photo( @@ -144,14 +142,17 @@ class TelegramHelperBot: except Exception as e: if LOGS: self.bot.send_message(chat_id=IMPORTANT_LOGS, - text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + text=f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") elif call.data == 'decline': try: self.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) except Exception as e: if LOGS: self.bot.send_message(IMPORTANT_LOGS, - f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + elif call.data[:3] == 'ban': + user_id = call.data[4:] + self.ban_user(call.message, user_id) def register_chat_handler(self, message): self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) @@ -166,29 +167,96 @@ class TelegramHelperBot: # Черный список def admin_panel(self, message): try: - #Добавить админа: 842766148 markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("Забанить пользователя из списка") - item2 = types.KeyboardButton("Забанить пользователя по ID") - markup.add(item1, item2) - self.bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) - self.bot.register_next_step_handler(message, self.ban_user) + item1 = types.KeyboardButton("Бан (Список)") + item2 = types.KeyboardButton("Добавить админа") + item3 = types.KeyboardButton("Удалить админа") + markup.add(item1, item2, item3) + self.bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", + reply_markup=markup) + self.bot.register_next_step_handler(message, self.handle_admin_message) except Exception as e: self.bot.register_next_step_handler(message, self.admin_panel) - def ban_user(self, message): - # проверяем, что ID передан правильно - #TODO: остановился где-то тут, функция не дописана. Хотел сделать админку + бан пользователей + def handle_admin_message(self, message): try: if message.text == "Забанить пользователя из списка": - pass - elif message.text == "Забанить пользователя по ID": - self.bot.send_message(message.chat.id, "Пришли ID юзера") - #BotDB.set_user_blacklist(ban_user_id) - #bot.reply_to(message, f"Пользователь {ban_user_id} заблокирован.") + self.get_last_users(message) except Exception as e: - self.bot.reply_to(message, f"Укажи ID пользователя. Ошибка\n\n {e}") - self.bot.register_next_step_handler(message, self.ban_user) + self.bot.reply_to(message, f"Ошибка\n\n {e}") + self.admin_panel(message) + + def ban_user(self, message, user_id: int): + user_name = BotDB.get_username(user_id=user_id) + ban_object = {'user_id': user_id, 'user_name': user_name, 'message_for_user': None, 'date_to_unban': None} + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("Спам") + item2 = types.KeyboardButton("Заебал стикерами") + markup.add(item1, item2) + self.bot.send_message(message.chat.id, + f"Выбран пользователь: {user_id}. Выбери причину бана из списка или напиши ее в чат", + reply_markup=markup) + self.bot.register_next_step_handler(message, self.ban_user_step_2, ban_object) + + def ban_user_step_2(self, message, ban_object: dict): + ban_object['message_for_user'] = message.text + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("1") + item2 = types.KeyboardButton("7") + item3 = types.KeyboardButton("30") + item4 = types.KeyboardButton("Навсегда") + markup.add(item1, item2, item3, item4) + self.bot.send_message(message.chat.id, f"Выбрана причина: {message.text}. Выбери срок бана в днях или напиши " + f"его в чат", + reply_markup=markup) + self.bot.register_next_step_handler(message, self.ban_user_step_3, ban_object) + + def ban_user_step_3(self, message, ban_object: dict): + date_to_unban = None + if message.text != 'Навсегда': + date_to_unban = self.add_days_to_date(message.text) + else: + pass + ban_object['date_to_unban'] = date_to_unban + markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) + item1 = types.KeyboardButton("Подтвердить") + item2 = types.KeyboardButton("Отменить") + markup.add(item1, item2) + self.bot.send_message(message.chat.id, + f"Необходимо подтверждение:\nПользователь:{ban_object['user_id']}\nПричина бана:{ban_object['message_for_user']}.\nСрок бана:{ban_object['date_to_unban']}", + parse_mode='html', + reply_markup=markup) + self.bot.register_next_step_handler(message, self.ban_user_final_step, ban_object) + + def ban_user_final_step(self, message, ban_object: dict): + if message.text == 'Подтвердить': + exists = BotDB.check_user_in_blacklist(ban_object['user_id']) + if exists: + self.bot.reply_to(message, f"Пользователь уже был заблокирован ранее.") + self.admin_panel(message) + else: + result = BotDB.set_user_blacklist(ban_object['user_id'], + ban_object['user_name'], + ban_object['message_for_user'], + ban_object['date_to_unban']) + if result: + self.bot.reply_to(message, f"Пользователь {ban_object['user_name']} успешно заблокирован.") + self.admin_panel(message) + else: + self.bot.reply_to(message, f"Произошла ошибка при блокировке пользователя.") + self.admin_panel(message) + + def get_last_users(self, message): + list_users = BotDB.get_last_users_from_bot() + markup = types.InlineKeyboardMarkup(row_width=1) + for user_id, full_name in list_users.items(): + button = types.InlineKeyboardButton( + f"{full_name}", callback_data=f'ban_{user_id}' + ) + # Добавляем кнопки на клавиатуру + markup.add(button) + self.bot.send_message(chat_id=message.chat.id, text="Список пользователей которые последними обращались к боту", + reply_markup=markup) def start_message(self, message): try: @@ -230,7 +298,6 @@ class TelegramHelperBot: self.bot.send_message(IMPORTANT_LOGS, f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - #TODO: При отправке более одного сообщения, не пересылает сообщение в чат, БАГ!!!! def resend_message_in_group_for_message(self, message): self.bot.forward_message(chat_id=GROUP_FOR_MESSAGE, from_chat_id=message.chat.id, @@ -401,11 +468,22 @@ class TelegramHelperBot: def __get_first_name(message): return message.from_user.first_name + @staticmethod + def check_access(user_id: int): + """Проверка прав на совершение действий""" + return BotDB.is_admin(user_id) + + @staticmethod + def add_days_to_date(days): + """Прибавляет указанное количество дней к текущей дате и возвращает дату в формате DD-MM-YYYY.""" + current_date = datetime.now() + future_date = current_date + timedelta(days=int(days)) + formatted_date = future_date.strftime("%d-%m-%Y") + return formatted_date + bot = TelegramHelperBot(BOT_TOKEN) - - if __name__ == "__main__": # Запускаем бота - bot.start() \ No newline at end of file + bot.start() From aded540d823e349044df31b46dc23ee69553048d Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Fri, 5 Jul 2024 01:27:35 +0300 Subject: [PATCH 06/10] add TO MUCH callbacks --- db.py | 25 ++++++++-- main.py | 139 +++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 144 insertions(+), 20 deletions(-) diff --git a/db.py b/db.py index efd2395..b61319f 100644 --- a/db.py +++ b/db.py @@ -313,13 +313,30 @@ class BotDB: except sqlite3.Error as error: print(error) - def get_last_users_from_bot(self): + def get_last_users_from_db(self): """Возвращает список идентификаторов последних 10 пользователей обращавшихся в бот""" try: - result = self.cursor.execute("SELECT full_name, user_id FROM our_users ORDER BY date_changed DESC LIMIT 10") + result = self.cursor.execute("SELECT full_name, user_id FROM our_users ORDER BY date_changed DESC") users = result.fetchall() - user_dict = {user[1]: user[0] for user in users} - return user_dict + return users + except sqlite3.Error as error: + print(error) + + def get_banned_users_from_db(self): + """Возвращает список идентификаторов последних 10 пользователей обращавшихся в бот""" + try: + result = self.cursor.execute("SELECT user_name, user_id, message_for_user, date_to_unban FROM blacklist", ) + users = result.fetchall() + return users + except sqlite3.Error as error: + print(error) + + def get_banned_users_from_db_with_limits(self, offset: int, limit: int): + """Возвращает список идентификаторов последних 10 пользователей обращавшихся в бот""" + try: + result = self.cursor.execute("SELECT user_name, user_id, message_for_user, date_to_unban FROM blacklist LIMIT ?, ?", (offset, limit,) ) + users = result.fetchall() + return users except sqlite3.Error as error: print(error) diff --git a/main.py b/main.py index 9f16088..35e6999 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,8 @@ import sys from pathlib import Path from time import sleep from enum import Enum +from typing import Any + import db from db import BotDB import telebot @@ -35,8 +37,9 @@ TEST = config.getboolean('Settings', 'test') BotDB = BotDB('tg-bot-database') -#TODO: state хранить в базе -#TODO: Перенести обработчик коллбэков +#TODO: Дописать функцию разбана и подключить ее к обработке коллбеков +#TODO: Подумать что сделать с процессом наступления даты разбана +#TODO: Сделать функционал игнора забаненных class State(Enum): START = "START" @@ -121,7 +124,7 @@ class TelegramHelperBot: self.bot.send_message(chat_id, message_from_admin, reply_markup=markup) # Админка - @self.bot.callback_query_handler(func=lambda call: True) + @self.bot.callback_query_handler(func=lambda call: call.data in ['publish', 'decline']) def post_for_group(call): if call.data == 'publish' and call.message.content_type == 'text': try: @@ -150,9 +153,29 @@ class TelegramHelperBot: if LOGS: self.bot.send_message(IMPORTANT_LOGS, f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") - elif call.data[:3] == 'ban': + + @self.bot.callback_query_handler(func=lambda call: True) + def pagination(call): + if call.data[:3] == 'ban': user_id = call.data[4:] self.ban_user(call.message, user_id) + if call.data[:5] == 'unban': + #TODO: Тут обрабатываем события, ДОПИСАТЬ!!!! + print(f'UNBAN NAXUY , {call.data[6:]}') + elif call.data[:4] == 'page': + if call.message.text == 'Список пользователей которые последними обращались к боту': + list_users = BotDB.get_last_users_from_db() + keyboard = self.create_keyboard_with_pagination(int(call.data[5:]), len(list_users), list_users, 'ban') + self.bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=keyboard) + if "Список заблокированных пользователей".lower() in call.message.text.lower(): + #Готовим сообщения + message_user = self.get_banned_users_list(int(call.data[5:])*7-7) + self.bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text=message_user) + + #Готовим клавиатуру + buttons = self.get_banned_users_buttons() + keyboard = self.create_keyboard_with_pagination(int(call.data[5:]), len(buttons), buttons, 'unban') + self.bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=keyboard) def register_chat_handler(self, message): self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) @@ -171,7 +194,8 @@ class TelegramHelperBot: item1 = types.KeyboardButton("Бан (Список)") item2 = types.KeyboardButton("Добавить админа") item3 = types.KeyboardButton("Удалить админа") - markup.add(item1, item2, item3) + item4 = types.KeyboardButton("Разбан (список)") + markup.add(item1, item2, item3, item4) self.bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) self.bot.register_next_step_handler(message, self.handle_admin_message) @@ -180,8 +204,10 @@ class TelegramHelperBot: def handle_admin_message(self, message): try: - if message.text == "Забанить пользователя из списка": + if message.text == "Бан (Список)": self.get_last_users(message) + elif message.text == "Разбан (список)": + self.get_banned_users(message) except Exception as e: self.bot.reply_to(message, f"Ошибка\n\n {e}") self.admin_panel(message) @@ -243,20 +269,21 @@ class TelegramHelperBot: self.bot.reply_to(message, f"Пользователь {ban_object['user_name']} успешно заблокирован.") self.admin_panel(message) else: - self.bot.reply_to(message, f"Произошла ошибка при блокировке пользователя.") + #TODO: тут какой-то баг. Отвечает что ошибка, но ошибок None + self.bot.reply_to(message, f"Произошла ошибка при блокировке пользователя. ERROR: {result}") self.admin_panel(message) def get_last_users(self, message): - list_users = BotDB.get_last_users_from_bot() - markup = types.InlineKeyboardMarkup(row_width=1) - for user_id, full_name in list_users.items(): - button = types.InlineKeyboardButton( - f"{full_name}", callback_data=f'ban_{user_id}' - ) - # Добавляем кнопки на клавиатуру - markup.add(button) + list_users = BotDB.get_last_users_from_db() + keyboard = self.create_keyboard_with_pagination(1, len(list_users), list_users, 'ban') self.bot.send_message(chat_id=message.chat.id, text="Список пользователей которые последними обращались к боту", - reply_markup=markup) + reply_markup=keyboard) + + def get_banned_users(self, message): + message_text = self.get_banned_users_list(0) + buttons_list = self.get_banned_users_buttons() + k = self.create_keyboard_with_pagination(1, len(buttons_list), buttons_list, 'unban') + self.bot.send_message(message.chat.id, message_text, reply_markup=k) def start_message(self, message): try: @@ -481,6 +508,86 @@ class TelegramHelperBot: formatted_date = future_date.strftime("%d-%m-%Y") return formatted_date + @staticmethod + def create_keyboard_with_pagination(page: int, total_items: int, array_items: list[tuple[Any, Any]], callback: str): + """ + Создает клавиатуру с пагинацией для заданного набора элементов и устанавливает необходимый callback + + Args: + page: Номер текущей страницы. + total_items: Общее количество элементов. + array_items: Лист кортежей. Содержит в себе user_name: user_id + callback: Действие в коллбеке. Вернет callback вида ({callback}_{user_id}) + + Returns: + InlineKeyboardMarkup: Клавиатура с кнопками пагинации. + """ + + # Определяем общее количество страниц + total_pages = (total_items + 7 - 1) // 7 + + page = page + # Создаем список кнопок + buttons = [] + # Вычисляем стартовый номер для текущей страницы + start_index = (page - 1) * 7 #тут было +1, убрал, потому что на текстовом массиве выходит за пределы + # Кнопки с номерами страниц + for i in range(start_index, min(start_index + 7, len(array_items))): #тут было len(array_items) +1, убрал, потому что на текстовом массиве выходит за пределы + buttons.append(types.InlineKeyboardButton(f"{array_items[i][0]}", callback_data=f"{callback}_{array_items[i][1]}")) + + + # Добавляем кнопки "Предыдущая" и "Следующая" + if int(page) > 1: + buttons.insert(6, types.InlineKeyboardButton("⬅️ Предыдущая", callback_data=f"page_{page-1}")) + if page < total_pages: + buttons.append(types.InlineKeyboardButton("➡️ Следующая", callback_data=f"page_{page+1}")) + + # Формируем клавиатуру с 3 кнопками в ряд + keyboard = [] + for i in range(0, len(buttons), 3): + keyboard.append(buttons[i:i+3]) + + return types.InlineKeyboardMarkup(keyboard) + + @staticmethod + def get_banned_users_list(offset: int): + """ + Возвращает сообщение со списком пользователей и словарь с ником + идентификатором + + Args: + offset: отступ для запроса в базу данных + + Returns: + message - текст сообщения + user_ids - лист кортежей [(user_name: user_id)] + """ + users = BotDB.get_banned_users_from_db_with_limits(limit=7, offset=offset) + message = "Список заблокированных пользователей:\n" + + for user in users: + message += f"Пользователь: {user[0]}\n" + message += f"Причина бана: {user[2]}\n" + message += f"Дата разбана: {user[3]}\n\n" + return message + + @staticmethod + def get_banned_users_buttons(): + """ + Возвращает сообщение со списком пользователей и словарь с ником + идентификатором + + Args: + offset: отступ для запроса в базу данных + + Returns: + message - текст сообщения + user_ids - лист кортежей [(user_name: user_id)] + """ + users = BotDB.get_banned_users_from_db() + user_ids = [] + + for user in users: + user_ids.append((user[0], user[1])) + return user_ids bot = TelegramHelperBot(BOT_TOKEN) From 2944bf2ae8be9f78a5c1581136492fcfd7f5a6f4 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Sat, 6 Jul 2024 00:16:53 +0300 Subject: [PATCH 07/10] final fix --- db.py | 12 +++++ main.py | 130 ++++++++++++++++++++++++++++++----------------- messages.py | 9 ++-- requirements.txt | 3 +- 4 files changed, 103 insertions(+), 51 deletions(-) diff --git a/db.py b/db.py index b61319f..6c6d4d5 100644 --- a/db.py +++ b/db.py @@ -221,6 +221,18 @@ class BotDB: except sqlite3.Error as error: print(error) + def get_users_for_unblock_today(self, date_to_unban): + """Возвращает пользователей у которых истекает срок блокировки сегодня""" + try: + result = self.cursor.execute("SELECT user_id, user_name FROM `blacklist` WHERE date_to_unban = ?", (date_to_unban,)) + fetch_all = result.fetchall() + list_of_users = {} + for i in fetch_all: + list_of_users[i[0]] = i[1] + return list_of_users + except sqlite3.Error as error: + print(error) + def get_blacklist_users_by_filters(self): """Возвращает список пользователей в черном списке по фильтру""" return None diff --git a/main.py b/main.py index 35e6999..a023ec7 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from pathlib import Path from time import sleep from enum import Enum from typing import Any - +from apscheduler.schedulers.background import BackgroundScheduler import db from db import BotDB import telebot @@ -88,28 +88,39 @@ class TelegramHelperBot: self.bot.send_message(message.chat.id, "Не понимаю где ты находишься. Нажми /state, и я расскажу что ты можешь " "сделать") - if self.state == State.SUGGEST: - self.bot.register_next_step_handler(message, self.resend_message_in_group_for_post) + self.bot.register_next_step_handler(message, self.send_to_suggest) self.state = State.START + if message.text == '/start': + self.state = State.START + self.start_message(message) elif self.state == State.PRE_CHAT: self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) self.state = State.START + if message.text == '/start': + self.state = State.START + self.start_message(message) if self.state == State.CHAT: if message.text == 'Выйти из чата': self.state = State.START self.end_message(message) + elif message.text == '/start': + self.state = State.START + self.start_message(message) else: self.resend_message_in_group_for_message(message) if self.state == State.ADMIN: - if message == '/admin' or message == '/restart': + if message == '/admin' or message == '/restart' or message == 'Вернуться в админку': access = self.check_access(message.from_user.id) if access: self.admin_panel(message) else: self.bot.send_message(message.chat.id, 'Доступ запрещен, досвидания!') + if message.text == '/start': + self.state = State.START + self.start_message(message) @self.bot.message_handler(func=lambda message: True, chat_types=['group']) def handle_message(message): @@ -159,26 +170,32 @@ class TelegramHelperBot: if call.data[:3] == 'ban': user_id = call.data[4:] self.ban_user(call.message, user_id) + if call.data == 'return': + self.bot.delete_message(call.message.chat.id, call.message.message_id) + self.admin_panel(call.message) + if call.data[:5] == 'unban': - #TODO: Тут обрабатываем события, ДОПИСАТЬ!!!! - print(f'UNBAN NAXUY , {call.data[6:]}') + self.delete_user_blacklist(call.data[6:]) + msg = f'Успешно удалено.' + self.bot.send_message(chat_id=call.message.chat.id, text=msg) elif call.data[:4] == 'page': if call.message.text == 'Список пользователей которые последними обращались к боту': list_users = BotDB.get_last_users_from_db() - keyboard = self.create_keyboard_with_pagination(int(call.data[5:]), len(list_users), list_users, 'ban') - self.bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=keyboard) + keyboard = self.create_keyboard_with_pagination(int(call.data[5:]), len(list_users), list_users, + 'ban') + self.bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, + reply_markup=keyboard) if "Список заблокированных пользователей".lower() in call.message.text.lower(): #Готовим сообщения - message_user = self.get_banned_users_list(int(call.data[5:])*7-7) - self.bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text=message_user) + message_user = self.get_banned_users_list(int(call.data[5:]) * 7 - 7) + self.bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, + text=message_user) #Готовим клавиатуру buttons = self.get_banned_users_buttons() keyboard = self.create_keyboard_with_pagination(int(call.data[5:]), len(buttons), buttons, 'unban') - self.bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=keyboard) - - def register_chat_handler(self, message): - self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) + self.bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, + reply_markup=keyboard) def start(self): while True: @@ -187,15 +204,29 @@ class TelegramHelperBot: except (ConnectionError, Exception): print(f"Произошла ошибка: {str(Exception)}\n\nTraceback:\n{traceback.format_exc()}") + def unban_notifier(self): + # Получение сегодняшней даты в формате DD-MM-YYYY + current_date = datetime.now() + today = current_date.strftime("%d-%m-%Y") + print(today) + # Получение списка разблокированных пользователей + unblocked_users = BotDB.get_users_for_unblock_today(today) + message = "Разблокированные пользователи:\n" + for user_id, user_name in unblocked_users.items(): + message += f"ID: {user_id}, Имя: {user_name}\n" + + # Отправка сообщения в канал + self.bot.send_message(GROUP_FOR_MESSAGE, message) + # Черный список def admin_panel(self, message): try: markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) item1 = types.KeyboardButton("Бан (Список)") - item2 = types.KeyboardButton("Добавить админа") - item3 = types.KeyboardButton("Удалить админа") + #item2 = types.KeyboardButton("Добавить админа") #TODO: Когда-нибудь потом доделаю + #item3 = types.KeyboardButton("Удалить админа") item4 = types.KeyboardButton("Разбан (список)") - markup.add(item1, item2, item3, item4) + markup.add(item1, item4) self.bot.send_message(message.chat.id, "Добро пожаловать в админку. Выбери что хочешь:", reply_markup=markup) self.bot.register_next_step_handler(message, self.handle_admin_message) @@ -261,17 +292,12 @@ class TelegramHelperBot: self.bot.reply_to(message, f"Пользователь уже был заблокирован ранее.") self.admin_panel(message) else: - result = BotDB.set_user_blacklist(ban_object['user_id'], - ban_object['user_name'], - ban_object['message_for_user'], - ban_object['date_to_unban']) - if result: - self.bot.reply_to(message, f"Пользователь {ban_object['user_name']} успешно заблокирован.") - self.admin_panel(message) - else: - #TODO: тут какой-то баг. Отвечает что ошибка, но ошибок None - self.bot.reply_to(message, f"Произошла ошибка при блокировке пользователя. ERROR: {result}") - self.admin_panel(message) + BotDB.set_user_blacklist(ban_object['user_id'], + ban_object['user_name'], + ban_object['message_for_user'], + ban_object['date_to_unban']) + self.bot.reply_to(message, f"Пользователь {ban_object['user_name']} успешно заблокирован.") + self.admin_panel(message) def get_last_users(self, message): list_users = BotDB.get_last_users_from_db() @@ -282,8 +308,12 @@ class TelegramHelperBot: def get_banned_users(self, message): message_text = self.get_banned_users_list(0) buttons_list = self.get_banned_users_buttons() - k = self.create_keyboard_with_pagination(1, len(buttons_list), buttons_list, 'unban') - self.bot.send_message(message.chat.id, message_text, reply_markup=k) + if buttons_list: + k = self.create_keyboard_with_pagination(1, len(buttons_list), buttons_list, 'unban') + self.bot.send_message(message.chat.id, message_text, reply_markup=k) + else: + self.bot.send_message(message.chat.id, "В списке забанненых пользователей никого нет") + self.admin_panel(message) def start_message(self, message): try: @@ -334,9 +364,7 @@ class TelegramHelperBot: date = current_date.strftime("%Y-%m-%d %H:%M:%S") BotDB.add_new_message_in_db(message.text, message.message_id + 1, message.from_user.id, date, 0) question = messages.get_message(self.__get_first_name(message), 'QUESTION') - markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) - item1 = types.KeyboardButton("Выйти из чата") - markup.add(item1) + markup = self.get_reply_keyboard(message) self.bot.send_message(message.chat.id, question, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK, reply_markup=markup) @@ -349,9 +377,8 @@ class TelegramHelperBot: suggest_news_2 = messages.get_message(self.__get_first_name(message), 'SUGGEST_NEWS_2') self.bot.send_message(message.chat.id, suggest_news_2, parse_mode='html', reply_markup=markup) except Exception as e: - if LOGS: - self.bot.send_message(IMPORTANT_LOGS, - f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + self.bot.send_message(IMPORTANT_LOGS, + f"Произошла ошибка: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") # logging if LOGS: self.bot.forward_message(chat_id=GROUP_FOR_LOGS, @@ -405,7 +432,7 @@ class TelegramHelperBot: from_chat_id=message.chat.id, message_id=message.message_id) - def resend_message_in_group_for_post(self, message): + def send_to_suggest(self, message): markup = types.InlineKeyboardMarkup(row_width=1) item1 = types.InlineKeyboardButton("Опубликовать", callback_data='publish') item2 = types.InlineKeyboardButton("Отклонить", callback_data='decline') @@ -530,23 +557,24 @@ class TelegramHelperBot: # Создаем список кнопок buttons = [] # Вычисляем стартовый номер для текущей страницы - start_index = (page - 1) * 7 #тут было +1, убрал, потому что на текстовом массиве выходит за пределы + start_index = (page - 1) * 7 #тут было +1, убрал, потому что на текстовом массиве выходит за пределы # Кнопки с номерами страниц - for i in range(start_index, min(start_index + 7, len(array_items))): #тут было len(array_items) +1, убрал, потому что на текстовом массиве выходит за пределы - buttons.append(types.InlineKeyboardButton(f"{array_items[i][0]}", callback_data=f"{callback}_{array_items[i][1]}")) - + for i in range(start_index, min(start_index + 7, + len(array_items))): #тут было len(array_items) +1, убрал, потому что на текстовом массиве выходит за пределы + buttons.append( + types.InlineKeyboardButton(f"{array_items[i][0]}", callback_data=f"{callback}_{array_items[i][1]}")) # Добавляем кнопки "Предыдущая" и "Следующая" if int(page) > 1: - buttons.insert(6, types.InlineKeyboardButton("⬅️ Предыдущая", callback_data=f"page_{page-1}")) + buttons.insert(6, types.InlineKeyboardButton("⬅️ Предыдущая", callback_data=f"page_{page - 1}")) if page < total_pages: - buttons.append(types.InlineKeyboardButton("➡️ Следующая", callback_data=f"page_{page+1}")) - + buttons.append(types.InlineKeyboardButton("➡️ Следующая", callback_data=f"page_{page + 1}")) + #Добавляем кнопку назад + buttons.append(types.InlineKeyboardButton("🏠 Назад", callback_data="return")) # Формируем клавиатуру с 3 кнопками в ряд keyboard = [] for i in range(0, len(buttons), 3): - keyboard.append(buttons[i:i+3]) - + keyboard.append(buttons[i:i + 3]) return types.InlineKeyboardMarkup(keyboard) @staticmethod @@ -589,8 +617,18 @@ class TelegramHelperBot: user_ids.append((user[0], user[1])) return user_ids + @staticmethod + def delete_user_blacklist(user_id): + return BotDB.delete_user_blacklist(user_id=user_id) + + bot = TelegramHelperBot(BOT_TOKEN) if __name__ == "__main__": # Запускаем бота bot.start() + + scheduler = BackgroundScheduler() + scheduler.add_job(bot.unban_notifier(), 'cron', hour=0, minute=0) + scheduler.start() + diff --git a/messages.py b/messages.py index 26c4824..883ae1d 100644 --- a/messages.py +++ b/messages.py @@ -5,10 +5,11 @@ def get_message(username: str, type_message: str): 'HELLO_MESSAGE': "Привет, username!👋🏼&Меня зовут Виби, я бот канала 'Влюбленный Бийск'❤🤖" "&Я был создан для того, чтобы помочь тебе выложить пост в наш канал и если это необходимо, связаться с админами ✍✉" "&Так же я могу выдать тебе набор стикеров, где я буду главным героем🦸‍♂" - "&Дать возможность высказаться в нашем стендап режиме🎤&Послушать о чем говорит наш город🎧" + "&Наш бот голосового общения переехал сюда: https://t.me/podslushano_biysk_bot 🎤&Там можно послушать о чем говорит наш город🎧" "&Предлагай свой пост мне и я обязательно его опубликую😉" "&Для продолжения взаимодействия воспользуйся меню внизу твоего дисплея⬇" - "&&P.S. Иногда я зависаю по неизвестным причинам, если от меня нет ответа, введи в чат команду /start, это перезапустит сценарий." + "&&Если что-то пошло не так: введи в чат команду /start, это перезапустит сценарий сначала." + "&Не жми кнопку несколько раз если я не ответил с первого раза. Возможно ведутся тех.работы и я отвечу позже" "&&Основная группа в ВК: https://vk.com/love_bsk" "&Основной канал в ТГ: https://t.me/love_bsk", 'SUGGEST_NEWS': "username, окей, жду от тебя текст поста🙌🏼" @@ -17,8 +18,8 @@ def get_message(username: str, type_message: str): 'SUGGEST_NEWS_2': "Обрати внимание, что я умный и смогу из твоего текста понять команды указанные ниже😉" "&Если хочешь чтобы пост был опубликован анонимно, напиши в любом месте своего поста слово 'анон'." "&Если хочешь опубликовать пост не анонимно, то напиши 'не анон', 'неанон' или не пиши ничего." - "&&Я обучен только на команды, указанные мной выше👆" - "&‼Проверь, чтобы указание авторства было выполнено так как я попросил." + "&&❗️❗️❗️Я обучен только на команды, указанные мной выше❗️❗️❗️👆" + "&‼Проверь, чтобы указание авторства было выполнено так как я попросил, иначе пост будет выложен не корректно" "&Пост будет опубликован только в группе ТГ📩", "CONNECT_WITH_ADMIN": "username, напиши свое обращение или предложение✍️" "&Мы рассмотрим и ответим тебе в ближайшее время☺️❤️", diff --git a/requirements.txt b/requirements.txt index 0ec9818..682a9e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -pyTelegramBotAPI \ No newline at end of file +pyTelegramBotAPI +APScheduler~=3.10.4 \ No newline at end of file From 7adab035f4a147500b0d21342a0ee995f0572951 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Sat, 6 Jul 2024 00:17:25 +0300 Subject: [PATCH 08/10] add logger --- custom_logger.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 custom_logger.py diff --git a/custom_logger.py b/custom_logger.py new file mode 100644 index 0000000..7a76c48 --- /dev/null +++ b/custom_logger.py @@ -0,0 +1,58 @@ +import logging +import os +import datetime +from logging.handlers import RotatingFileHandler + + +class Logger: + def __init__(self, name): + # Инициализация логгера + self.logger = logging.getLogger(name) # Сохраняем logger как свойство класса + self.logger.setLevel(logging.INFO) + + # Формат записи логов + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(message)s') + + # Получение сегодняшней даты для имени файла + today = datetime.date.today().strftime('%Y-%m-%d') + + # Создание папки для логов + current_dir = os.path.dirname(os.path.abspath(__file__)) + logs_dir = os.path.join(current_dir, 'logs') + if not os.path.exists(logs_dir): + # Если не существует, создаем ее + os.makedirs(logs_dir) + filename = f'logs/helper_bot_{today}.log' + + # Создание обработчика для файла логов + file_handler = RotatingFileHandler( + filename, + mode='a', + maxBytes=10 * 1024 * 1024, # Максимальный размер файла (10 МБ) + backupCount=3 # Количество резервных файлов + ) + file_handler.setFormatter(formatter) + + # Добавление обработчика к логгеру + self.logger.addHandler(file_handler) + + # Добавление стандартного обработчика + # чтобы сообщения также отображались на консоли + console_handler = logging.StreamHandler() + console_handler.setFormatter(formatter) + self.logger.addHandler(console_handler) + + def info(self, message): + self.logger.info(message) + + def debug(self, message): + self.logger.debug(message) + + def warning(self, message): + self.logger.warning(message) + + def error(self, message): + self.logger.error(message) + + def critical(self, message): + self.logger.critical(message) \ No newline at end of file From c3a6bcbb8a2bba43103dc9bb6a7570b598b65419 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Sat, 6 Jul 2024 00:33:37 +0300 Subject: [PATCH 09/10] some fix --- db.py | 11 ++++++++--- main.py | 8 +++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/db.py b/db.py index 6c6d4d5..75dab11 100644 --- a/db.py +++ b/db.py @@ -233,9 +233,14 @@ class BotDB: except sqlite3.Error as error: print(error) - def get_blacklist_users_by_filters(self): - """Возвращает список пользователей в черном списке по фильтру""" - return None + def get_blacklist_users_by_id(self, user_id): + """Возвращает список пользователей в черном списке по user_id""" + try: + result = self.cursor.execute("SELECT user_id, user_name, message_for_user, date_to_unban FROM `blacklist` WHERE user_id = ?", (user_id, )) + return self.cursor.fetchone() + except sqlite3.Error as error: + print(error) + def check_user_in_blacklist(self, user_id): """Проверяет, существует ли запись с данным user_id в blacklist.""" diff --git a/main.py b/main.py index a023ec7..6cb05a3 100644 --- a/main.py +++ b/main.py @@ -57,6 +57,11 @@ class TelegramHelperBot: # Router for user @self.bot.message_handler(func=lambda message: True, chat_types=['private']) def handle_message(message): + if BotDB.check_user_in_blacklist(message.from_user.id): + attribute = BotDB.get_blacklist_users_by_id(message.from_user.id) + self.bot.send_message(message.chat.id, + f'Ты заблокирован\nПричина блокировки: {attribute[2]}\nДата разблокировки: {attribute[3]}', parse_mode='HTML') + return if self.state == State.START: if message.text == '/start': self.start_message(message) @@ -88,13 +93,14 @@ class TelegramHelperBot: self.bot.send_message(message.chat.id, "Не понимаю где ты находишься. Нажми /state, и я расскажу что ты можешь " "сделать") + if self.state == State.SUGGEST: self.bot.register_next_step_handler(message, self.send_to_suggest) self.state = State.START if message.text == '/start': self.state = State.START self.start_message(message) - elif self.state == State.PRE_CHAT: + if self.state == State.PRE_CHAT: self.bot.register_next_step_handler(message, self.resend_message_in_group_for_message) self.state = State.START if message.text == '/start': From 2c71b8ba4627bf5f3e95bb4708a436d7267fd215 Mon Sep 17 00:00:00 2001 From: KatykhinAA Date: Sat, 6 Jul 2024 13:05:50 +0300 Subject: [PATCH 10/10] add migrations --- custom_logger.py | 37 +++++----------- db.py | 66 ++++++++++++++++++++++++----- main.py | 7 +-- migrations/000_migrations_init.py | 27 ++++++++++++ migrations/001_create_new_tables.py | 56 ++++++++++++++++++++++++ requirements.txt | 3 +- 6 files changed, 152 insertions(+), 44 deletions(-) create mode 100644 migrations/000_migrations_init.py create mode 100644 migrations/001_create_new_tables.py diff --git a/custom_logger.py b/custom_logger.py index 7a76c48..28b9655 100644 --- a/custom_logger.py +++ b/custom_logger.py @@ -1,17 +1,11 @@ -import logging -import os import datetime -from logging.handlers import RotatingFileHandler +import os +from loguru import logger class Logger: def __init__(self, name): - # Инициализация логгера - self.logger = logging.getLogger(name) # Сохраняем logger как свойство класса - self.logger.setLevel(logging.INFO) - - # Формат записи логов - formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(message)s') + self.logger = logger.bind(name=name) # Получение сегодняшней даты для имени файла today = datetime.date.today().strftime('%Y-%m-%d') @@ -22,25 +16,16 @@ class Logger: if not os.path.exists(logs_dir): # Если не существует, создаем ее os.makedirs(logs_dir) - filename = f'logs/helper_bot_{today}.log' + filename = f'{logs_dir}/helper_bot_{today}.log' - # Создание обработчика для файла логов - file_handler = RotatingFileHandler( + # Настройка формата логов + self.logger.add( filename, - mode='a', - maxBytes=10 * 1024 * 1024, # Максимальный размер файла (10 МБ) - backupCount=3 # Количество резервных файлов + rotation="00:00", + retention="5 days", + compression="zip", + format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {name} | {line} | {message}", ) - file_handler.setFormatter(formatter) - - # Добавление обработчика к логгеру - self.logger.addHandler(file_handler) - - # Добавление стандартного обработчика - # чтобы сообщения также отображались на консоли - console_handler = logging.StreamHandler() - console_handler.setFormatter(formatter) - self.logger.addHandler(console_handler) def info(self, message): self.logger.info(message) @@ -55,4 +40,4 @@ class Logger: self.logger.error(message) def critical(self, message): - self.logger.critical(message) \ No newline at end of file + self.logger.critical(message) diff --git a/db.py b/db.py index 75dab11..76cef3f 100644 --- a/db.py +++ b/db.py @@ -1,23 +1,64 @@ import sqlite3 import configparser import os -import sys -import custom_logger +from datetime import datetime +from loguru import logger +from custom_logger import Logger -config_path = os.path.join(sys.path[0], 'settings.ini') +db_logger = Logger(name='db') +script_dir = os.path.dirname(os.path.abspath(__file__)) +config_path = os.path.join(script_dir, 'settings.ini') config = configparser.ConfigParser() config.read(config_path) LOGS = config.getboolean('Settings', 'logs') IMPORTANT_LOGS = config.get('Telegram', 'important_logs') -db_logger = custom_logger.Logger('database') - class BotDB: - def __init__(self, db_file): + def __init__(self): + db_file_path = os.path.dirname(os.path.abspath(__file__)) + db_file = os.path.join(db_file_path, 'tg-bot-database') self.conn = sqlite3.connect(db_file, check_same_thread=False) self.cursor = self.conn.cursor() + logger.info(f'Подключен к базе данных: {db_file_path}') + + def create_table(self, sql_script): + """Создает таблицу в базе.""" + try: + cursor = self.conn.cursor() + cursor.execute(sql_script) + except Exception as e: + print(f"Ошибка при создании таблицы: {e}") + + def get_current_version(self): + """Получает текущую версию миграций из таблицы migrations.""" + try: + cursor = self.conn.cursor() + cursor.execute("SELECT version FROM migrations ORDER BY version DESC LIMIT 1") + version = cursor.fetchone()[0] + return version + except Exception as e: + print(f"Ошибка при получении версии: {e}") + return 0 + + def update_version(self, new_version, script_name): + """Обновляет версию миграций в таблице migrations.""" + logger.info(f'Попытка обновления версии: {new_version}, скрипт: {script_name}') + try: + current_date = datetime.now() + today = current_date.strftime("%d-%m-%Y %H:%M:%S") + cursor = self.conn.cursor() + cursor.execute( + "INSERT INTO migrations (version, script_name, created_at) VALUES(?, ?, ?)", + (new_version, script_name, today), + ) + self.conn.commit() + logger.info(f"Версия обновлена: {new_version}, скрипт: {script_name}") + except sqlite3.IntegrityError as e: + logger.error(f"Ошибка при обновлении версии: {e}") + except Exception as e: + logger.error(f"Ошибка при обновлении версии: {e}") # TODO: Deprecated, удалить def get_message_from_db(self, type: str, username): @@ -264,10 +305,10 @@ class BotDB: #TODO: Функция всегда возвращает true, даже если такого id нет в таблице self.cursor.execute("DELETE FROM blacklist WHERE user_id = ?", (user_id,)) self.conn.commit() - db_logger.info(f"User with ID {user_id} successfull delete.") + logger.info(f"Пользователь с идентификатором {user_id} успешно удален.") return True except sqlite3.Error as error: - db_logger.error(f"Error delete user with ID {user_id} from blacklist table: {str(error)}") + logger.error(f"Ошибка удаления пользователя с идентификатором {user_id} из таблицы blacklist. Ошибка: {str(error)}") return False def add_new_message_in_db(self, message_text, user_id, message_id, date, has_answer): @@ -302,14 +343,17 @@ class BotDB: result = self.cursor.fetchone() return bool(result) - def add_admin(self, user_id, username=None): + def add_admin(self, user_id, role): """ Добавляет пользователя в список администраторов. Args: user_id: ID пользователя Telegram. - username: Username пользователя (необязательно). + role: Роль пользователя. + Доступные варианты: + 1. creator - создатель + 2. admin - обычная роль """ - self.cursor.execute("INSERT INTO admins (user_id, username) VALUES (?, ?)", (user_id, username)) + self.cursor.execute("INSERT INTO admins (user_id, role) VALUES (?, ?)", (user_id, role)) return self.conn.commit() def remove_admin(self, user_id): diff --git a/main.py b/main.py index 6cb05a3..9cbe318 100644 --- a/main.py +++ b/main.py @@ -34,13 +34,9 @@ LOGS = config.getboolean('Settings', 'logs') TEST = config.getboolean('Settings', 'test') # Инициализируем бота и базку -BotDB = BotDB('tg-bot-database') +BotDB = BotDB() -#TODO: Дописать функцию разбана и подключить ее к обработке коллбеков -#TODO: Подумать что сделать с процессом наступления даты разбана -#TODO: Сделать функционал игнора забаненных - class State(Enum): START = "START" SUGGEST = "SUGGEST" @@ -214,7 +210,6 @@ class TelegramHelperBot: # Получение сегодняшней даты в формате DD-MM-YYYY current_date = datetime.now() today = current_date.strftime("%d-%m-%Y") - print(today) # Получение списка разблокированных пользователей unblocked_users = BotDB.get_users_for_unblock_today(today) message = "Разблокированные пользователи:\n" diff --git a/migrations/000_migrations_init.py b/migrations/000_migrations_init.py new file mode 100644 index 0000000..4ba49b0 --- /dev/null +++ b/migrations/000_migrations_init.py @@ -0,0 +1,27 @@ +import os +from db import BotDB + + +BotDB = BotDB() + + +def get_filename(): + """Возвращает имя файла без расширения.""" + filename = os.path.basename(__file__) + filename = os.path.splitext(filename)[0] + return filename + + +def main(): + migrations_init = """ + CREATE TABLE IF NOT EXISTS migrations ( + version INTEGER PRIMARY KEY NOT NULL, + script_name TEXT NOT NULL, + created_at TEXT + ); + """ + BotDB.create_table(migrations_init) + BotDB.update_version(0, get_filename()) + +if __name__ == "__main__": + main() diff --git a/migrations/001_create_new_tables.py b/migrations/001_create_new_tables.py new file mode 100644 index 0000000..cd45af5 --- /dev/null +++ b/migrations/001_create_new_tables.py @@ -0,0 +1,56 @@ +import os +from db import BotDB + +BotDB = BotDB() + + +def get_filename(): + """Возвращает имя файла без расширения.""" + filename = os.path.basename(__file__) + filename = os.path.splitext(filename)[0] + return filename + + +def main(): + # Проверка версии миграций + current_version = BotDB.get_current_version() # Добавьте функцию для получения версии + + # Выполнение миграций и проверка последней версии + if current_version < 1: + # Скрипты миграции + create_table_sql_1 = """ + CREATE TABLE IF NOT EXISTS "admins" ( + user_id INTEGER NOT NULL, + "role" TEXT + ); + """ + create_table_sql_2 = """CREATE TABLE IF NOT EXISTS "blacklist" + ( + "user_id" INTEGER NOT NULL UNIQUE, + "user_name" INTEGER, + "message_for_user" INTEGER, + "date_to_unban" INTEGER + ); + """ + create_table_sql_3 = """ + CREATE TABLE IF NOT EXISTS user_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_text TEXT, + user_id INTEGER, + message_id INTEGER NOT NULL, + date TEXT + ); + """ + # Применение миграции + BotDB.create_table(create_table_sql_1) + BotDB.create_table(create_table_sql_2) + BotDB.create_table(create_table_sql_3) + BotDB.add_admin(842766148, 'creator') + BotDB.add_admin(920057022, 'admin') + filename = get_filename() + + BotDB.update_version(1, filename) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index 682a9e4..35a1522 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pyTelegramBotAPI -APScheduler~=3.10.4 \ No newline at end of file +APScheduler~=3.10.4 +loguru~=0.7.2 \ No newline at end of file