from types import NoneType, UnionType 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 sqlmodel.ext.asyncio.session import AsyncSession from typing import Any, get_args, get_origin import ujson as json from ..context import ContextData, CallbackCommand, CommandContext from ....model.user import UserBase from ....model.settings import Settings from ....main import QBotApp from ....model.bot_entity import BotEntity from ....model.bot_enum import BotEnum from ....model.descriptors import (EntityFieldDescriptor, EntityDescriptor, EntityCaptionCallable, EntityItemCaptionCallable, EntityFieldCaptionCallable) 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_ origin = get_origin(type_) if value is None: return "" if origin == UnionType: args = get_args(type_) if args[1] == NoneType: type_ = args[0] if isinstance(value, bool): return "【✔︎】" if value else "【 】" elif origin == list: arg_type = None args = get_args(type_) if args: arg_type = args[0] if arg_type and issubclass(arg_type, BotEntity): if locale and arg_type.bot_entity_descriptor.fields_descriptors["name"].localizable: return "[" + ", ".join([get_local_text(value = item.name, locale = locale) for item in value]) + "]" else: return "[" + ", ".join([str(item.name) for item in value]) + "]" elif arg_type and issubclass(arg_type, BotEnum): return "[" + ", ".join(item.localized(locale) for item in value) + "]" elif arg_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(value = 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(value, 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): 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_SETTINGS_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]: 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)