from aiogram.types import Message, CallbackQuery from aiogram.fsm.context import FSMContext from aiogram.utils.i18n import I18n from aiogram.utils.keyboard import InlineKeyboardBuilder from typing import Any, Callable, TYPE_CHECKING, Literal, Union from babel.support import LazyProxy from dataclasses import dataclass, field from sqlmodel.ext.asyncio.session import AsyncSession from .role import RoleBase from . import EntityPermission from ..bot.handlers.context import ContextData if TYPE_CHECKING: from .bot_entity import BotEntity from ..main import QBotApp from .user import UserBase EntityCaptionCallable = Callable[["EntityDescriptor"], str] EntityItemCaptionCallable = Callable[["EntityDescriptor", Any], str] EntityFieldCaptionCallable = Callable[["FieldDescriptor", Any, Any], str] @dataclass class FieldEditButton: field_name: str caption: str | LazyProxy | EntityFieldCaptionCallable | None = None visibility: Callable[[Any], bool] | None = None @dataclass class CommandButton: command: ContextData | Callable[[ContextData, Any], ContextData] | str caption: str | LazyProxy | EntityItemCaptionCallable visibility: Callable[[Any], bool] | None = None @dataclass class Filter: field_name: str operator: Literal[ "==", "!=", ">", "<", ">=", "<=", "in", "not in", "like", "ilike", "is", "is not", ] value_type: Literal["const", "param"] value: Any | None = None param_index: int | None = None @dataclass class EntityList: caption: str | LazyProxy | EntityCaptionCallable | None = None item_repr: EntityItemCaptionCallable | None = None show_add_new_button: bool = True item_form: str | None = None pagination: bool = True static_filters: list[Filter] | Any = None filtering: bool = False filtering_fields: list[str] = None order_by: str | Any | None = None @dataclass class EntityForm: item_repr: EntityItemCaptionCallable | None = None edit_field_sequence: list[str] = None form_buttons: list[list[FieldEditButton | CommandButton]] = None show_edit_button: bool = True show_delete_button: bool = True @dataclass(kw_only=True) class _BaseFieldDescriptor: icon: str = None caption: str | LazyProxy | EntityFieldCaptionCallable | None = None description: str | LazyProxy | EntityFieldCaptionCallable | None = None edit_prompt: str | LazyProxy | EntityFieldCaptionCallable | None = None caption_value: EntityFieldCaptionCallable | None = None is_visible: bool = True localizable: bool = False bool_false_value: str | LazyProxy = "no" bool_true_value: str | LazyProxy = "yes" ep_form: str | None = None ep_parent_field: str | None = None ep_child_field: str | None = None dt_type: Literal["date", "datetime"] = "date" default: Any = None @dataclass(kw_only=True) class EntityField(_BaseFieldDescriptor): name: str | None = None sm_descriptor: Any = None @dataclass(kw_only=True) class Setting(_BaseFieldDescriptor): name: str | None = None @dataclass(kw_only=True) class FormField(_BaseFieldDescriptor): name: str | None = None type_: type @dataclass(kw_only=True) class FieldDescriptor(_BaseFieldDescriptor): name: str field_name: str type_: type type_base: type = None is_list: bool = False is_optional: bool = False entity_descriptor: "EntityDescriptor" = None command: "BotCommand" = None def __hash__(self): return self.name.__hash__() @dataclass(kw_only=True) class _BaseEntityDescriptor: icon: str = "📘" full_name: str | LazyProxy | EntityCaptionCallable | None = None full_name_plural: str | LazyProxy | EntityCaptionCallable | None = None description: str | LazyProxy | EntityCaptionCallable | None = None item_repr: EntityItemCaptionCallable | None = None default_list: EntityList = field(default_factory=EntityList) default_form: EntityForm = field(default_factory=EntityForm) lists: dict[str, EntityList] = field(default_factory=dict[str, EntityList]) forms: dict[str, EntityForm] = field(default_factory=dict[str, EntityForm]) show_in_entities_menu: bool = True ownership_fields: dict[RoleBase, str] = field(default_factory=dict[RoleBase, str]) permissions: dict[EntityPermission, list[RoleBase]] = field( default_factory=lambda: { EntityPermission.LIST: [RoleBase.DEFAULT_USER, RoleBase.SUPER_USER], EntityPermission.READ: [RoleBase.DEFAULT_USER, RoleBase.SUPER_USER], EntityPermission.CREATE: [RoleBase.DEFAULT_USER, RoleBase.SUPER_USER], EntityPermission.UPDATE: [RoleBase.DEFAULT_USER, RoleBase.SUPER_USER], EntityPermission.DELETE: [RoleBase.DEFAULT_USER, RoleBase.SUPER_USER], EntityPermission.LIST_ALL: [RoleBase.SUPER_USER], EntityPermission.READ_ALL: [RoleBase.SUPER_USER], EntityPermission.CREATE_ALL: [RoleBase.SUPER_USER], EntityPermission.UPDATE_ALL: [RoleBase.SUPER_USER], EntityPermission.DELETE_ALL: [RoleBase.SUPER_USER], } ) @dataclass(kw_only=True) class Entity(_BaseEntityDescriptor): name: str | None = None @dataclass class EntityDescriptor(_BaseEntityDescriptor): name: str class_name: str type_: type["BotEntity"] fields_descriptors: dict[str, FieldDescriptor] @dataclass(kw_only=True) class CommandCallbackContext[UT: UserBase]: keyboard_builder: InlineKeyboardBuilder = field( default_factory=InlineKeyboardBuilder ) message_text: str | None = None register_navigation: bool = True message: Message | CallbackQuery callback_data: ContextData db_session: AsyncSession user: UT app: "QBotApp" state_data: dict[str, Any] state: FSMContext form_data: dict[str, Any] i18n: I18n kwargs: dict[str, Any] = field(default_factory=dict) @dataclass(kw_only=True) class BotCommand: name: str caption: str | dict[str, str] | None = None pre_check: Callable[[Union[Message, CallbackQuery], Any], bool] | None = None show_in_bot_commands: bool = False register_navigation: bool = True clear_navigation: bool = False clear_state: bool = True param_form: dict[str, FieldDescriptor] | None = None show_cancel_in_param_form: bool = True show_back_in_param_form: bool = True handler: Callable[[CommandCallbackContext], None]