add form rendering call from app object
All checks were successful
Build Docs / changes (push) Successful in 7s
Build Docs / build-docs (push) Has been skipped
Build Docs / deploy-docs (push) Has been skipped

This commit is contained in:
Alexander Kalinovsky
2025-04-08 01:20:45 +07:00
parent e10d7ff7bf
commit dc006c70fd
3 changed files with 90 additions and 16 deletions

View File

@@ -75,14 +75,14 @@ async def entity_item(
state_data = kwargs["state_data"]
await state.set_data(state_data)
if not entity_item:
if not entity_item and query:
return await query.answer(
text=(await Settings.get(Settings.APP_STRINGS_NOT_FOUND))
)
# is_owned = issubclass(entity_type, OwnedBotEntity)
if not check_entity_permission(
if query and not check_entity_permission(
entity=entity_item, user=user, permission=EntityPermission.READ
):
return await query.answer(
@@ -352,6 +352,12 @@ async def entity_item(
# state_data = kwargs["state_data"]
# await state.set_data(state_data)
send_message = get_send_message(query)
await send_message(text=item_text, reply_markup=keyboard_builder.as_markup())
if query:
send_message = get_send_message(query)
await send_message(text=item_text, reply_markup=keyboard_builder.as_markup())
else:
await app.bot.send_message(
chat_id=user.id,
text=item_text,
reply_markup=keyboard_builder.as_markup(),
)

View File

@@ -47,6 +47,7 @@ class Config(BaseSettings):
else ''
}"
TELEGRAM_BOT_USERNAME: str = "quickbot"
TELEGRAM_BOT_SERVER: str = "https://api.telegram.org"
TELEGRAM_BOT_SERVER_IS_LOCAL: bool = False
TELEGRAM_BOT_TOKEN: str = "changethis"

View File

@@ -1,5 +1,5 @@
from contextlib import asynccontextmanager
from typing import Callable, Any
from typing import Callable, Any, Generic, TypeVar
from aiogram import Bot, Dispatcher
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer
@@ -9,20 +9,31 @@ from aiogram.utils.callback_answer import CallbackAnswerMiddleware
from aiogram.utils.i18n import I18n
from fastapi import FastAPI
from fastapi.applications import Lifespan, AppType
from fastapi.datastructures import State
from secrets import token_hex
from logging import getLogger
from quickbot.utils.main import clear_state
from quickbot.utils.navigation import save_navigation_context
from .config import Config
from .bot.handlers.forms.entity_form import entity_item
from .db import get_db
from .fsm.db_storage import DbStorage
from .middleware.telegram import AuthMiddleware, I18nMiddleware
from .model.bot_entity import BotEntity
from .model.user import UserBase
from .model.entity_metadata import EntityMetadata
from .model.descriptors import BotCommand
from .bot.handlers.context import CallbackCommand, ContextData
from .router import Router
logger = getLogger(__name__)
UserType = TypeVar("UserType", bound=UserBase, default=UserBase)
ConfigType = TypeVar("ConfigType", bound=Config, default=Config)
@asynccontextmanager
async def default_lifespan(app: "QBotApp"):
@@ -34,6 +45,8 @@ async def default_lifespan(app: "QBotApp"):
await app.bot_init()
app.config.TELEGRAM_BOT_USERNAME = (await app.bot.get_me()).username
logger.info("qbot app started")
if app.lifespan:
@@ -53,15 +66,15 @@ async def default_lifespan(app: "QBotApp"):
logger.info("qbot app stopped")
class QBotApp[UserType: UserBase](FastAPI):
class QBotApp(Generic[UserType, ConfigType], FastAPI):
"""
Main class for the QBot application
"""
def __init__(
self,
user_class: UserType = None,
config: Config | None = None,
config: ConfigType = Config(),
user_class: type[UserType] = None,
bot_start: Callable[
[
Callable[[Message, Any], tuple[UserType, bool]],
@@ -73,12 +86,8 @@ class QBotApp[UserType: UserBase](FastAPI):
lifespan: Lifespan[AppType] | None = None,
lifespan_bot_init: bool = True,
allowed_updates: list[str] | None = None,
*args,
**kwargs,
):
if config is None:
config = Config()
if user_class is None:
from .model.default_user import DefaultUser
@@ -103,8 +112,8 @@ class QBotApp[UserType: UserBase](FastAPI):
dp = Dispatcher(storage=DbStorage())
i18n = I18n(path="locales", default_locale="en", domain="messages")
i18n_middleware = I18nMiddleware(user_class=user_class, i18n=i18n)
self.i18n = I18n(path="locales", default_locale="en", domain="messages")
i18n_middleware = I18nMiddleware(user_class=user_class, i18n=self.i18n)
i18n_middleware.setup(dp)
dp.callback_query.middleware(CallbackAnswerMiddleware())
@@ -128,7 +137,7 @@ class QBotApp[UserType: UserBase](FastAPI):
self.lifespan_bot_init = lifespan_bot_init
super().__init__(lifespan=default_lifespan, *args, **kwargs)
super().__init__(lifespan=default_lifespan, **kwargs)
from .api_route.telegram import router as telegram_router
@@ -201,6 +210,64 @@ class QBotApp[UserType: UserBase](FastAPI):
secret_token=self.bot_auth_token,
)
async def show_form(
self,
app_state: State,
user_id: int,
entity: type[BotEntity] | str,
entity_id: int,
form_name: str = None,
form_params: list[Any] = None,
**kwargs,
):
f_params = []
if form_name:
f_params.append(form_name)
if form_params:
f_params.extend(form_params)
if isinstance(entity, type):
entity = entity.bot_entity_descriptor.name
callback_data = ContextData(
command=CallbackCommand.ENTITY_ITEM,
entity_name=entity,
entity_id=entity_id,
form_params="&".join(f_params),
)
state = self.dp.fsm.get_context(bot=self.bot, chat_id=user_id, user_id=user_id)
state_data = await state.get_data()
clear_state(state_data=state_data)
stack = save_navigation_context(
callback_data=callback_data, state_data=state_data
)
db_session = kwargs.get("db_session")
if not db_session:
db_session = await get_db()
user = await self.user_class.get(
session=db_session,
id=user_id,
)
with self.i18n.context(), self.i18n.use_locale(user.lang.value):
await entity_item(
query=None,
db_session=kwargs.get("db_session"),
callback_data=callback_data,
app=self,
user=user,
navigation_stack=stack,
state=state,
state_data=state_data,
i18n=self.i18n,
app_state=app_state,
)
async def bot_close(self):
await self.bot.delete_webhook()
await self.bot.log_out()