from typing import get_args, get_origin from aiogram import Router, F from aiogram.filters import Command from aiogram.fsm.context import FSMContext from aiogram.fsm.state import StatesGroup, State from aiogram.types import Message, CallbackQuery, InlineKeyboardButton from aiogram.utils.i18n import I18n from aiogram.utils.keyboard import InlineKeyboardBuilder from logging import getLogger from sqlmodel.ext.asyncio.session import AsyncSession from ....main import QBotApp from ....model.bot_entity import BotEntity from ....model.bot_enum import BotEnum from ....model.owned_bot_entity import OwnedBotEntity from ....model.settings import Settings from ....model.user import UserBase from ....model.descriptors import EntityFieldDescriptor, EntityDescriptor from ....model import EntityPermission from ....utils import serialize, deserialize, get_user_permissions from ..context import ContextData, CallbackCommand, CommandContext from ..common import (add_pagination_controls, get_local_text, get_entity_descriptor, get_callable_str, get_send_message) logger = getLogger(__name__) router = Router() @router.callback_query(ContextData.filter(F.command == CallbackCommand.ENTITY_LIST)) async def entity_list_callback(query: CallbackQuery, callback_data: ContextData, **kwargs): if callback_data.data == "skip": return await clear_state(state = kwargs["state"]) stack = await save_navigation_context(callback_data = callback_data, state = kwargs["state"]) await entity_list(message = query, callback_data = callback_data, navigation_stack = stack, **kwargs) async def entity_list(message: CallbackQuery | Message, callback_data: ContextData, db_session: AsyncSession, user: UserBase, app: QBotApp, navigation_stack: list[ContextData], **kwargs): page = int(callback_data.data or "1") entity_descriptor = get_entity_descriptor(app, callback_data) user_permissions = get_user_permissions(user, entity_descriptor) entity_type = entity_descriptor.type_ keyboard_builder = InlineKeyboardBuilder() if EntityPermission.CREATE in user_permissions or EntityPermission.CREATE_ALL in user_permissions: keyboard_builder.row( InlineKeyboardButton( text = (await Settings.get(Settings.APP_STRINGS_ADD_BTN)), callback_data = ContextData( command = CallbackCommand.FIELD_EDITOR, context = CommandContext.ENTITY_CREATE, entity_name = entity_descriptor.name, field_name = entity_descriptor.field_sequence[0], save_state = True).pack())) page_size = await Settings.get(Settings.PAGE_SIZE) if issubclass(entity_type, OwnedBotEntity): if EntityPermission.READ_ALL in user_permissions or EntityPermission.LIST_ALL in user_permissions: items = await entity_type.get_multi( session = db_session, order_by = entity_type.name, skip = page_size * (page - 1), limit = page_size) items_count = await entity_type.get_count(session = db_session) elif EntityPermission.READ in user_permissions or EntityPermission.LIST in user_permissions: items = await entity_type.get_multi_by_user( session = db_session, user_id = user.id, order_by = entity_type.name, skip = page_size * (page - 1), limit = page_size) items_count = await entity_type.get_count_by_user(session = db_session, user_id = user.id) else: items = list[OwnedBotEntity]() items_count = 0 elif issubclass(entity_type, BotEntity): if (EntityPermission.READ in user_permissions or EntityPermission.LIST in user_permissions or EntityPermission.READ_ALL in user_permissions or EntityPermission.LIST_ALL in user_permissions): items = await entity_type.get_multi( session = db_session, order_by = entity_type.name, skip = page_size * (page - 1), limit = page_size) items_count = await entity_type.get_count(session = db_session) else: items = list[BotEntity]() items_count = 0 else: raise ValueError(f"Unsupported entity type: {entity_type}") total_pages = items_count // page_size + (1 if items_count % page_size else 0) for item in items: if entity_descriptor.item_caption_btn: caption = entity_descriptor.item_caption_btn(entity_descriptor, item) elif entity_descriptor.fields_descriptors["name"].localizable: caption = get_local_text(item.name, user.lang) else: caption = item.name keyboard_builder.row( InlineKeyboardButton( text = caption, callback_data = ContextData( command = CallbackCommand.ENTITY_ITEM, entity_name = entity_descriptor.name, entity_id = str(item.id)).pack())) add_pagination_controls(keyboard_builder = keyboard_builder, callback_data = callback_data, total_pages = total_pages, command = CallbackCommand.ENTITY_LIST, page = page) context = pop_navigation_context(navigation_stack) if context: keyboard_builder.row( InlineKeyboardButton( text = (await Settings.get(Settings.APP_STRINGS_BACK_BTN)), callback_data = context.pack())) if entity_descriptor.caption_msg: entity_text = get_callable_str(entity_descriptor.caption_msg, entity_descriptor) else: entity_text = entity_descriptor.name if entity_descriptor.description: entity_desciption = get_callable_str(entity_descriptor.description, entity_descriptor) else: entity_desciption = None send_message = get_send_message(message) await send_message(text = f"{entity_text}{f"\n{entity_desciption}" if entity_desciption else ""}", reply_markup = keyboard_builder.as_markup()) from ..navigation import pop_navigation_context, save_navigation_context, clear_state