From ef9c45250f7aa4a31a7fc7077eaeda92a1d7214b Mon Sep 17 00:00:00 2001 From: Sabina Date: Tue, 20 Jun 2023 22:41:44 +0300 Subject: [PATCH 1/5] Tasks pagination added --- src/bot/handlers/tasks.py | 36 ++++++++++++++++++++++++++++++---- src/bot/services/task.py | 5 +++++ src/core/db/repository/task.py | 4 ++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/bot/handlers/tasks.py b/src/bot/handlers/tasks.py index 16ee1c5a..21d84d19 100644 --- a/src/bot/handlers/tasks.py +++ b/src/bot/handlers/tasks.py @@ -1,4 +1,4 @@ -from telegram import Update +from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram.constants import ParseMode from telegram.ext import Application, CallbackContext, CallbackQueryHandler, ContextTypes @@ -65,16 +65,44 @@ async def back_subcategory_callback(update: Update, context: ContextTypes.DEFAUL @logger_decor -async def view_task_callback(update: Update, context: CallbackContext, limit: int = 3): +async def view_task_callback(update: Update, context: CallbackContext): task_service = TaskService() - tasks = await task_service.get_user_tasks(limit) + tasks = await task_service.get_all_user_tasks() + tasks = tasks.all() - for task in tasks: + page_number = context.user_data.get("page_number", 1) + start = (page_number - 1) * 3 + finish = page_number * 3 + tasks_to_show = tasks[start:finish] + + for task in tasks_to_show: message = display_tasks(task) await context.bot.send_message( chat_id=update.effective_chat.id, text=message, parse_mode=ParseMode.HTML, disable_web_page_preview=True ) + await show_next_tasks(update, context, tasks, page_number) + + +async def show_next_tasks(update: Update, context: CallbackContext, tasks, page_number: int): + if len(tasks) > page_number * 3: + text = "Есть ещё задания, показать?" + context.user_data["page_number"] = page_number + 1 + buttons = [ + [InlineKeyboardButton(text="Показать ещё задания", callback_data=callback_data.VIEW_TASKS)], + [InlineKeyboardButton(text="Открыть меню", callback_data=callback_data.MENU)], + ] + else: + text = "Заданий больше нет." + buttons = [[InlineKeyboardButton(text="Открыть меню", callback_data=callback_data.MENU)]] + + keyboard = InlineKeyboardMarkup(buttons) + await context.bot.send_message( + chat_id=update.effective_chat.id, + text=text, + reply_markup=keyboard, + ) + def init_app(app: Application): app.add_handler(CallbackQueryHandler(subcategories_callback, pattern=patterns.SUBCATEGORIES)) diff --git a/src/bot/services/task.py b/src/bot/services/task.py index d46d0a26..c82a7d7f 100644 --- a/src/bot/services/task.py +++ b/src/bot/services/task.py @@ -18,3 +18,8 @@ async def get_user_tasks(self, limit: int) -> list[Task]: async with self._sessionmaker() as session: repository = TaskRepository(session) return await repository.get_user_tasks(limit) + + async def get_all_user_tasks(self) -> list[Task]: + async with self._sessionmaker() as session: + repository = TaskRepository(session) + return await repository.get_all_user_tasks() diff --git a/src/core/db/repository/task.py b/src/core/db/repository/task.py index aa8d140d..f473a748 100644 --- a/src/core/db/repository/task.py +++ b/src/core/db/repository/task.py @@ -22,3 +22,7 @@ async def get_tasks_for_user(self, user_id: int) -> list[Task]: async def get_user_tasks(self, limit: int) -> list[Task]: """Получить список задач из категорий.""" return await self._session.scalars(select(Task).options(joinedload(Task.category)).limit(limit)) + + async def get_all_user_tasks(self) -> list[Task]: + """Получить список задач из категорий.""" + return await self._session.scalars(select(Task).options(joinedload(Task.category))) From 6bd9e9cc9cee90e7db2db235ffcb20910733a13a Mon Sep 17 00:00:00 2001 From: Sabina Date: Fri, 23 Jun 2023 14:43:39 +0300 Subject: [PATCH 2/5] Add keyboards and task service --- src/bot/handlers/tasks.py | 28 ++++++++++++---------------- src/bot/keyboards.py | 8 ++++++++ src/bot/services/task.py | 10 +++++++++- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/bot/handlers/tasks.py b/src/bot/handlers/tasks.py index 21d84d19..600356b6 100644 --- a/src/bot/handlers/tasks.py +++ b/src/bot/handlers/tasks.py @@ -1,9 +1,14 @@ -from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update +from telegram import Update from telegram.constants import ParseMode from telegram.ext import Application, CallbackContext, CallbackQueryHandler, ContextTypes from src.bot.constants import callback_data, patterns -from src.bot.keyboards import get_categories_keyboard, get_subcategories_keyboard +from src.bot.keyboards import ( + get_back_menu, + get_categories_keyboard, + get_subcategories_keyboard, + view_more_tasks_keyboard, +) from src.bot.services.category import CategoryService from src.bot.services.task import TaskService from src.core.logging.utils import logger_decor @@ -65,15 +70,10 @@ async def back_subcategory_callback(update: Update, context: ContextTypes.DEFAUL @logger_decor -async def view_task_callback(update: Update, context: CallbackContext): +async def view_task_callback(update: Update, context: CallbackContext, limit: int = 3): task_service = TaskService() tasks = await task_service.get_all_user_tasks() - tasks = tasks.all() - - page_number = context.user_data.get("page_number", 1) - start = (page_number - 1) * 3 - finish = page_number * 3 - tasks_to_show = tasks[start:finish] + tasks_to_show, page_number = await task_service.get_user_tasks_by_page(tasks, context, limit) for task in tasks_to_show: message = display_tasks(task) @@ -88,15 +88,11 @@ async def show_next_tasks(update: Update, context: CallbackContext, tasks, page_ if len(tasks) > page_number * 3: text = "Есть ещё задания, показать?" context.user_data["page_number"] = page_number + 1 - buttons = [ - [InlineKeyboardButton(text="Показать ещё задания", callback_data=callback_data.VIEW_TASKS)], - [InlineKeyboardButton(text="Открыть меню", callback_data=callback_data.MENU)], - ] + keyboard = await view_more_tasks_keyboard() else: text = "Заданий больше нет." - buttons = [[InlineKeyboardButton(text="Открыть меню", callback_data=callback_data.MENU)]] + keyboard = await get_back_menu() - keyboard = InlineKeyboardMarkup(buttons) await context.bot.send_message( chat_id=update.effective_chat.id, text=text, @@ -104,7 +100,7 @@ async def show_next_tasks(update: Update, context: CallbackContext, tasks, page_ ) -def init_app(app: Application): +def registration_handlers(app: Application): app.add_handler(CallbackQueryHandler(subcategories_callback, pattern=patterns.SUBCATEGORIES)) app.add_handler(CallbackQueryHandler(select_subcategory_callback, pattern=patterns.SELECT_CATEGORY)) app.add_handler(CallbackQueryHandler(back_subcategory_callback, pattern=patterns.BACK_SUBCATEGORY)) diff --git a/src/bot/keyboards.py b/src/bot/keyboards.py index e890eb34..fafd691f 100644 --- a/src/bot/keyboards.py +++ b/src/bot/keyboards.py @@ -74,6 +74,14 @@ async def get_start_keyboard(telegram_id: int) -> InlineKeyboardMarkup: return InlineKeyboardMarkup(keyboard) +async def view_more_tasks_keyboard() -> InlineKeyboardMarkup: + keyboard = [ + [InlineKeyboardButton(text="Показать ещё задания", callback_data=callback_data.VIEW_TASKS)], + [InlineKeyboardButton(text="Открыть меню", callback_data=callback_data.MENU)], + ] + return InlineKeyboardMarkup(keyboard) + + def get_confirm_keyboard() -> InlineKeyboardMarkup: keyboard = [ [InlineKeyboardButton("Да", callback_data=callback_data.CONFIRM_CATEGORIES)], diff --git a/src/bot/services/task.py b/src/bot/services/task.py index c82a7d7f..4042e7e5 100644 --- a/src/bot/services/task.py +++ b/src/bot/services/task.py @@ -22,4 +22,12 @@ async def get_user_tasks(self, limit: int) -> list[Task]: async def get_all_user_tasks(self) -> list[Task]: async with self._sessionmaker() as session: repository = TaskRepository(session) - return await repository.get_all_user_tasks() + tasks = await repository.get_all_user_tasks() + return tasks.all() + + async def get_user_tasks_by_page(self, tasks, context, limit: int): + page_number = context.user_data.get("page_number", 1) + start = (page_number - 1) * limit + finish = page_number * limit + tasks_to_show = tasks[start:finish] + return tasks_to_show, page_number From f861e4ceb7ea5137e70ff7ea138c1715657edb5e Mon Sep 17 00:00:00 2001 From: Sabina Date: Thu, 29 Jun 2023 17:24:01 +0300 Subject: [PATCH 3/5] Add offset into tasks function logic --- src/bot/handlers/tasks.py | 16 ++++++++++------ src/bot/services/task.py | 16 ++++------------ src/core/db/repository/task.py | 21 ++++++++++++++------- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/bot/handlers/tasks.py b/src/bot/handlers/tasks.py index 600356b6..9f8dae6b 100644 --- a/src/bot/handlers/tasks.py +++ b/src/bot/handlers/tasks.py @@ -72,21 +72,25 @@ async def back_subcategory_callback(update: Update, context: ContextTypes.DEFAUL @logger_decor async def view_task_callback(update: Update, context: CallbackContext, limit: int = 3): task_service = TaskService() - tasks = await task_service.get_all_user_tasks() - tasks_to_show, page_number = await task_service.get_user_tasks_by_page(tasks, context, limit) + page_number = context.user_data.get("page_number", 1) + offset = (page_number - 1) * limit + tasks_to_show = await task_service.get_user_tasks_by_page(limit, offset) for task in tasks_to_show: message = display_tasks(task) await context.bot.send_message( chat_id=update.effective_chat.id, text=message, parse_mode=ParseMode.HTML, disable_web_page_preview=True ) + await show_next_tasks(update, context, limit, offset, page_number) - await show_next_tasks(update, context, tasks, page_number) +async def show_next_tasks(update: Update, context: CallbackContext, limit: int, offset: int, page_number: int): + task_service = TaskService() + total_tasks = await task_service.get_user_tasks_count() + remaining_tasks = total_tasks - (offset + limit) -async def show_next_tasks(update: Update, context: CallbackContext, tasks, page_number: int): - if len(tasks) > page_number * 3: - text = "Есть ещё задания, показать?" + if remaining_tasks > 0: + text = f"Есть ещё задания, показать? Осталось: {remaining_tasks}" context.user_data["page_number"] = page_number + 1 keyboard = await view_more_tasks_keyboard() else: diff --git a/src/bot/services/task.py b/src/bot/services/task.py index 4042e7e5..3eb0a614 100644 --- a/src/bot/services/task.py +++ b/src/bot/services/task.py @@ -14,20 +14,12 @@ class TaskService: def __init__(self, sessionmaker: Generator[AsyncSession, None, None] = get_session): self._sessionmaker = contextlib.asynccontextmanager(sessionmaker) - async def get_user_tasks(self, limit: int) -> list[Task]: + async def get_user_tasks_by_page(self, limit: int, offset: int) -> list[Task]: async with self._sessionmaker() as session: repository = TaskRepository(session) - return await repository.get_user_tasks(limit) + return await repository.get_tasks_limit_for_user(limit, offset) - async def get_all_user_tasks(self) -> list[Task]: + async def get_user_tasks_count(self) -> int: async with self._sessionmaker() as session: repository = TaskRepository(session) - tasks = await repository.get_all_user_tasks() - return tasks.all() - - async def get_user_tasks_by_page(self, tasks, context, limit: int): - page_number = context.user_data.get("page_number", 1) - start = (page_number - 1) * limit - finish = page_number * limit - tasks_to_show = tasks[start:finish] - return tasks_to_show, page_number + return await repository.get_user_tasks_count() diff --git a/src/core/db/repository/task.py b/src/core/db/repository/task.py index f473a748..083b40dc 100644 --- a/src/core/db/repository/task.py +++ b/src/core/db/repository/task.py @@ -14,15 +14,22 @@ class TaskRepository(ContentRepository): def __init__(self, session: AsyncSession = Depends(get_session)) -> None: super().__init__(session, Task) - async def get_tasks_for_user(self, user_id: int) -> list[Task]: + async def get_tasks_for_user(self, user_id: int, limit: int, offset: int) -> list[Task]: """Получить список задач из категорий на которые подписан пользователь.""" - tasks = await self._session.execute(select(Task).join(Category).where(Category.users.any(id=user_id))) + tasks = await self._session.execute( + select(Task).join(Category).where(Category.users.any(id=user_id)).limit(limit).offset(offset) + ) return tasks.scalars().all() - async def get_user_tasks(self, limit: int) -> list[Task]: - """Получить список задач из категорий.""" - return await self._session.scalars(select(Task).options(joinedload(Task.category)).limit(limit)) - async def get_all_user_tasks(self) -> list[Task]: - """Получить список задач из категорий.""" + """Получить список задач из категорий на которые подписан пользователь.""" return await self._session.scalars(select(Task).options(joinedload(Task.category))) + + async def get_tasks_limit_for_user(self, limit: int, offset: int) -> list[Task]: + """Получить limit-выборку из списка всех задач пользователя.""" + return await self._session.scalars(select(Task).options(joinedload(Task.category)).limit(limit).offset(offset)) + + async def get_user_tasks_count(self) -> int: + """Получить общее количество задач для пользователя.""" + tasks = await self._session.scalars(select(Task).options(joinedload(Task.category))) + return len(tasks.all()) From cdfd62ffee018479b7c9910f803f3181b5afbeeb Mon Sep 17 00:00:00 2001 From: Sabina Date: Sat, 1 Jul 2023 23:55:11 +0300 Subject: [PATCH 4/5] Service --- src/bot/handlers/tasks.py | 8 +++----- src/bot/services/task.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/bot/handlers/tasks.py b/src/bot/handlers/tasks.py index 9f8dae6b..a038d69a 100644 --- a/src/bot/handlers/tasks.py +++ b/src/bot/handlers/tasks.py @@ -72,9 +72,8 @@ async def back_subcategory_callback(update: Update, context: ContextTypes.DEFAUL @logger_decor async def view_task_callback(update: Update, context: CallbackContext, limit: int = 3): task_service = TaskService() - page_number = context.user_data.get("page_number", 1) - offset = (page_number - 1) * limit - tasks_to_show = await task_service.get_user_tasks_by_page(limit, offset) + user_data = context.user_data + tasks_to_show, offset, page_number = await task_service.get_user_tasks_by_page(user_data, limit) for task in tasks_to_show: message = display_tasks(task) @@ -86,8 +85,7 @@ async def view_task_callback(update: Update, context: CallbackContext, limit: in async def show_next_tasks(update: Update, context: CallbackContext, limit: int, offset: int, page_number: int): task_service = TaskService() - total_tasks = await task_service.get_user_tasks_count() - remaining_tasks = total_tasks - (offset + limit) + remaining_tasks = await task_service.get_remaining_user_tasks_count(limit, offset) if remaining_tasks > 0: text = f"Есть ещё задания, показать? Осталось: {remaining_tasks}" diff --git a/src/bot/services/task.py b/src/bot/services/task.py index 3eb0a614..1df671f0 100644 --- a/src/bot/services/task.py +++ b/src/bot/services/task.py @@ -14,12 +14,16 @@ class TaskService: def __init__(self, sessionmaker: Generator[AsyncSession, None, None] = get_session): self._sessionmaker = contextlib.asynccontextmanager(sessionmaker) - async def get_user_tasks_by_page(self, limit: int, offset: int) -> list[Task]: + async def get_user_tasks_by_page(self, user_data: dict, limit: int) -> list[Task]: + page_number = user_data.get("page_number", 1) + offset = (page_number - 1) * limit async with self._sessionmaker() as session: repository = TaskRepository(session) - return await repository.get_tasks_limit_for_user(limit, offset) + return await repository.get_tasks_limit_for_user(limit, offset), offset, page_number - async def get_user_tasks_count(self) -> int: + async def get_remaining_user_tasks_count(self, limit: int, offset: int) -> int: async with self._sessionmaker() as session: repository = TaskRepository(session) - return await repository.get_user_tasks_count() + total_tasks = await repository.get_user_tasks_count() + remaining_tasks = total_tasks - (offset + limit) + return remaining_tasks From 84f4c099d6b35ed917b92d6c7ad7f7ede01dfa6e Mon Sep 17 00:00:00 2001 From: Sabina Date: Mon, 3 Jul 2023 17:34:10 +0300 Subject: [PATCH 5/5] Another commit --- src/bot/handlers/tasks.py | 5 +++-- src/bot/services/task.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bot/handlers/tasks.py b/src/bot/handlers/tasks.py index a038d69a..6d4d2f74 100644 --- a/src/bot/handlers/tasks.py +++ b/src/bot/handlers/tasks.py @@ -72,8 +72,9 @@ async def back_subcategory_callback(update: Update, context: ContextTypes.DEFAUL @logger_decor async def view_task_callback(update: Update, context: CallbackContext, limit: int = 3): task_service = TaskService() - user_data = context.user_data - tasks_to_show, offset, page_number = await task_service.get_user_tasks_by_page(user_data, limit) + tasks_to_show, offset, page_number = await task_service.get_user_tasks_by_page( + context.user_data.get("page_number", 1), limit + ) for task in tasks_to_show: message = display_tasks(task) diff --git a/src/bot/services/task.py b/src/bot/services/task.py index 1df671f0..1d9f4e33 100644 --- a/src/bot/services/task.py +++ b/src/bot/services/task.py @@ -14,8 +14,7 @@ class TaskService: def __init__(self, sessionmaker: Generator[AsyncSession, None, None] = get_session): self._sessionmaker = contextlib.asynccontextmanager(sessionmaker) - async def get_user_tasks_by_page(self, user_data: dict, limit: int) -> list[Task]: - page_number = user_data.get("page_number", 1) + async def get_user_tasks_by_page(self, page_number, limit: int) -> list[Task]: offset = (page_number - 1) * limit async with self._sessionmaker() as session: repository = TaskRepository(session)