diff --git a/database/db.py b/database/db.py index 9948499..5924137 100644 --- a/database/db.py +++ b/database/db.py @@ -874,6 +874,33 @@ class BotDB: except Exception as e: self.logger.error(f"Ошибка в функции get_post_text_from_telegram_by_last_id {str(e)}") + def get_author_id_by_message_id(self, message_id: int): + self.logger.info(f"Запуск функции get_author_id_by_message_id, идентификатор поста {message_id}") + try: + self.connect() + result = self.cursor.execute("SELECT author_id " + "FROM post_from_telegram_suggest WHERE message_id = ?", + (message_id,)) + author_id = result.fetchone()[0] + self.logger.info(f"Функция get_author_id_by_message_id получила author_id {author_id}") + return author_id + except Exception as e: + self.logger.error(f"Ошибка в функции get_author_id_by_message_id {str(e)}") + + def get_author_id_by_helper_message_id(self, helper_text_message_id: int): + self.logger.info(f"Запуск функции get_author_id_by_helper_message_id, идентификатор поста " + f"{helper_text_message_id}") + try: + self.connect() + result = self.cursor.execute("SELECT author_id " + "FROM post_from_telegram_suggest WHERE helper_text_message_id = ?", + (helper_text_message_id,)) + author_id = result.fetchone()[0] + self.logger.info(f"Функция get_author_id_by_helper_message_id получила author_id {author_id}") + return author_id + except Exception as e: + self.logger.error(f"Ошибка в функции get_author_id_by_helper_message_id {str(e)}") + def add_post_content_in_db(self, post_id: int, message_id: int, content_name: str, type_content: str): self.logger.info( f"Запуск функции add_post_content_in_db: post_id={post_id}, message_id={message_id}, " diff --git a/helper_bot/handlers/admin/admin_handlers.py b/helper_bot/handlers/admin/admin_handlers.py index 917ce95..e83e545 100644 --- a/helper_bot/handlers/admin/admin_handlers.py +++ b/helper_bot/handlers/admin/admin_handlers.py @@ -5,16 +5,14 @@ from aiogram.filters import Command, StateFilter from aiogram.fsm.context import FSMContext from helper_bot.filters.main import ChatTypeFilter -from helper_bot.keyboards.main import get_reply_keyboard_admin, create_keyboard_with_pagination, \ +from helper_bot.keyboards.keyboards import get_reply_keyboard_admin, create_keyboard_with_pagination, \ create_keyboard_for_ban_days, create_keyboard_for_approve_ban from helper_bot.utils.base_dependency_factory import BaseDependencyFactory from helper_bot.utils.helper_func import check_access, add_days_to_date, get_banned_users_buttons, get_banned_users_list from logs.custom_logger import logger - admin_router = Router() - bdf = BaseDependencyFactory() GROUP_FOR_POST = bdf.settings['Telegram']['group_for_posts'] GROUP_FOR_MESSAGE = bdf.settings['Telegram']['group_for_message'] diff --git a/helper_bot/handlers/callback/callback_handlers.py b/helper_bot/handlers/callback/callback_handlers.py index 761867e..2004810 100644 --- a/helper_bot/handlers/callback/callback_handlers.py +++ b/helper_bot/handlers/callback/callback_handlers.py @@ -4,7 +4,7 @@ from aiogram import Router, F from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery -from helper_bot.keyboards.main import create_keyboard_with_pagination, get_reply_keyboard_admin, \ +from helper_bot.keyboards.keyboards import create_keyboard_with_pagination, get_reply_keyboard_admin, \ create_keyboard_for_ban_reason from helper_bot.utils.base_dependency_factory import BaseDependencyFactory from helper_bot.utils.helper_func import send_text_message, send_photo_message, get_banned_users_list, \ @@ -35,7 +35,14 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): f'Получен callback-запрос с действием: {call.data} от пользователя {call.from_user.full_name} (ID сообщения: {call.message.message_id})') if call.message.content_type == 'text' and call.message.text != "^": try: + # Пересылаем сообщение в канал await send_text_message(MAIN_PUBLIC, call.message, call.message.text) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + + # Очищаем предложку и удаляем оттуда пост await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) logger.info(f'Текст сообщения опубликован в канале {MAIN_PUBLIC}.') await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -47,6 +54,12 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): elif call.message.content_type == 'photo': try: await send_photo_message(MAIN_PUBLIC, call.message, call.message.photo[-1].file_id, call.message.caption) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + + # Удаляем пост из предложки await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) logger.info(f'Пост с фото опубликован в канале {MAIN_PUBLIC}.') await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -58,6 +71,11 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): elif call.message.content_type == 'video': try: await send_video_message(MAIN_PUBLIC, call.message, call.message.video.file_id, call.message.caption) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) logger.info(f'Пост с видео опубликован в канале {MAIN_PUBLIC}.') await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -69,6 +87,11 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): elif call.message.content_type == 'video_note': try: await send_video_note_message(MAIN_PUBLIC, call.message, call.message.video_note.file_id) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) logger.info(f'Пост с кружком опубликован в канале {MAIN_PUBLIC}.') await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -80,6 +103,11 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): elif call.message.content_type == 'audio': try: await send_audio_message(MAIN_PUBLIC, call.message, call.message.audio.file_id, call.message.caption) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) logger.info(f'Пост с аудио опубликован в канале {MAIN_PUBLIC}.') await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -91,6 +119,11 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): elif call.message.content_type == 'voice': try: await send_voice_message(MAIN_PUBLIC, call.message, call.message.voice.file_id) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) logger.info(f'Пост с войсом опубликован в канале {MAIN_PUBLIC}.') await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -112,6 +145,11 @@ async def post_for_group(call: CallbackQuery, state: FSMContext): # Выкладываем пост в канал await send_media_group_to_channel(bot=call.bot, chat_id=MAIN_PUBLIC, post_content=post_content, post_text=post_text) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_helper_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был выложен🥰') + # TODO: Удалить фотки с локалки после выкладки? await call.bot.delete_messages(chat_id=GROUP_FOR_POST, message_ids=message_ids) await call.answer(text='Выложено!', show_alert=True, cache_time=3) @@ -124,8 +162,15 @@ async def decline_post_for_group(call: CallbackQuery, state: FSMContext): logger.info( f'Получен callback-запрос с данными: {call.data} от пользователя {call.from_user.full_name} (ID: {call.from_user.id})') try: - if call.message.content_type == 'text' and call.message.text != "^" or call.message.content_type == 'photo': + if call.message.content_type == 'text' and call.message.text != "^" or call.message.content_type == 'photo' \ + or call.message.content_type == 'audio' or call.message.content_type == 'voice' \ + or call.message.content_type == 'video' or call.message.content_type == 'video_note': await call.bot.delete_message(chat_id=GROUP_FOR_POST, message_id=call.message.message_id) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был отклонен😔') + logger.info( f'Сообщение отклонено админом {call.from_user.full_name} (ID: {call.from_user.id}).') await call.answer(text='Отклонено!', show_alert=True, cache_time=3) @@ -135,6 +180,11 @@ async def decline_post_for_group(call: CallbackQuery, state: FSMContext): message_ids.append(call.message.message_id) await call.bot.delete_messages(chat_id=GROUP_FOR_POST, message_ids=message_ids) + + # Получаем из базы автора + отправляем сообщение + удаляем сообщение из предложки + author_id = BotDB.get_author_id_by_helper_message_id(call.message.message_id) + await send_text_message(author_id, call.message, 'Твой пост был отклонен😔') + await call.answer(text='Удалено!', show_alert=True, cache_time=3) except Exception as e: await call.bot.send_message(IMPORTANT_LOGS, diff --git a/helper_bot/handlers/group/group_handlers.py b/helper_bot/handlers/group/group_handlers.py index 3ab82c3..6028d83 100644 --- a/helper_bot/handlers/group/group_handlers.py +++ b/helper_bot/handlers/group/group_handlers.py @@ -2,14 +2,13 @@ from aiogram import Router, types from aiogram.fsm.context import FSMContext from helper_bot.filters.main import ChatTypeFilter -from helper_bot.keyboards.main import get_reply_keyboard_leave_chat +from helper_bot.keyboards.keyboards import get_reply_keyboard_leave_chat from helper_bot.utils.base_dependency_factory import BaseDependencyFactory from helper_bot.utils.helper_func import send_text_message from logs.custom_logger import logger group_router = Router() - bdf = BaseDependencyFactory() GROUP_FOR_POST = bdf.settings['Telegram']['group_for_posts'] GROUP_FOR_MESSAGE = bdf.settings['Telegram']['group_for_message'] diff --git a/helper_bot/handlers/private/private_handlers.py b/helper_bot/handlers/private/private_handlers.py index e0a75e4..fd70cad 100644 --- a/helper_bot/handlers/private/private_handlers.py +++ b/helper_bot/handlers/private/private_handlers.py @@ -11,14 +11,14 @@ from aiogram.types import FSInputFile from helper_bot.filters.main import ChatTypeFilter from helper_bot.keyboards import get_reply_keyboard, get_reply_keyboard_for_post -from helper_bot.keyboards.main import get_reply_keyboard_leave_chat +from helper_bot.keyboards.keyboards import get_reply_keyboard_leave_chat from helper_bot.middlewares.album_middleware import AlbumMiddleware from helper_bot.middlewares.blacklist_middleware import BlacklistMiddleware from helper_bot.utils import messages from helper_bot.utils.base_dependency_factory import BaseDependencyFactory from helper_bot.utils.helper_func import get_first_name, get_text_message, send_text_message, send_photo_message, \ send_media_group_message_to_private_chat, prepare_media_group_from_middlewares, check_username_and_full_name, \ - send_video_message, send_video_note_message, send_audio_message, send_voice_message + send_video_message, send_video_note_message, send_audio_message, send_voice_message, add_in_db_media from logs.custom_logger import logger private_router = Router() @@ -173,7 +173,10 @@ async def suggest_router(message: types.Message, state: FSMContext, album: list markup = get_reply_keyboard_for_post() # Отправляем сообщение в приватный канал - await send_text_message(GROUP_FOR_POST, message, post_text, markup) + sent_message_id = await send_text_message(GROUP_FOR_POST, message, post_text, markup) + + # Записываем в базу пост + BotDB.add_post_in_db(sent_message_id, message.text, message.from_user.id) # Отправляем юзеру ответ, что сообщение отравлено и возвращаем его в меню markup_for_user = get_reply_keyboard(BotDB, message.from_user.id) @@ -182,15 +185,19 @@ async def suggest_router(message: types.Message, state: FSMContext, album: list await state.set_state("START") elif message.content_type == 'photo' and message.media_group_id is None: - lower_caption = message.caption.lower() + if message.caption: + lower_caption = message.caption.lower() + # Получаем текст сообщения и преобразовываем его по правилам + post_caption = get_text_message(lower_caption, message.from_user.full_name, + message.from_user.username) markup = get_reply_keyboard_for_post() - # Получаем текст сообщения и преобразовываем его по правилам - post_caption = get_text_message(lower_caption, message.from_user.full_name, - message.from_user.username) # Отправляем фото и текст в приватный канал - await send_photo_message(GROUP_FOR_POST, message, - message.photo[-1].file_id, post_caption, markup) + sent_message = await send_photo_message(GROUP_FOR_POST, message, + message.photo[-1].file_id, post_caption, markup) + # Записываем в базу пост и контент + BotDB.add_post_in_db(sent_message.message_id, sent_message.caption, message.from_user.id) + await add_in_db_media(sent_message) # Отправляем юзеру ответ и возвращаем его в меню markup_for_user = get_reply_keyboard(BotDB, message.from_user.id) @@ -207,8 +214,16 @@ async def suggest_router(message: types.Message, state: FSMContext, album: list # Получаем текст сообщения и преобразовываем его по правилам # Отправляем видео и текст в приватный канал - await send_video_message(GROUP_FOR_POST, message, - message.video.file_id, post_caption, markup) + sent_message = await send_video_message(GROUP_FOR_POST, message, + message.video.file_id, post_caption, markup) + + # Записываем в базу пост и контент + BotDB.add_post_in_db(sent_message.message_id, sent_message.caption, message.from_user.id) + await add_in_db_media(sent_message) + + # Записываем в базу пост и контент + BotDB.add_post_in_db(sent_message.message_id, sent_message.caption, message.from_user.id) + await add_in_db_media(sent_message) # Отправляем юзеру ответ и возвращаем его в меню markup_for_user = get_reply_keyboard(BotDB, message.from_user.id) @@ -220,8 +235,12 @@ async def suggest_router(message: types.Message, state: FSMContext, album: list markup = get_reply_keyboard_for_post() # Отправляем видеокружок в приватный канал - await send_video_note_message(GROUP_FOR_POST, message, - message.video_note.file_id, markup) + sent_message = await send_video_note_message(GROUP_FOR_POST, message, + message.video_note.file_id, markup) + + # Записываем в базу пост и контент + BotDB.add_post_in_db(sent_message.message_id, sent_message.caption, message.from_user.id) + await add_in_db_media(sent_message) # Отправляем юзеру ответ и возвращаем его в меню markup_for_user = get_reply_keyboard(BotDB, message.from_user.id) @@ -230,15 +249,20 @@ async def suggest_router(message: types.Message, state: FSMContext, album: list await state.set_state("START") elif message.content_type == 'audio' and message.media_group_id is None: - lower_caption = message.caption.lower() + if message.caption: + lower_caption = message.caption.lower() + # Получаем текст сообщения и преобразовываем его по правилам + post_caption = get_text_message(lower_caption, message.from_user.full_name, + message.from_user.username) markup = get_reply_keyboard_for_post() - # Получаем текст сообщения и преобразовываем его по правилам - post_caption = get_text_message(lower_caption, message.from_user.full_name, - message.from_user.username) - # Отправляем видео и текст в приватный канал - await send_audio_message(GROUP_FOR_POST, message, - message.audio.file_id, post_caption, markup) + # Отправляем аудио и текст в приватный канал + sent_message = await send_audio_message(GROUP_FOR_POST, message, + message.audio.file_id, post_caption, markup) + + # Записываем в базу пост и контент + BotDB.add_post_in_db(sent_message.message_id, sent_message.caption, message.from_user.id) + await add_in_db_media(sent_message) # Отправляем юзеру ответ и возвращаем его в меню markup_for_user = get_reply_keyboard(BotDB, message.from_user.id) @@ -249,9 +273,13 @@ async def suggest_router(message: types.Message, state: FSMContext, album: list elif message.content_type == 'voice' and message.media_group_id is None: markup = get_reply_keyboard_for_post() - # Отправляем видео и текст в приватный канал - await send_voice_message(GROUP_FOR_POST, message, - message.voice.file_id, markup) + # Отправляем войс и текст в приватный канал + sent_message = await send_voice_message(GROUP_FOR_POST, message, + message.voice.file_id, markup) + + # Записываем в базу пост и контент + BotDB.add_post_in_db(sent_message.message_id, sent_message.caption, message.from_user.id) + await add_in_db_media(sent_message) # Отправляем юзеру ответ и возвращаем его в меню markup_for_user = get_reply_keyboard(BotDB, message.from_user.id) diff --git a/helper_bot/keyboards/__init__.py b/helper_bot/keyboards/__init__.py index 734fb54..4810ecf 100644 --- a/helper_bot/keyboards/__init__.py +++ b/helper_bot/keyboards/__init__.py @@ -1 +1 @@ -from .main import get_reply_keyboard_for_post, get_reply_keyboard \ No newline at end of file +from .keyboards import get_reply_keyboard_for_post, get_reply_keyboard diff --git a/helper_bot/keyboards/main.py b/helper_bot/keyboards/keyboards.py similarity index 97% rename from helper_bot/keyboards/main.py rename to helper_bot/keyboards/keyboards.py index 1bf7ed6..d2318eb 100644 --- a/helper_bot/keyboards/main.py +++ b/helper_bot/keyboards/keyboards.py @@ -1,110 +1,110 @@ -from aiogram import types -from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder - - -def get_reply_keyboard_for_post(): - builder = InlineKeyboardBuilder() - builder.row(types.InlineKeyboardButton( - text="Опубликовать", callback_data="publish") - ) - builder.row(types.InlineKeyboardButton( - text="Отклонить", callback_data="decline") - ) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup - - -def get_reply_keyboard(BotDB, user_id): - builder = ReplyKeyboardBuilder() - builder.add(types.KeyboardButton(text="📢Предложить свой пост")) - builder.add(types.KeyboardButton(text="📩Связаться с админами")) - builder.add(types.KeyboardButton(text="👋🏼Сказать пока!")) - if not BotDB.get_info_about_stickers(user_id=user_id): - builder.add(types.KeyboardButton(text="🤪Хочу стикеры")) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup - - -def get_reply_keyboard_leave_chat(): - builder = ReplyKeyboardBuilder() - builder.add(types.KeyboardButton(text="Выйти из чата")) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup - - -def get_reply_keyboard_admin(): - builder = ReplyKeyboardBuilder() - builder.add(types.KeyboardButton(text="Бан (Список)")) - builder.add(types.KeyboardButton(text="Разбан (список)")) - builder.add(types.KeyboardButton(text="Вернуться в бота")) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup - - -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 + 9 - 1) // 9 - - # Создаем билдер для клавиатуры - keyboard = InlineKeyboardBuilder() - # Вычисляем стартовый номер для текущей страницы - start_index = (page - 1) * 9 - - # Кнопки с номерами страниц - for i in range(start_index, min(start_index + 9, len(array_items))): - keyboard.add(types.InlineKeyboardButton( - text=f"{array_items[i][0]}", callback_data=f"{callback}_{array_items[i][1]}" - )) - keyboard.adjust(3) - - next_button = types.InlineKeyboardButton( - text="➡️ Следующая", callback_data=f"page_{page + 1}" - ) - prev_button = types.InlineKeyboardButton( - text="⬅️ Предыдущая", callback_data=f"page_{page - 1}" - ) - keyboard.row(prev_button, next_button) - home_button = types.InlineKeyboardButton( - text="🏠 Назад", callback_data="return") - keyboard.row(home_button) - k = keyboard.as_markup() - return k - - -def create_keyboard_for_ban_reason(): - builder = ReplyKeyboardBuilder() - builder.add(types.KeyboardButton(text="Спам")) - builder.add(types.KeyboardButton(text="Заебал стикерами")) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup - - -def create_keyboard_for_ban_days(): - builder = ReplyKeyboardBuilder() - builder.add(types.KeyboardButton(text="1")) - builder.add(types.KeyboardButton(text="7")) - builder.add(types.KeyboardButton(text="30")) - builder.add(types.KeyboardButton(text="Навсегда")) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup - - -def create_keyboard_for_approve_ban(): - builder = ReplyKeyboardBuilder() - builder.add(types.KeyboardButton(text="Подтвердить")) - builder.add(types.KeyboardButton(text="Отменить")) - markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) - return markup +from aiogram import types +from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder + + +def get_reply_keyboard_for_post(): + builder = InlineKeyboardBuilder() + builder.row(types.InlineKeyboardButton( + text="Опубликовать", callback_data="publish") + ) + builder.row(types.InlineKeyboardButton( + text="Отклонить", callback_data="decline") + ) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup + + +def get_reply_keyboard(BotDB, user_id): + builder = ReplyKeyboardBuilder() + builder.add(types.KeyboardButton(text="📢Предложить свой пост")) + builder.add(types.KeyboardButton(text="📩Связаться с админами")) + builder.add(types.KeyboardButton(text="👋🏼Сказать пока!")) + if not BotDB.get_info_about_stickers(user_id=user_id): + builder.add(types.KeyboardButton(text="🤪Хочу стикеры")) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup + + +def get_reply_keyboard_leave_chat(): + builder = ReplyKeyboardBuilder() + builder.add(types.KeyboardButton(text="Выйти из чата")) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup + + +def get_reply_keyboard_admin(): + builder = ReplyKeyboardBuilder() + builder.add(types.KeyboardButton(text="Бан (Список)")) + builder.add(types.KeyboardButton(text="Разбан (список)")) + builder.add(types.KeyboardButton(text="Вернуться в бота")) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup + + +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 + 9 - 1) // 9 + + # Создаем билдер для клавиатуры + keyboard = InlineKeyboardBuilder() + # Вычисляем стартовый номер для текущей страницы + start_index = (page - 1) * 9 + + # Кнопки с номерами страниц + for i in range(start_index, min(start_index + 9, len(array_items))): + keyboard.add(types.InlineKeyboardButton( + text=f"{array_items[i][0]}", callback_data=f"{callback}_{array_items[i][1]}" + )) + keyboard.adjust(3) + + next_button = types.InlineKeyboardButton( + text="➡️ Следующая", callback_data=f"page_{page + 1}" + ) + prev_button = types.InlineKeyboardButton( + text="⬅️ Предыдущая", callback_data=f"page_{page - 1}" + ) + keyboard.row(prev_button, next_button) + home_button = types.InlineKeyboardButton( + text="🏠 Назад", callback_data="return") + keyboard.row(home_button) + k = keyboard.as_markup() + return k + + +def create_keyboard_for_ban_reason(): + builder = ReplyKeyboardBuilder() + builder.add(types.KeyboardButton(text="Спам")) + builder.add(types.KeyboardButton(text="Заебал стикерами")) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup + + +def create_keyboard_for_ban_days(): + builder = ReplyKeyboardBuilder() + builder.add(types.KeyboardButton(text="1")) + builder.add(types.KeyboardButton(text="7")) + builder.add(types.KeyboardButton(text="30")) + builder.add(types.KeyboardButton(text="Навсегда")) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup + + +def create_keyboard_for_approve_ban(): + builder = ReplyKeyboardBuilder() + builder.add(types.KeyboardButton(text="Подтвердить")) + builder.add(types.KeyboardButton(text="Отменить")) + markup = builder.as_markup(resize_keyboard=True, one_time_keyboard=True) + return markup diff --git a/helper_bot/utils/helper_func.py b/helper_bot/utils/helper_func.py index e47146f..db5c44a 100644 --- a/helper_bot/utils/helper_func.py +++ b/helper_bot/utils/helper_func.py @@ -26,9 +26,7 @@ def get_text_message(post_text: str, first_name: str, username: str): username: Юзернейм автора поста Returns: - Кортеж из двух элементов: - - Сформированный текст сообщения. - - Флаг, указывающий, является ли пост анонимным (True - анонимный, False - не анонимный) + str: - Сформированный текст сообщения. """ if "неанон" in post_text or "не анон" in post_text: return f'Пост из ТГ:\n{post_text}\n\nАвтор поста: {first_name} @{username}' @@ -54,6 +52,9 @@ async def download_file(message: types.Message, file_id: str): os.makedirs("files", exist_ok=True) os.makedirs("files/photos", exist_ok=True) os.makedirs("files/videos", exist_ok=True) + os.makedirs("files/music", exist_ok=True) + os.makedirs("files/voice", exist_ok=True) + os.makedirs("files/video_notes", exist_ok=True) file = await message.bot.get_file(file_id) file_path = os.path.join("files", file.file_path) await message.bot.download_file(file_path=file.file_path, destination=file_path) @@ -109,7 +110,7 @@ async def prepare_media_group_from_middlewares(album, post_caption: str = ''): return media_group # Возвращаем MediaGroup -async def add_in_db_media(sent_message): +async def add_in_db_media_mediagroup(sent_message): """ Идентификатор медиа-группы @@ -134,26 +135,34 @@ async def add_in_db_media(sent_message): continue -async def add_in_db_media_old(sent_message): +async def add_in_db_media(sent_message): """ - Идентификатор медиа-группы - Args: sent_message: sent_message объект из Telegram API Returns: - Список InputMediaPhoto. + Список InputFile (FSInputFile). """ - media_group_message_id = sent_message[-1].message_id # Получаем идентификатор медиа-группы - for i, message in enumerate(sent_message): - file_id = message.photo[-1].file_id - file_path = await download_file(message, file_id=file_id) - if i == 0: - BotDB.add_post_content_in_db(media_group_message_id, message.message_id, file_path) - elif i == len(sent_message) - 1: - BotDB.add_post_content_in_db(media_group_message_id, message.message_id, file_path) - else: - BotDB.add_post_content_in_db(media_group_message_id, message.message_id, file_path) + if sent_message.photo: + file_id = sent_message.photo[-1].file_id + file_path = await download_file(sent_message, file_id=file_id) + BotDB.add_post_content_in_db(sent_message.message_id, sent_message.message_id, file_path, 'photo') + elif sent_message.video: + file_id = sent_message.video.file_id + file_path = await download_file(sent_message, file_id=file_id) + BotDB.add_post_content_in_db(sent_message.message_id, sent_message.message_id, file_path, 'video') + elif sent_message.voice: + file_id = sent_message.voice.file_id + file_path = await download_file(sent_message, file_id=file_id) + BotDB.add_post_content_in_db(sent_message.message_id, sent_message.message_id, file_path, 'voice') + elif sent_message.audio: + file_id = sent_message.audio.file_id + file_path = await download_file(sent_message, file_id=file_id) + BotDB.add_post_content_in_db(sent_message.message_id, sent_message.message_id, file_path, 'audio') + elif sent_message.video_note: + file_id = sent_message.video_note.file_id + file_path = await download_file(sent_message, file_id=file_id) + BotDB.add_post_content_in_db(sent_message.message_id, sent_message.message_id, file_path, 'video_note') async def send_media_group_message_to_private_chat(chat_id: int, message: types.Message, @@ -163,7 +172,7 @@ async def send_media_group_message_to_private_chat(chat_id: int, message: types. media=media_group, ) BotDB.add_post_in_db(sent_message[-1].message_id, sent_message[-1].caption, message.from_user.id) - await add_in_db_media(sent_message) + await add_in_db_media_mediagroup(sent_message) message_id = sent_message[-1].message_id return message_id @@ -219,82 +228,87 @@ async def send_text_message(chat_id, message: types.Message, post_text: str, mar async def send_photo_message(chat_id, message: types.Message, photo: str, post_text: str, markup: types.ReplyKeyboardMarkup = None): if markup is None: - await message.bot.send_photo( + sent_message = await message.bot.send_photo( chat_id=chat_id, caption=post_text, photo=photo ) else: - await message.bot.send_photo( + sent_message = await message.bot.send_photo( chat_id=chat_id, caption=post_text, photo=photo, reply_markup=markup ) + return sent_message async def send_video_message(chat_id, message: types.Message, video: str, post_text: str = "", markup: types.ReplyKeyboardMarkup = None): if markup is None: - await message.bot.send_video( + sent_message = await message.bot.send_video( chat_id=chat_id, caption=post_text, video=video ) else: - await message.bot.send_video( + sent_message = await message.bot.send_video( chat_id=chat_id, caption=post_text, video=video, reply_markup=markup ) + return sent_message async def send_video_note_message(chat_id, message: types.Message, video_note: str, markup: types.ReplyKeyboardMarkup = None): if markup is None: - await message.bot.send_video_note( + sent_message = await message.bot.send_video_note( chat_id=chat_id, video_note=video_note ) else: - await message.bot.send_video_note( + sent_message = await message.bot.send_video_note( chat_id=chat_id, video_note=video_note, reply_markup=markup ) + return sent_message async def send_audio_message(chat_id, message: types.Message, audio: str, post_text: str, markup: types.ReplyKeyboardMarkup = None): if markup is None: - await message.bot.send_audio( + sent_message = await message.bot.send_audio( chat_id=chat_id, caption=post_text, audio=audio ) else: - await message.bot.send_audio( + sent_message = await message.bot.send_audio( chat_id=chat_id, caption=post_text, audio=audio, reply_markup=markup ) + return sent_message async def send_voice_message(chat_id, message: types.Message, voice: str, markup: types.ReplyKeyboardMarkup = None): if markup is None: - await message.bot.send_voice( + sent_message = await message.bot.send_voice( chat_id=chat_id, voice=voice ) else: - await message.bot.send_voice( + sent_message = await message.bot.send_voice( chat_id=chat_id, voice=voice, reply_markup=markup ) + return sent_message def check_access(user_id: int): diff --git a/tests/test_db.py b/tests/test_db.py index ff0eba5..56489a8 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -1,13 +1,17 @@ -from datetime import datetime import os import sqlite3 +from datetime import datetime + import pytest + from database.db import BotDB + @pytest.fixture def bot(): """Фикстура для создания объекта BotDB.""" - return BotDB("test.db") + current_dir = os.getcwd() + return BotDB(current_dir, "test.db") @pytest.fixture(autouse=True, ) @@ -104,12 +108,12 @@ def setup_db(): ); """) - #blacklist mock data + # blacklist mock data cursor.execute("INSERT INTO blacklist (user_id, user_name, message_for_user, date_to_unban) VALUES (?, ?, ?, ?)", (user_id, username, message_for_user, next_date)) cursor.execute("INSERT INTO blacklist (user_id, user_name, message_for_user, date_to_unban) VALUES (?, ?, ?, ?)", (user_id_2, username_2, message_for_user_2, date)) - #our_users mock data + # our_users mock data cursor.execute( "INSERT INTO our_users (user_id, first_name, full_name, username, date_added, date_changed, has_stickers)" " VALUES (?, ?, ?, ?, ?, ?, ?)", (user_id, first_name, full_name, username, date, date, has_stickers) @@ -118,7 +122,7 @@ def setup_db(): "INSERT INTO our_users (user_id, first_name, full_name, username, date_added, date_changed, has_stickers)" " VALUES (?, ?, ?, ?, ?, ?, ?)", (user_id_2, first_name_2, full_name_2, username_2, date, date, has_stickers_2) ) - #messages mock data + # messages mock data cursor.execute( "INSERT INTO user_messages (message_text, user_id, message_id, date) " "VALUES (?, ?, ?, ?)", @@ -127,7 +131,7 @@ def setup_db(): "INSERT INTO user_messages (message_text, user_id, message_id, date) " "VALUES (?, ?, ?, ?)", (message_text_2, user_id_2, message_id_2, date)) - #mock admins + # mock admins cursor.execute( "INSERT INTO admins (user_id, role) " "VALUES (?, ?)",