diff --git a/src/qbot/__init__.py b/src/qbot/__init__.py index cdb901e..d874510 100644 --- a/src/qbot/__init__.py +++ b/src/qbot/__init__.py @@ -15,6 +15,7 @@ from .model.descriptors import ( Filter as Filter, EntityPermission as EntityPermission, CommandCallbackContext as CommandCallbackContext, + EntityEventContext as EntityEventContext, CommandButton as CommandButton, FieldEditButton as FieldEditButton, InlineButton as InlineButton, diff --git a/src/qbot/bot/handlers/editors/main_callbacks.py b/src/qbot/bot/handlers/editors/main_callbacks.py index fd7cdd3..7c06043 100644 --- a/src/qbot/bot/handlers/editors/main_callbacks.py +++ b/src/qbot/bot/handlers/editors/main_callbacks.py @@ -1,3 +1,4 @@ +from inspect import iscoroutinefunction from aiogram import Router, F from aiogram.types import Message, CallbackQuery from aiogram.fsm.context import FSMContext @@ -12,7 +13,7 @@ from ..user_handlers.main import cammand_handler from ....model import EntityPermission from ....model.user import UserBase from ....model.settings import Settings -from ....model.descriptors import FieldDescriptor +from ....model.descriptors import EntityEventContext, FieldDescriptor from ....model.language import LanguageBase from ....auth import authorize_command from ....utils.main import ( @@ -281,6 +282,12 @@ async def process_field_edit_callback(message: Message | CallbackQuery, **kwargs commit=True, ) + if entity_descriptor.on_created: + if iscoroutinefunction(entity_descriptor.on_created): + await entity_descriptor.on_created(new_entity, EntityEventContext(db_session=db_session, app=app)) + else: + entity_descriptor.on_created(new_entity, EntityEventContext(db_session=db_session, app=app)) + form_name = ( callback_data.form_params.split("&")[0] if callback_data.form_params @@ -325,6 +332,13 @@ async def process_field_edit_callback(message: Message | CallbackQuery, **kwargs setattr(entity, key, value) await db_session.commit() + await db_session.refresh(entity) + + if entity_descriptor.on_updated: + if iscoroutinefunction(entity_descriptor.on_updated): + await entity_descriptor.on_updated(entity, EntityEventContext(db_session=db_session, app=app)) + else: + entity_descriptor.on_updated(entity, EntityEventContext(db_session=db_session, app=app)) elif callback_data.context == CommandContext.COMMAND_FORM: clear_state(state_data=state_data) diff --git a/src/qbot/bot/handlers/forms/entity_form_callbacks.py b/src/qbot/bot/handlers/forms/entity_form_callbacks.py index b82fb0a..70950fe 100644 --- a/src/qbot/bot/handlers/forms/entity_form_callbacks.py +++ b/src/qbot/bot/handlers/forms/entity_form_callbacks.py @@ -1,3 +1,4 @@ +from inspect import iscoroutinefunction from aiogram import Router, F from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery, InlineKeyboardButton @@ -5,6 +6,8 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder from sqlmodel.ext.asyncio.session import AsyncSession from typing import TYPE_CHECKING +from qbot.model.descriptors import EntityEventContext + from ..context import ContextData, CallbackCommand from ....model.user import UserBase from ....model.settings import Settings @@ -47,10 +50,18 @@ async def entity_delete_callback(query: CallbackQuery, **kwargs): ) if callback_data.data == "yes": - await entity_descriptor.type_.remove( + + entity = await entity_descriptor.type_.remove( session=db_session, id=int(callback_data.entity_id), commit=True ) + if entity_descriptor.on_deleted: + if iscoroutinefunction(entity_descriptor.on_created): + await entity_descriptor.on_deleted(entity, EntityEventContext(db_session=db_session, app=app)) + else: + entity_descriptor.on_deleted(entity, EntityEventContext(db_session=db_session, app=app)) + + await route_callback(message=query, **kwargs) elif not callback_data.data: diff --git a/src/qbot/config/__init__.py b/src/qbot/config/__init__.py index 27cb658..1b20328 100644 --- a/src/qbot/config/__init__.py +++ b/src/qbot/config/__init__.py @@ -31,7 +31,7 @@ class Config(BaseSettings): def API_DOMAIN(self) -> str: if self.ENVIRONMENT == "local": return self.DOMAIN - return f"api.{self.DOMAIN}" + return f"{self.DOMAIN}" @computed_field @property @@ -39,7 +39,7 @@ class Config(BaseSettings): if self.USE_NGROK: return self.NGROK_URL return ( - f"{'http' if self.ENVIRONMENT == 'local' else 'https'}://{self.API_DOMAIN}" + f"https://{self.API_DOMAIN}" ) API_PORT: int = 8000 diff --git a/src/qbot/model/descriptors.py b/src/qbot/model/descriptors.py index b3bc1f0..15b66c0 100644 --- a/src/qbot/model/descriptors.py +++ b/src/qbot/model/descriptors.py @@ -163,6 +163,9 @@ class _BaseEntityDescriptor: EntityPermission.DELETE_ALL: [RoleBase.SUPER_USER], } ) + on_created: Callable[["BotEntity", "EntityEventContext"], None] | None = None + on_deleted: Callable[["BotEntity", "EntityEventContext"], None] | None = None + on_updated: Callable[["BotEntity", "EntityEventContext"], None] | None = None @dataclass(kw_only=True) @@ -197,6 +200,12 @@ class CommandCallbackContext[UT: UserBase]: kwargs: dict[str, Any] = field(default_factory=dict) +@dataclass(kw_only=True) +class EntityEventContext: + db_session: AsyncSession + app: "QBotApp" + + @dataclass(kw_only=True) class BotCommand: name: str