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"] state_data = kwargs["state_data"]
await state.set_data(state_data) await state.set_data(state_data)
if not entity_item: if not entity_item and query:
return await query.answer( return await query.answer(
text=(await Settings.get(Settings.APP_STRINGS_NOT_FOUND)) text=(await Settings.get(Settings.APP_STRINGS_NOT_FOUND))
) )
# is_owned = issubclass(entity_type, OwnedBotEntity) # 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 entity=entity_item, user=user, permission=EntityPermission.READ
): ):
return await query.answer( return await query.answer(
@@ -352,6 +352,12 @@ async def entity_item(
# state_data = kwargs["state_data"] # state_data = kwargs["state_data"]
# await state.set_data(state_data) # await state.set_data(state_data)
send_message = get_send_message(query) if query:
send_message = get_send_message(query)
await send_message(text=item_text, reply_markup=keyboard_builder.as_markup()) 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 '' else ''
}" }"
TELEGRAM_BOT_USERNAME: str = "quickbot"
TELEGRAM_BOT_SERVER: str = "https://api.telegram.org" TELEGRAM_BOT_SERVER: str = "https://api.telegram.org"
TELEGRAM_BOT_SERVER_IS_LOCAL: bool = False TELEGRAM_BOT_SERVER_IS_LOCAL: bool = False
TELEGRAM_BOT_TOKEN: str = "changethis" TELEGRAM_BOT_TOKEN: str = "changethis"

View File

@@ -1,5 +1,5 @@
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import Callable, Any from typing import Callable, Any, Generic, TypeVar
from aiogram import Bot, Dispatcher from aiogram import Bot, Dispatcher
from aiogram.client.session.aiohttp import AiohttpSession from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer from aiogram.client.telegram import TelegramAPIServer
@@ -9,20 +9,31 @@ from aiogram.utils.callback_answer import CallbackAnswerMiddleware
from aiogram.utils.i18n import I18n from aiogram.utils.i18n import I18n
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.applications import Lifespan, AppType from fastapi.applications import Lifespan, AppType
from fastapi.datastructures import State
from secrets import token_hex from secrets import token_hex
from logging import getLogger from logging import getLogger
from quickbot.utils.main import clear_state
from quickbot.utils.navigation import save_navigation_context
from .config import Config 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 .fsm.db_storage import DbStorage
from .middleware.telegram import AuthMiddleware, I18nMiddleware from .middleware.telegram import AuthMiddleware, I18nMiddleware
from .model.bot_entity import BotEntity
from .model.user import UserBase from .model.user import UserBase
from .model.entity_metadata import EntityMetadata from .model.entity_metadata import EntityMetadata
from .model.descriptors import BotCommand from .model.descriptors import BotCommand
from .bot.handlers.context import CallbackCommand, ContextData
from .router import Router from .router import Router
logger = getLogger(__name__) logger = getLogger(__name__)
UserType = TypeVar("UserType", bound=UserBase, default=UserBase)
ConfigType = TypeVar("ConfigType", bound=Config, default=Config)
@asynccontextmanager @asynccontextmanager
async def default_lifespan(app: "QBotApp"): async def default_lifespan(app: "QBotApp"):
@@ -34,6 +45,8 @@ async def default_lifespan(app: "QBotApp"):
await app.bot_init() await app.bot_init()
app.config.TELEGRAM_BOT_USERNAME = (await app.bot.get_me()).username
logger.info("qbot app started") logger.info("qbot app started")
if app.lifespan: if app.lifespan:
@@ -53,15 +66,15 @@ async def default_lifespan(app: "QBotApp"):
logger.info("qbot app stopped") logger.info("qbot app stopped")
class QBotApp[UserType: UserBase](FastAPI): class QBotApp(Generic[UserType, ConfigType], FastAPI):
""" """
Main class for the QBot application Main class for the QBot application
""" """
def __init__( def __init__(
self, self,
user_class: UserType = None, config: ConfigType = Config(),
config: Config | None = None, user_class: type[UserType] = None,
bot_start: Callable[ bot_start: Callable[
[ [
Callable[[Message, Any], tuple[UserType, bool]], Callable[[Message, Any], tuple[UserType, bool]],
@@ -73,12 +86,8 @@ class QBotApp[UserType: UserBase](FastAPI):
lifespan: Lifespan[AppType] | None = None, lifespan: Lifespan[AppType] | None = None,
lifespan_bot_init: bool = True, lifespan_bot_init: bool = True,
allowed_updates: list[str] | None = None, allowed_updates: list[str] | None = None,
*args,
**kwargs, **kwargs,
): ):
if config is None:
config = Config()
if user_class is None: if user_class is None:
from .model.default_user import DefaultUser from .model.default_user import DefaultUser
@@ -103,8 +112,8 @@ class QBotApp[UserType: UserBase](FastAPI):
dp = Dispatcher(storage=DbStorage()) dp = Dispatcher(storage=DbStorage())
i18n = I18n(path="locales", default_locale="en", domain="messages") self.i18n = I18n(path="locales", default_locale="en", domain="messages")
i18n_middleware = I18nMiddleware(user_class=user_class, i18n=i18n) i18n_middleware = I18nMiddleware(user_class=user_class, i18n=self.i18n)
i18n_middleware.setup(dp) i18n_middleware.setup(dp)
dp.callback_query.middleware(CallbackAnswerMiddleware()) dp.callback_query.middleware(CallbackAnswerMiddleware())
@@ -128,7 +137,7 @@ class QBotApp[UserType: UserBase](FastAPI):
self.lifespan_bot_init = lifespan_bot_init 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 from .api_route.telegram import router as telegram_router
@@ -201,6 +210,64 @@ class QBotApp[UserType: UserBase](FastAPI):
secret_token=self.bot_auth_token, 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): async def bot_close(self):
await self.bot.delete_webhook() await self.bot.delete_webhook()
await self.bot.log_out() await self.bot.log_out()