diff --git a/db.py b/db.py new file mode 100644 index 0000000..72402ae --- /dev/null +++ b/db.py @@ -0,0 +1,140 @@ +import sqlite3 +import configparser +import os +import sys + +config_path = os.path.join(sys.path[0], 'settings.ini') +config = configparser.ConfigParser() +config.read(config_path) +LOGS = config.getboolean('Settings', 'logs') +IMPORTANT_LOGS = config.get('Telegram', 'important_logs') + + +class BotDB: + + def __init__(self, db_file): + self.conn = sqlite3.connect(db_file, check_same_thread=False) + self.cursor = self.conn.cursor() + + def get_message_from_db(self, type: str, username): + """Функция для запроса к базе данных и получения сообщений для бота. В аргументы передаются: + type - тип получаемой обратной связи, строковое значение, сохраненное в БД + username - имя пользователя + """ + # Подключаемся к базе + try: + cursor = self.conn.cursor() + cursor.execute(f"SELECT * FROM messages WHERE type=?", (type,)) + # Забираем данные из таблицы, преобразуем в строку, заменяем поле username на имя пользователя, + # и вместо амберсанда подставляем перенос строки + if type == 'connect_with_admin' or type == 'del_message' or type == 'suggest_news' or type == 'start_message': + response_from_database = str(cursor.fetchone()[1]).replace('username', username).replace('&', '\n') + else: + response_from_database = str(cursor.fetchone()[1]).replace('&', '\n') + return response_from_database + except sqlite3.Error as error: + print(error) + + def get_error_message_from_db(self, id: int): + """Функция для запроса к базе данных и получения сообщений ошибки. В аргументы передаются: + id - идентификатор ошибки + """ + # Подключаемся к базе + try: + cursor = self.conn.cursor() + cursor.execute(f"SELECT * FROM error_messages WHERE id=?", (id,)) + response_from_database = str(cursor.fetchone()[1]) + return response_from_database + 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): + """Добавляем юзера в базу""" + 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)) + return self.conn.commit() + except sqlite3.Error as error: + print(error) + + + def user_exists(self, user_id): + """Проверяем, есть ли юзер в базе""" + try: + result = self.cursor.execute("SELECT `id` FROM `our_users` WHERE `user_id` = ?", (user_id,)) + return bool(len(result.fetchall())) + except sqlite3.Error as error: + print(error) + + + def get_user_id(self, user_id): + """Достаем id юзера в базе по его user_id""" + try: + result = self.cursor.execute("SELECT `id` FROM `our_users` WHERE `user_id` = ?", (user_id,)) + return result.fetchone()[0] + except sqlite3.Error as error: + print(error) + + + def get_user_first_name(self, user_id): + try: + result = self.cursor.execute("SELECT `first_name` FROM `our_users` WHERE `user_id` = ?", (user_id,)) + return result.fetchone()[0] + 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), ) + pass + + 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)) + return self.conn.commit() + 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,)) + return bool(len(result.fetchall())) + except sqlite3.Error as error: + print(error) + + 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,)) + return result.fetchone()[0] + except sqlite3.Error as error: + print(error) + + 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,)) + return result.fetchone()[0] + except sqlite3.Error as error: + print(error) + + def get_random_audio(self): + """Получает данные о войсе юзера из БД""" + try: + 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) + + def close(self): + """Закрываем соединение с БД""" + self.conn.close() + diff --git a/main.py b/main.py index 90b543a..15cc261 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,14 @@ import configparser +import itertools import os import sys -import sqlite3 from pathlib import Path from time import sleep - +from db import BotDB import telebot import random +from datetime import datetime +import time from telebot import types from telebot.apihelper import ApiTelegramException @@ -18,6 +20,7 @@ config.read(config_path) 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') +GROUP_FOR_AUDIO = config.get('Telegram', 'group_for_audio') MAIN_PUBLIC = config.get('Telegram', 'main_public') GROUP_FOR_LOGS = config.get('Telegram', 'group_for_logs') IMPORTANT_LOGS = config.get('Telegram', 'important_logs') @@ -25,50 +28,9 @@ PREVIEW_LINK = config.getboolean('Telegram', 'PREVIEW_LINK') #SETTINGS LOGS = config.getboolean('Settings', 'logs') -#Инициализируем бота +#Инициализируем бота и базку bot = telebot.TeleBot(BOT_TOKEN, parse_mode=None) - -def select_message_from_db(type: str, username): - """Функция для запроса к базе данных и получения сообщений для бота. В аргументы передаются: - type - тип получаемой обратной связи, строковое значение, сохраненное в БД - username - имя пользователя - """ - # Подключаемся к базе - conn = sqlite3.connect('tg-bot-database', check_same_thread=False) - try: - cursor = conn.cursor() - cursor.execute(f"SELECT * FROM messages WHERE type=?", (type,)) - #Забираем данные из таблицы, преобразуем в строку, заменяем поле username на имя пользователя, - #и вместо амберсанда подставляем перенос строки - response_from_database = str(cursor.fetchone()[1]).replace('username', username).replace('&', '\n') - return response_from_database - except sqlite3.Error as error: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f'Ошибка при работе с SQLite, {error}') - finally: - if conn: - conn.close() - - -def error_message_from_db(id: int): - """Функция для запроса к базе данных и получения сообщений ошибки. В аргументы передаются: - id - идентификатор ошибки - """ - # Подключаемся к базе - conn = sqlite3.connect('tg-bot-database', check_same_thread=False) - try: - cursor = conn.cursor() - cursor.execute(f"SELECT * FROM error_messages WHERE id=?", (id,)) - response_from_database = str(cursor.fetchone()[1]) - return response_from_database - except sqlite3.Error as error: - if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, - text=f'Ошибка при работе с SQLite, {error}') - finally: - if conn: - conn.close() +BotDB = BotDB('tg-bot-database') def telegram_bot(): @bot.message_handler(commands=['start']) @@ -88,26 +50,39 @@ def telegram_bot(): sleep(0.3) except: if LOGS: - bot.send_message(IMPORTANT_LOGS, error_message_from_db(7)) + bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(7)) markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True) item1 = types.KeyboardButton("Предложить свой пост") item2 = types.KeyboardButton("Связаться с админами") item3 = types.KeyboardButton("Удалить пост") + item4 = types.KeyboardButton("Войти в режим стендапа") - markup.add(item1, item2, item3) + markup.add(item1, item2, item3, item4) try: - username = message.from_user.first_name - hello_message = select_message_from_db('start_message', username) + user_id = message.from_user.id + first_name = message.from_user.first_name + full_name = message.from_user.full_name + 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) + if BotDB.user_exists(user_id): + pass + else: + BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date_added, date_changed) + 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: if LOGS: - bot.send_message(IMPORTANT_LOGS, error_message_from_db(8)) + bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(8)) bot.register_next_step_handler(message, go_send_messages) @bot.message_handler(commands=['end_command']) def after_post(message): - markup = types.ReplyKeyboardMarkup(row_width=1) + markup = types.ReplyKeyboardMarkup(row_width=2) item1 = types.KeyboardButton("Предложить свой пост") item2 = types.KeyboardButton("Связаться с админами") item3 = types.KeyboardButton("Удалить пост") @@ -124,16 +99,16 @@ def telegram_bot(): if message.text == 'Предложить свой пост': try: markup = types.ReplyKeyboardRemove() - username = message.from_user.first_name - suggest_news = select_message_from_db('suggest_news', username) + first_name = message.from_user.first_name + suggest_news = BotDB.get_message_from_db('suggest_news', first_name) bot.send_message(message.chat.id, suggest_news, parse_mode='html') sleep(0.3) - username = message.from_user.first_name - suggest_news_2 = select_message_from_db('suggest_news_2', username) + 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: if LOGS: - bot.send_message(IMPORTANT_LOGS, error_message_from_db(10)) + bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(10)) #logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, @@ -142,8 +117,8 @@ def telegram_bot(): bot.register_next_step_handler(msg, resend_message_in_group_for_post) elif message.text == "Связаться с админами": - username = message.from_user.first_name - connect_with_admin = select_message_from_db('connect_with_admin', username) + first_name = message.from_user.first_name + connect_with_admin = BotDB.get_message_from_db('connect_with_admin', first_name) msg = bot.send_message(message.chat.id, connect_with_admin, parse_mode="html") #logging if LOGS: @@ -152,10 +127,26 @@ def telegram_bot(): message_id=message.message_id) bot.register_next_step_handler(msg, resend_message_in_group_for_message) + elif message.text == "Войти в режим стендапа": + markup = types.ReplyKeyboardMarkup(row_width=1) + item1 = types.KeyboardButton("Высказаться") + item2 = types.KeyboardButton("Послушать") + markup.add(item1, item2) + first_name = message.from_user.first_name + message_for_standup = BotDB.get_message_from_db('message_for_standup', first_name) + msg = bot.send_message(message.chat.id, message_for_standup, parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) + #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, standup) + + elif message.text == "Удалить пост": #TODO: требует автоматизации. На входе говорим пришли мне пост, на выходе получаем идентификатор поста, удаляем из ТГ. Насчет удаления из ВК надо подумать - username = message.from_user.first_name - del_message = select_message_from_db('del_message', username) + first_name = message.from_user.first_name + del_message = BotDB.get_message_from_db('del_message', first_name) msg = bot.send_message(message.chat.id, del_message, parse_mode="html") #logging if LOGS: @@ -172,39 +163,100 @@ def telegram_bot(): bot.send_sticker(message.chat.id, random_stick_bye) except ApiTelegramException: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message_from_db(11)) + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(11)) markup = types.ReplyKeyboardRemove() try: - username = message.from_user.first_name - bye_message = select_message_from_db('bye_message', username) + first_name = message.from_user.first_name + bye_message = BotDB.get_message_from_db('bye_message', first_name) bot.send_message(message.chat.id, bye_message, parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) except: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message_from_db(6)) + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(6)) if LOGS: #logging bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, message_id=message.message_id) - else: try: - username = message.from_user.first_name - user_error = select_message_from_db('user_error', username) + 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: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message_from_db(9)) + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(9)) #logging if LOGS: bot.forward_message(chat_id=GROUP_FOR_LOGS, from_chat_id=message.chat.id, message_id=message.message_id) - after_post(message=message) + menu_standup(message=message) + def standup(message): + try: + if message.text == 'Высказаться' or message.text == 'Высказаться еще': + markup = types.ReplyKeyboardRemove() + msg = bot.send_message(chat_id=message.chat.id, text='Пришли мне свое голосовое сообщение', reply_markup=markup) + bot.register_next_step_handler(msg, save_voice_message) + elif message.text == 'Послушать': + #msg = bot.send_voice(chat_id=message.chat.id, open('voice_users/new_file.ogg', 'rb')) + msg = bot.send_message(chat_id=message.chat.id, text='Погоди, так еще не умею') + bot.register_next_step_handler(msg, menu_standup) + elif message.text == 'Вернуться в меню': + after_post(message=message) + except: + if LOGS: + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(4)) + + def menu_standup(message): + markup = types.ReplyKeyboardMarkup(row_width=2) + item1 = types.KeyboardButton("Высказаться еще") + item2 = types.KeyboardButton("Послушать") + item3 = types.KeyboardButton("Вернуться в меню") + markup.add(item1, item2, item3) + msg = bot.send_message(chat_id=message.chat.id, + text='Держи клавиатуру и выбери нужную кнопку внизу экрана!', + parse_mode='html', reply_markup=markup, disable_web_page_preview=not PREVIEW_LINK) + bot.register_next_step_handler(msg, standup) + + def save_voice_message(message): + if message.content_type == 'voice': + #ret_msg = bot.send_voice(message.chat.id, open('voice_users/new_file.ogg', 'rb')) message_id, author_id, added_date + file_name = '' + file_id = 1 + #Проверяем что запись о файле есть в базе данных + is_having_audio_from_user = BotDB.get_last_user_audio_record(user_id=message.from_user.id) + if is_having_audio_from_user is False: + #Если нет, то генерируем имя файла + file_name = f'message_from_{message.from_user.id}_number_{file_id}' + else: + #Иначе берем последнюю запись из БД, добавляем к ней 1, и создаем новую запись + file_name = BotDB.get_path_for_audio_record(user_id=message.from_user.id) + file_id = BotDB.get_id_for_audio_record(message.from_user.id) + 1 + path = Path(f'voice_users/{file_name}.ogg') + if path.exists(): + file_name = f'message_from_{message.from_user.id}_number_{file_id}' + else: + pass + #Собираем инфо о сообщении + author_id = message.from_user.id + time_UTC = int(time.time()) + date_added = datetime.fromtimestamp(time_UTC) + #Сохраняем в базку + BotDB.add_audio_record(file_name, author_id, date_added, 0, file_id) + #Сохраняем файл на сервер + file_info = bot.get_file(message.voice.file_id) + downloaded_file = bot.download_file(file_info.file_path) + with open(f'voice_users/{file_name}.ogg', 'wb') as new_file: + new_file.write(downloaded_file) + bot.send_message(chat_id=message.chat.id, text='Окей, сохранил!') + menu_standup(message=message) + else: + msg = bot.send_message(chat_id=message.chat.id, text='Я тебя не понимаю, запиши голосовое') + bot.register_next_step_handler(msg, save_voice_message) def resend_message_in_group_for_post(message): markup = types.InlineKeyboardMarkup(row_width=1) @@ -252,11 +304,11 @@ def telegram_bot(): except: if LOGS: username = message.from_user.first_name - error_message = str(error_message_from_db(5)).replace('username', username) + error_message = str(BotDB.get_error_message_from_db(5)).replace('username', username) bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message) username = message.from_user.first_name - success_send_message = select_message_from_db('success_send_message', username) + success_send_message = BotDB.get_message_from_db('success_send_message', username) bot.send_message(message.chat.id, success_send_message, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK) after_post(message=message) @@ -268,11 +320,11 @@ def telegram_bot(): message_id=message.message_id ) username = message.from_user.first_name - question = select_message_from_db('question', username) + question = BotDB.get_message_from_db('question', username) bot.send_message(message.chat.id, question, parse_mode='html', disable_web_page_preview=not PREVIEW_LINK) except: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message_from_db(4)) + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(4)) after_post(message=message) @@ -285,7 +337,7 @@ def telegram_bot(): bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) except: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message_from_db(3)) + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(3)) elif call.data == 'post_post_post' and call.message.content_type == 'photo': try: bot.send_photo( @@ -296,16 +348,14 @@ def telegram_bot(): bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) except: if LOGS: - bot.send_message(chat_id=IMPORTANT_LOGS, text=error_message_from_db(2)) + bot.send_message(chat_id=IMPORTANT_LOGS, text=BotDB.get_error_message_from_db(2)) elif call.data == 'decline': try: bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) except: if LOGS: - logs(IMPORTANT_LOGS, error_message_from_db(1)) + bot.send_message(IMPORTANT_LOGS, BotDB.get_error_message_from_db(1)) -def logs(chat_name, text_error): - bot.send_message(chat_id=chat_name, text=text_error) if __name__ == '__main__': telegram_bot()