Implement user-specific question numbering and update database schema. Added triggers for automatic question numbering and adjustments upon deletion. Enhanced CRUD operations to manage user_question_number effectively.

This commit is contained in:
2025-09-06 18:35:12 +03:00
parent 50be010026
commit 596a2fa813
111 changed files with 16847 additions and 65 deletions

View File

@@ -0,0 +1,185 @@
"""
Сервис для работы с пагинацией
"""
from typing import Any, List, Optional, Tuple
from aiogram.types import InlineKeyboardMarkup
from config.constants import DEFAULT_PAGE_SIZE, MIN_PAGE_NUMBER
from services.infrastructure.logger import get_logger
logger = get_logger(__name__)
class PaginationService:
"""Сервис для работы с пагинацией"""
def __init__(self):
pass
async def calculate_pagination_from_db(
self,
total_count: int,
page: int,
per_page: int = DEFAULT_PAGE_SIZE
) -> Tuple[int, int, int, int]:
"""
Расчет пагинации на основе общего количества записей в БД
Args:
total_count: Общее количество записей в БД
page: Номер страницы (начиная с 0)
per_page: Количество элементов на странице
Returns:
Кортеж (общееоличество, текущая_страница, общееоличество_страниц, offset)
"""
try:
total_pages = (total_count + per_page - 1) // per_page # Округление вверх
# Проверяем корректность номера страницы
if page < MIN_PAGE_NUMBER:
page = MIN_PAGE_NUMBER
elif page >= total_pages and total_pages > 0:
page = total_pages - 1
# Вычисляем offset для БД
offset = page * per_page
return total_count, page, total_pages, offset
except Exception as e:
logger.error(f"Ошибка при расчете пагинации из БД: {e}")
return MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER
def calculate_pagination(
self,
items: List[Any],
page: int,
per_page: int = DEFAULT_PAGE_SIZE
) -> Tuple[List[Any], int, int, int]:
"""
Расчет пагинации для списка элементов
Args:
items: Список элементов
page: Номер страницы (начиная с 0)
per_page: Количество элементов на странице
Returns:
Кортеж (элементы_страницы, общееоличество, текущая_страница, общееоличество_страниц)
"""
try:
total_items = len(items)
total_pages = (total_items + per_page - 1) // per_page # Округление вверх
# Проверяем корректность номера страницы
if page < MIN_PAGE_NUMBER:
page = MIN_PAGE_NUMBER
elif page >= total_pages and total_pages > 0:
page = total_pages - 1
# Вычисляем диапазон элементов для текущей страницы
start_idx = page * per_page
end_idx = min(start_idx + per_page, total_items)
page_items = items[start_idx:end_idx]
return page_items, total_items, page, total_pages
except Exception as e:
logger.error(f"Ошибка при расчете пагинации: {e}")
return [], MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER
def format_pagination_info(
self,
current_page: int,
total_pages: int,
start_idx: int,
end_idx: int,
total_items: int
) -> str:
"""
Форматирование информации о пагинации
Args:
current_page: Текущая страница
total_pages: Общее количество страниц
start_idx: Начальный индекс
end_idx: Конечный индекс
total_items: Общее количество элементов
Returns:
Отформатированная строка с информацией о пагинации
"""
try:
info = f"📊 Показано {start_idx + 1}-{end_idx} из {total_items}\n"
info += f"📄 Страница {current_page + 1} из {total_pages}\n\n"
return info
except Exception as e:
logger.error(f"Ошибка при форматировании информации о пагинации: {e}")
return ""
def get_pagination_buttons(
self,
current_page: int,
total_pages: int,
callback_prefix: str,
additional_buttons: Optional[List[Tuple[str, str]]] = None
) -> List[Tuple[str, str]]:
"""
Получение кнопок пагинации
Args:
current_page: Текущая страница
total_pages: Общее количество страниц
callback_prefix: Префикс для callback_data
additional_buttons: Дополнительные кнопки
Returns:
Список кортежей (текст_кнопки, callback_data)
"""
try:
buttons = []
# Кнопка "Предыдущая"
if current_page > MIN_PAGE_NUMBER:
buttons.append(("⬅️", f"{callback_prefix}_page_{current_page - 1}"))
# Кнопка "Следующая"
if current_page < total_pages - 1:
buttons.append(("➡️", f"{callback_prefix}_page_{current_page + 1}"))
# Дополнительные кнопки
if additional_buttons:
buttons.extend(additional_buttons)
return buttons
except Exception as e:
logger.error(f"Ошибка при создании кнопок пагинации: {e}")
return []
def validate_page_number(self, page: int, total_pages: int) -> int:
"""
Валидация номера страницы
Args:
page: Номер страницы
total_pages: Общее количество страниц
Returns:
Валидный номер страницы
"""
try:
if page < 0:
return 0
elif page >= total_pages and total_pages > 0:
return total_pages - 1
else:
return page
except Exception as e:
logger.error(f"Ошибка при валидации номера страницы: {e}")
return MIN_PAGE_NUMBER