add ruff format, ruff check, time_picker, project structure and imports reorganized
This commit is contained in:
@@ -1,345 +0,0 @@
|
||||
from types import NoneType, UnionType
|
||||
from aiogram import Router, F
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from babel.support import LazyProxy
|
||||
from inspect import signature
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
from typing import Any, get_args, get_origin, TYPE_CHECKING
|
||||
import ujson as json
|
||||
|
||||
|
||||
from ..context import ContextData, CallbackCommand, CommandContext
|
||||
from ...command_context_filter import CallbackCommandFilter
|
||||
from ....model.user import UserBase
|
||||
from ....model.settings import Settings
|
||||
from ....model.bot_entity import BotEntity
|
||||
from ....model.bot_enum import BotEnum
|
||||
from ....model.view_setting import ViewSetting
|
||||
from ....utils import get_local_text, deserialize
|
||||
from ....model.descriptors import (EntityFieldDescriptor,
|
||||
EntityDescriptor,
|
||||
EntityCaptionCallable,
|
||||
EntityItemCaptionCallable,
|
||||
EntityFieldCaptionCallable)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
def get_send_message(message: Message | CallbackQuery):
|
||||
if isinstance(message, Message):
|
||||
return message.answer
|
||||
else:
|
||||
return message.message.edit_text
|
||||
|
||||
|
||||
# def get_local_text(text: str, lang: str):
|
||||
# try:
|
||||
# text_obj = json.loads(text) #@IgnoreException
|
||||
# return text_obj.get(lang, text_obj[list(text_obj.keys())[0]])
|
||||
# except:
|
||||
# return text
|
||||
|
||||
|
||||
def get_value_repr(value: Any, field_descriptor: EntityFieldDescriptor, locale: str | None = None) -> str:
|
||||
|
||||
type_ = field_descriptor.type_base
|
||||
if value is None:
|
||||
return ""
|
||||
|
||||
if isinstance(value, bool):
|
||||
return "【✔︎】" if value else "【 】"
|
||||
elif field_descriptor.is_list:
|
||||
if issubclass(type_, BotEntity):
|
||||
if locale and type_.bot_entity_descriptor.fields_descriptors["name"].localizable:
|
||||
return "[" + ", ".join([get_local_text(text = item.name, locale = locale) for item in value]) + "]"
|
||||
else:
|
||||
return "[" + ", ".join([str(item.name) for item in value]) + "]"
|
||||
elif issubclass(type_, BotEnum):
|
||||
return "[" + ", ".join(item.localized(locale) for item in value) + "]"
|
||||
elif type_ == str:
|
||||
return "[" + ", ".join([f"\"{item}\"" for item in value]) + "]"
|
||||
else:
|
||||
return "[" + ", ".join([str(item) for item in value]) + "]"
|
||||
elif issubclass(type_, BotEntity):
|
||||
if type_.bot_entity_descriptor.fields_descriptors["name"].localizable:
|
||||
return get_local_text(text = value.name, locale = locale)
|
||||
return value.name
|
||||
elif issubclass(type_, BotEnum):
|
||||
return value.localized(locale)
|
||||
elif isinstance(value, str):
|
||||
if field_descriptor and field_descriptor.localizable:
|
||||
return get_local_text(text = value, locale = locale)
|
||||
return value
|
||||
elif isinstance(value, int):
|
||||
return str(value)
|
||||
elif isinstance(value, float):
|
||||
return str(value)
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
|
||||
def get_callable_str(callable_str: str | LazyProxy | EntityCaptionCallable | EntityItemCaptionCallable | EntityFieldCaptionCallable,
|
||||
descriptor: EntityFieldDescriptor | EntityDescriptor,
|
||||
entity: Any = None,
|
||||
value: Any = None) -> str:
|
||||
|
||||
if isinstance(callable_str, str):
|
||||
return callable_str
|
||||
elif isinstance(callable_str, LazyProxy):
|
||||
return callable_str.value
|
||||
elif callable(callable_str):
|
||||
args = signature(callable_str).parameters
|
||||
if len(args) == 1:
|
||||
return callable_str(descriptor)
|
||||
elif len(args) == 2:
|
||||
return callable_str(descriptor, entity)
|
||||
elif len(args) == 3:
|
||||
return callable_str(descriptor, entity, value)
|
||||
|
||||
|
||||
async def authorize_command(user: UserBase,
|
||||
callback_data: ContextData):
|
||||
|
||||
if (callback_data.command == CallbackCommand.MENU_ENTRY_PARAMETERS or
|
||||
callback_data.context == CommandContext.SETTING_EDIT):
|
||||
allowed_roles = (await Settings.get(Settings.SECURITY_PARAMETERS_ROLES))
|
||||
return any(role in user.roles for role in allowed_roles)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_entity_descriptor(app: "QBotApp", callback_data: ContextData) -> EntityDescriptor | None:
|
||||
|
||||
if callback_data.entity_name:
|
||||
return app.entity_metadata.entity_descriptors[callback_data.entity_name]
|
||||
return None
|
||||
|
||||
|
||||
def get_field_descriptor(app: "QBotApp", callback_data: ContextData) -> EntityFieldDescriptor | None:
|
||||
|
||||
if callback_data.context == CommandContext.SETTING_EDIT:
|
||||
return Settings.list_params()[callback_data.field_name]
|
||||
elif callback_data.context in [CommandContext.ENTITY_CREATE, CommandContext.ENTITY_EDIT, CommandContext.ENTITY_FIELD_EDIT]:
|
||||
entity_descriptor = get_entity_descriptor(app, callback_data)
|
||||
if entity_descriptor:
|
||||
return entity_descriptor.fields_descriptors.get(callback_data.field_name)
|
||||
return None
|
||||
|
||||
|
||||
def add_pagination_controls(keyboard_builder: InlineKeyboardBuilder,
|
||||
callback_data: ContextData,
|
||||
total_pages: int,
|
||||
command: CallbackCommand,
|
||||
page: int):
|
||||
|
||||
if total_pages > 1:
|
||||
navigation_buttons = []
|
||||
ContextData(**callback_data.model_dump()).__setattr__
|
||||
if total_pages > 10:
|
||||
navigation_buttons.append(InlineKeyboardButton(text = "⏮️",
|
||||
callback_data = ContextData(
|
||||
command = command,
|
||||
context = callback_data.context,
|
||||
entity_name = callback_data.entity_name,
|
||||
entity_id = callback_data.entity_id,
|
||||
field_name = callback_data.field_name,
|
||||
data = "1" if page != 1 else "skip",
|
||||
save_state = True).pack()))
|
||||
navigation_buttons.append(InlineKeyboardButton(text = "⏪️",
|
||||
callback_data = ContextData(
|
||||
command = command,
|
||||
context = callback_data.context,
|
||||
entity_name = callback_data.entity_name,
|
||||
entity_id = callback_data.entity_id,
|
||||
field_name = callback_data.field_name,
|
||||
data = str(max(page - 10, 1)) if page > 1 else "skip",
|
||||
save_state = True).pack()))
|
||||
|
||||
navigation_buttons.append(InlineKeyboardButton(text = f"◀️",
|
||||
callback_data = ContextData(
|
||||
command = command,
|
||||
context = callback_data.context,
|
||||
entity_name = callback_data.entity_name,
|
||||
entity_id = callback_data.entity_id,
|
||||
field_name = callback_data.field_name,
|
||||
data = str(max(page - 1, 1)) if page > 1 else "skip",
|
||||
save_state = True).pack()))
|
||||
navigation_buttons.append(InlineKeyboardButton(text = f"▶️",
|
||||
callback_data = ContextData(
|
||||
command = command,
|
||||
context = callback_data.context,
|
||||
entity_name = callback_data.entity_name,
|
||||
entity_id = callback_data.entity_id,
|
||||
field_name = callback_data.field_name,
|
||||
data = str(min(page + 1, total_pages)) if page < total_pages else "skip",
|
||||
save_state = True).pack()))
|
||||
|
||||
if total_pages > 10:
|
||||
navigation_buttons.append(InlineKeyboardButton(text = "⏩️",
|
||||
callback_data = ContextData(
|
||||
command = command,
|
||||
context = callback_data.context,
|
||||
entity_name = callback_data.entity_name,
|
||||
entity_id = callback_data.entity_id,
|
||||
field_name = callback_data.field_name,
|
||||
data = str(min(page + 10, total_pages)) if page < total_pages else "skip",
|
||||
save_state = True).pack()))
|
||||
navigation_buttons.append(InlineKeyboardButton(text = "⏭️",
|
||||
callback_data = ContextData(
|
||||
command = command,
|
||||
context = callback_data.context,
|
||||
entity_name = callback_data.entity_name,
|
||||
entity_id = callback_data.entity_id,
|
||||
field_name = callback_data.field_name,
|
||||
data = str(total_pages) if page != total_pages else "skip",
|
||||
save_state = True).pack()))
|
||||
|
||||
keyboard_builder.row(*navigation_buttons)
|
||||
|
||||
|
||||
def add_filter_controls(keyboard_builder: InlineKeyboardBuilder,
|
||||
entity_descriptor: EntityDescriptor,
|
||||
filter: str = None,
|
||||
page: int = 1):
|
||||
|
||||
field_name_descriptor = entity_descriptor.fields_descriptors["name"]
|
||||
if field_name_descriptor.caption:
|
||||
caption = get_callable_str(field_name_descriptor.caption, field_name_descriptor)
|
||||
else:
|
||||
caption = field_name_descriptor.name
|
||||
|
||||
keyboard_builder.row(
|
||||
InlineKeyboardButton(
|
||||
text = f"🔎 {caption}{f": \"{filter}\"" if filter else ""}",
|
||||
callback_data = ContextData(
|
||||
command = CallbackCommand.VIEW_FILTER_EDIT,
|
||||
entity_name = entity_descriptor.name,
|
||||
data = str(page)).pack()))
|
||||
|
||||
|
||||
@router.callback_query(ContextData.filter(F.command == CallbackCommand.VIEW_FILTER_EDIT))
|
||||
async def view_filter_edit(query: CallbackQuery, **kwargs):
|
||||
|
||||
callback_data: ContextData = kwargs["callback_data"]
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data = await state.get_data()
|
||||
kwargs["state_data"] = state_data
|
||||
|
||||
args = callback_data.data.split("&")
|
||||
page = int(args[0])
|
||||
cmd = None
|
||||
if len(args) > 1:
|
||||
cmd = args[1]
|
||||
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
user: UserBase = kwargs["user"]
|
||||
entity_descriptor = get_entity_descriptor(app = app, callback_data = callback_data)
|
||||
|
||||
if cmd in ["cancel", "clear"]:
|
||||
|
||||
if cmd == "clear":
|
||||
await ViewSetting.set_filter(session = db_session, user_id = user.id, entity_name = entity_descriptor.class_name, filter = None)
|
||||
|
||||
context_data_bak = state_data.pop("context_data_bak", None)
|
||||
if context_data_bak:
|
||||
|
||||
state_data["context_data"] = context_data_bak
|
||||
context_data = ContextData.unpack(context_data_bak)
|
||||
|
||||
field_descriptor = get_field_descriptor(app, context_data)
|
||||
edit_prompt = state_data["edit_prompt"]
|
||||
current_value = await deserialize(session = db_session,
|
||||
type_ = field_descriptor.type_,
|
||||
value = state_data["value"])
|
||||
page = int(state_data.pop("page"))
|
||||
kwargs.pop("callback_data")
|
||||
|
||||
return await render_entity_picker(field_descriptor = field_descriptor,
|
||||
message = query,
|
||||
callback_data = context_data,
|
||||
current_value = current_value,
|
||||
edit_prompt = edit_prompt,
|
||||
page = page,
|
||||
**kwargs)
|
||||
|
||||
else:
|
||||
|
||||
state_data.pop("context_data", None)
|
||||
return await route_callback(message = query, back = False, **kwargs)
|
||||
|
||||
|
||||
#await save_navigation_context(callback_data = callback_data, state = state)
|
||||
old_context_data = state_data.get("context_data")
|
||||
await state.update_data({"context_data": callback_data.pack(),
|
||||
"context_data_bak": old_context_data,
|
||||
"page": page})
|
||||
|
||||
send_message = get_send_message(query)
|
||||
|
||||
await send_message(text = await Settings.get(Settings.APP_STRINGS_VIEW_FILTER_EDIT_PROMPT),
|
||||
reply_markup = InlineKeyboardBuilder().row(
|
||||
InlineKeyboardButton(
|
||||
text = await Settings.get(Settings.APP_STRINGS_CANCEL_BTN),
|
||||
callback_data = ContextData(
|
||||
command = CallbackCommand.VIEW_FILTER_EDIT,
|
||||
entity_name = entity_descriptor.name,
|
||||
data = f"{page}&cancel").pack()),
|
||||
InlineKeyboardButton(
|
||||
text = await Settings.get(Settings.APP_STRINGS_CLEAR_BTN),
|
||||
callback_data = ContextData(
|
||||
command = CallbackCommand.VIEW_FILTER_EDIT,
|
||||
entity_name = entity_descriptor.name,
|
||||
data = f"{page}&clear").pack())).as_markup())
|
||||
|
||||
|
||||
@router.message(CallbackCommandFilter(command = CallbackCommand.VIEW_FILTER_EDIT))
|
||||
async def view_filter_edit_input(message: Message, **kwargs):
|
||||
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data = await state.get_data()
|
||||
kwargs["state_data"] = state_data
|
||||
callback_data = ContextData.unpack(state_data["context_data"])
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
user: UserBase = kwargs["user"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
entity_descriptor = get_entity_descriptor(app = app, callback_data = callback_data)
|
||||
filter = message.text
|
||||
await ViewSetting.set_filter(session = db_session, user_id = user.id, entity_name = entity_descriptor.class_name, filter = filter)
|
||||
|
||||
#state_data.pop("context_data")
|
||||
#return await route_callback(message = message, back = False, **kwargs)
|
||||
|
||||
context_data_bak = state_data.pop("context_data_bak", None)
|
||||
if context_data_bak:
|
||||
state_data["context_data"] = context_data_bak
|
||||
context_data = ContextData.unpack(context_data_bak)
|
||||
field_descriptor = get_field_descriptor(app, context_data)
|
||||
edit_prompt = state_data["edit_prompt"]
|
||||
current_value = await deserialize(session = db_session,
|
||||
type_ = field_descriptor.type_,
|
||||
value = state_data["value"])
|
||||
page = int(state_data.pop("page"))
|
||||
|
||||
return await render_entity_picker(field_descriptor = field_descriptor,
|
||||
message = message,
|
||||
callback_data = context_data,
|
||||
current_value = current_value,
|
||||
edit_prompt = edit_prompt,
|
||||
page = page,
|
||||
**kwargs)
|
||||
|
||||
else:
|
||||
|
||||
state_data.pop("context_data", None)
|
||||
return await route_callback(message = message, back = False, **kwargs)
|
||||
|
||||
|
||||
from ..navigation import route_callback, save_navigation_context, clear_state, get_navigation_context
|
||||
from ..editors.entity import render_entity_picker
|
||||
30
bot/handlers/common/filtering.py
Normal file
30
bot/handlers/common/filtering.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from aiogram.types import InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from ....model.descriptors import EntityDescriptor
|
||||
from ....utils.main import get_callable_str
|
||||
from ..context import ContextData, CallbackCommand
|
||||
|
||||
|
||||
def add_filter_controls(
|
||||
keyboard_builder: InlineKeyboardBuilder,
|
||||
entity_descriptor: EntityDescriptor,
|
||||
filter: str = None,
|
||||
page: int = 1,
|
||||
):
|
||||
field_name_descriptor = entity_descriptor.fields_descriptors["name"]
|
||||
if field_name_descriptor.caption:
|
||||
caption = get_callable_str(field_name_descriptor.caption, field_name_descriptor)
|
||||
else:
|
||||
caption = field_name_descriptor.name
|
||||
|
||||
keyboard_builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=f"🔎 {caption}{f': "{filter}"' if filter else ''}",
|
||||
callback_data=ContextData(
|
||||
command=CallbackCommand.VIEW_FILTER_EDIT,
|
||||
entity_name=entity_descriptor.name,
|
||||
data=str(page),
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
168
bot/handlers/common/filtering_callbacks.py
Normal file
168
bot/handlers/common/filtering_callbacks.py
Normal file
@@ -0,0 +1,168 @@
|
||||
from aiogram import Router, F
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..context import ContextData, CallbackCommand
|
||||
from ...command_context_filter import CallbackCommandFilter
|
||||
from ....model.user import UserBase
|
||||
from ....model.settings import Settings
|
||||
from ....model.view_setting import ViewSetting
|
||||
from ....utils.main import (
|
||||
get_send_message,
|
||||
get_entity_descriptor,
|
||||
get_field_descriptor,
|
||||
)
|
||||
from ....utils.serialization import deserialize
|
||||
from ..editors.entity import render_entity_picker
|
||||
from .routing import route_callback
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
ContextData.filter(F.command == CallbackCommand.VIEW_FILTER_EDIT)
|
||||
)
|
||||
async def view_filter_edit(query: CallbackQuery, **kwargs):
|
||||
callback_data: ContextData = kwargs["callback_data"]
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data = await state.get_data()
|
||||
kwargs["state_data"] = state_data
|
||||
|
||||
args = callback_data.data.split("&")
|
||||
page = int(args[0])
|
||||
cmd = None
|
||||
if len(args) > 1:
|
||||
cmd = args[1]
|
||||
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
user: UserBase = kwargs["user"]
|
||||
entity_descriptor = get_entity_descriptor(app=app, callback_data=callback_data)
|
||||
|
||||
if cmd in ["cancel", "clear"]:
|
||||
if cmd == "clear":
|
||||
await ViewSetting.set_filter(
|
||||
session=db_session,
|
||||
user_id=user.id,
|
||||
entity_name=entity_descriptor.class_name,
|
||||
filter=None,
|
||||
)
|
||||
|
||||
context_data_bak = state_data.pop("context_data_bak", None)
|
||||
if context_data_bak:
|
||||
state_data["context_data"] = context_data_bak
|
||||
context_data = ContextData.unpack(context_data_bak)
|
||||
|
||||
field_descriptor = get_field_descriptor(app, context_data)
|
||||
edit_prompt = state_data["edit_prompt"]
|
||||
current_value = await deserialize(
|
||||
session=db_session,
|
||||
type_=field_descriptor.type_,
|
||||
value=state_data["value"],
|
||||
)
|
||||
page = int(state_data.pop("page"))
|
||||
kwargs.pop("callback_data")
|
||||
|
||||
return await render_entity_picker(
|
||||
field_descriptor=field_descriptor,
|
||||
message=query,
|
||||
callback_data=context_data,
|
||||
current_value=current_value,
|
||||
edit_prompt=edit_prompt,
|
||||
page=page,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
else:
|
||||
state_data.pop("context_data", None)
|
||||
return await route_callback(message=query, back=False, **kwargs)
|
||||
|
||||
# await save_navigation_context(callback_data = callback_data, state = state)
|
||||
old_context_data = state_data.get("context_data")
|
||||
await state.update_data(
|
||||
{
|
||||
"context_data": callback_data.pack(),
|
||||
"context_data_bak": old_context_data,
|
||||
"page": page,
|
||||
}
|
||||
)
|
||||
|
||||
send_message = get_send_message(query)
|
||||
|
||||
await send_message(
|
||||
text=await Settings.get(Settings.APP_STRINGS_VIEW_FILTER_EDIT_PROMPT),
|
||||
reply_markup=InlineKeyboardBuilder()
|
||||
.row(
|
||||
InlineKeyboardButton(
|
||||
text=await Settings.get(Settings.APP_STRINGS_CANCEL_BTN),
|
||||
callback_data=ContextData(
|
||||
command=CallbackCommand.VIEW_FILTER_EDIT,
|
||||
entity_name=entity_descriptor.name,
|
||||
data=f"{page}&cancel",
|
||||
).pack(),
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text=await Settings.get(Settings.APP_STRINGS_CLEAR_BTN),
|
||||
callback_data=ContextData(
|
||||
command=CallbackCommand.VIEW_FILTER_EDIT,
|
||||
entity_name=entity_descriptor.name,
|
||||
data=f"{page}&clear",
|
||||
).pack(),
|
||||
),
|
||||
)
|
||||
.as_markup(),
|
||||
)
|
||||
|
||||
|
||||
@router.message(CallbackCommandFilter(command=CallbackCommand.VIEW_FILTER_EDIT))
|
||||
async def view_filter_edit_input(message: Message, **kwargs):
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data = await state.get_data()
|
||||
kwargs["state_data"] = state_data
|
||||
callback_data = ContextData.unpack(state_data["context_data"])
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
user: UserBase = kwargs["user"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
entity_descriptor = get_entity_descriptor(app=app, callback_data=callback_data)
|
||||
filter = message.text
|
||||
await ViewSetting.set_filter(
|
||||
session=db_session,
|
||||
user_id=user.id,
|
||||
entity_name=entity_descriptor.class_name,
|
||||
filter=filter,
|
||||
)
|
||||
|
||||
# state_data.pop("context_data")
|
||||
# return await route_callback(message = message, back = False, **kwargs)
|
||||
|
||||
context_data_bak = state_data.pop("context_data_bak", None)
|
||||
if context_data_bak:
|
||||
state_data["context_data"] = context_data_bak
|
||||
context_data = ContextData.unpack(context_data_bak)
|
||||
field_descriptor = get_field_descriptor(app, context_data)
|
||||
edit_prompt = state_data["edit_prompt"]
|
||||
current_value = await deserialize(
|
||||
session=db_session, type_=field_descriptor.type_, value=state_data["value"]
|
||||
)
|
||||
page = int(state_data.pop("page"))
|
||||
|
||||
return await render_entity_picker(
|
||||
field_descriptor=field_descriptor,
|
||||
message=message,
|
||||
callback_data=context_data,
|
||||
current_value=current_value,
|
||||
edit_prompt=edit_prompt,
|
||||
page=page,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
else:
|
||||
state_data.pop("context_data", None)
|
||||
return await route_callback(message=message, back=False, **kwargs)
|
||||
114
bot/handlers/common/pagination.py
Normal file
114
bot/handlers/common/pagination.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from aiogram.types import InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from ..context import ContextData, CallbackCommand
|
||||
|
||||
|
||||
def add_pagination_controls(
|
||||
keyboard_builder: InlineKeyboardBuilder,
|
||||
callback_data: ContextData,
|
||||
total_pages: int,
|
||||
command: CallbackCommand,
|
||||
page: int,
|
||||
):
|
||||
if total_pages > 1:
|
||||
navigation_buttons = []
|
||||
ContextData(**callback_data.model_dump()).__setattr__
|
||||
if total_pages > 10:
|
||||
navigation_buttons.append(
|
||||
InlineKeyboardButton(
|
||||
text="⏮️",
|
||||
callback_data=ContextData(
|
||||
command=command,
|
||||
context=callback_data.context,
|
||||
entity_name=callback_data.entity_name,
|
||||
entity_id=callback_data.entity_id,
|
||||
field_name=callback_data.field_name,
|
||||
form_params=callback_data.form_params,
|
||||
data="1" if page != 1 else "skip",
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
navigation_buttons.append(
|
||||
InlineKeyboardButton(
|
||||
text="⏪️",
|
||||
callback_data=ContextData(
|
||||
command=command,
|
||||
context=callback_data.context,
|
||||
entity_name=callback_data.entity_name,
|
||||
entity_id=callback_data.entity_id,
|
||||
field_name=callback_data.field_name,
|
||||
form_params=callback_data.form_params,
|
||||
data=str(max(page - 10, 1)) if page > 1 else "skip",
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
|
||||
navigation_buttons.append(
|
||||
InlineKeyboardButton(
|
||||
text="◀️",
|
||||
callback_data=ContextData(
|
||||
command=command,
|
||||
context=callback_data.context,
|
||||
entity_name=callback_data.entity_name,
|
||||
entity_id=callback_data.entity_id,
|
||||
field_name=callback_data.field_name,
|
||||
form_params=callback_data.form_params,
|
||||
data=str(max(page - 1, 1)) if page > 1 else "skip",
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
navigation_buttons.append(
|
||||
InlineKeyboardButton(
|
||||
text="▶️",
|
||||
callback_data=ContextData(
|
||||
command=command,
|
||||
context=callback_data.context,
|
||||
entity_name=callback_data.entity_name,
|
||||
entity_id=callback_data.entity_id,
|
||||
field_name=callback_data.field_name,
|
||||
form_params=callback_data.form_params,
|
||||
data=(
|
||||
str(min(page + 1, total_pages))
|
||||
if page < total_pages
|
||||
else "skip"
|
||||
),
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
|
||||
if total_pages > 10:
|
||||
navigation_buttons.append(
|
||||
InlineKeyboardButton(
|
||||
text="⏩️",
|
||||
callback_data=ContextData(
|
||||
command=command,
|
||||
context=callback_data.context,
|
||||
entity_name=callback_data.entity_name,
|
||||
entity_id=callback_data.entity_id,
|
||||
field_name=callback_data.field_name,
|
||||
form_params=callback_data.form_params,
|
||||
data=(
|
||||
str(min(page + 10, total_pages))
|
||||
if page < total_pages
|
||||
else "skip"
|
||||
),
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
navigation_buttons.append(
|
||||
InlineKeyboardButton(
|
||||
text="⏭️",
|
||||
callback_data=ContextData(
|
||||
command=command,
|
||||
context=callback_data.context,
|
||||
entity_name=callback_data.entity_name,
|
||||
entity_id=callback_data.entity_id,
|
||||
field_name=callback_data.field_name,
|
||||
form_params=callback_data.form_params,
|
||||
data=str(total_pages) if page != total_pages else "skip",
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
|
||||
keyboard_builder.row(*navigation_buttons)
|
||||
48
bot/handlers/common/routing.py
Normal file
48
bot/handlers/common/routing.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from aiogram.types import Message, CallbackQuery
|
||||
from ..context import CallbackCommand
|
||||
|
||||
from ..navigation import (
|
||||
get_navigation_context,
|
||||
save_navigation_context,
|
||||
pop_navigation_context,
|
||||
)
|
||||
|
||||
import qbot.bot.handlers.menu.main as menu_main
|
||||
import qbot.bot.handlers.menu.settings as menu_settings
|
||||
import qbot.bot.handlers.menu.parameters as menu_parameters
|
||||
import qbot.bot.handlers.menu.language as menu_language
|
||||
import qbot.bot.handlers.menu.entities as menu_entities
|
||||
import qbot.bot.handlers.forms.entity_list as form_list
|
||||
import qbot.bot.handlers.forms.entity_form as form_item
|
||||
import qbot.bot.handlers.editors.main as editor
|
||||
|
||||
|
||||
async def route_callback(message: Message | CallbackQuery, back: bool = True, **kwargs):
|
||||
state_data = kwargs["state_data"]
|
||||
stack, context = get_navigation_context(state_data)
|
||||
if back:
|
||||
context = pop_navigation_context(stack)
|
||||
stack = save_navigation_context(callback_data=context, state_data=state_data)
|
||||
kwargs.update({"callback_data": context, "navigation_stack": stack})
|
||||
if context:
|
||||
if context.command == CallbackCommand.MENU_ENTRY_MAIN:
|
||||
await menu_main.main_menu(message, **kwargs)
|
||||
elif context.command == CallbackCommand.MENU_ENTRY_SETTINGS:
|
||||
await menu_settings.settings_menu(message, **kwargs)
|
||||
elif context.command == CallbackCommand.MENU_ENTRY_PARAMETERS:
|
||||
await menu_parameters.parameters_menu(message, **kwargs)
|
||||
elif context.command == CallbackCommand.MENU_ENTRY_LANGUAGE:
|
||||
await menu_language.language_menu(message, **kwargs)
|
||||
elif context.command == CallbackCommand.MENU_ENTRY_ENTITIES:
|
||||
await menu_entities.entities_menu(message, **kwargs)
|
||||
elif context.command == CallbackCommand.ENTITY_LIST:
|
||||
await form_list.entity_list(message, **kwargs)
|
||||
elif context.command == CallbackCommand.ENTITY_ITEM:
|
||||
await form_item.entity_item(message, **kwargs)
|
||||
elif context.command == CallbackCommand.FIELD_EDITOR:
|
||||
await editor.field_editor(message, **kwargs)
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unknown command {context.command}")
|
||||
else:
|
||||
raise ValueError("No navigation context")
|
||||
Reference in New Issue
Block a user