from typing import TYPE_CHECKING from aiogram import Router, F from aiogram.fsm.context import FSMContext from aiogram.types import Message, CallbackQuery from logging import getLogger from sqlmodel.ext.asyncio.session import AsyncSession from ....model import EntityPermission from ....model.settings import Settings from ....model.user import UserBase from ....utils.main import ( check_entity_permission, get_field_descriptor, ) from ....utils.serialization import deserialize, serialize from ..context import ContextData, CallbackCommand, CommandContext from ....auth import authorize_command from ..navigation import ( get_navigation_context, save_navigation_context, ) from ..forms.entity_form import entity_item from .common import show_editor from ..menu.parameters import parameters_menu from .string import router as string_editor_router from .date import router as date_picker_router from .boolean import router as bool_editor_router from .entity import router as entity_picker_router if TYPE_CHECKING: from ....main import QBotApp logger = getLogger(__name__) router = Router() @router.callback_query(ContextData.filter(F.command == CallbackCommand.FIELD_EDITOR)) async def field_editor(message: Message | CallbackQuery, **kwargs): callback_data: ContextData = kwargs.get("callback_data", None) db_session: AsyncSession = kwargs["db_session"] user: UserBase = kwargs["user"] app: "QBotApp" = kwargs["app"] state: FSMContext = kwargs["state"] state_data = await state.get_data() entity_data = state_data.get("entity_data") for key in ["current_value", "value", "locale_index"]: if key in state_data: state_data.pop(key) kwargs["state_data"] = state_data entity_descriptor = None if callback_data.context == CommandContext.SETTING_EDIT: field_descriptor = get_field_descriptor(app, callback_data) if field_descriptor.type_ is bool: if await authorize_command(user=user, callback_data=callback_data): await Settings.set_param( field_descriptor, not await Settings.get(field_descriptor) ) else: return await message.answer( text=(await Settings.get(Settings.APP_STRINGS_FORBIDDEN)) ) stack, context = get_navigation_context(state_data=state_data) return await parameters_menu( message=message, navigation_stack=stack, **kwargs ) current_value = await Settings.get(field_descriptor, all_locales=True) else: field_descriptor = get_field_descriptor(app, callback_data) entity_descriptor = field_descriptor.entity_descriptor current_value = None if ( field_descriptor.type_base is bool and callback_data.context == CommandContext.ENTITY_FIELD_EDIT ): entity = await entity_descriptor.type_.get( session=db_session, id=int(callback_data.entity_id) ) if check_entity_permission( entity=entity, user=user, permission=EntityPermission.UPDATE ): current_value: bool = ( getattr(entity, field_descriptor.field_name) or False ) setattr(entity, field_descriptor.field_name, not current_value) await db_session.commit() stack, context = get_navigation_context(state_data=state_data) return await entity_item( query=message, navigation_stack=stack, **kwargs ) if not entity_data and callback_data.context in [ CommandContext.ENTITY_EDIT, CommandContext.ENTITY_FIELD_EDIT, ]: entity = await entity_descriptor.type_.get( session=kwargs["db_session"], id=int(callback_data.entity_id) ) if check_entity_permission( entity=entity, user=user, permission=EntityPermission.READ ): if entity: form_name = ( callback_data.form_params.split("&")[0] if callback_data.form_params else "default" ) form = entity_descriptor.forms.get( form_name, entity_descriptor.default_form ) entity_data = { key: serialize( getattr(entity, key), entity_descriptor.fields_descriptors[key], ) for key in ( form.edit_field_sequence if callback_data.context == CommandContext.ENTITY_EDIT else [callback_data.field_name] ) } state_data.update({"entity_data": entity_data}) if entity_data: current_value = await deserialize( session=db_session, type_=field_descriptor.type_, value=entity_data.get(callback_data.field_name), ) kwargs.update({"field_descriptor": field_descriptor}) save_navigation_context(state_data=state_data, callback_data=callback_data) await show_editor(message=message, current_value=current_value, **kwargs) router.include_routers( string_editor_router, date_picker_router, bool_editor_router, entity_picker_router, )