minor fixes and updates
This commit is contained in:
@@ -31,7 +31,11 @@ async def telegram_webhook(
|
|||||||
return Response(status_code=400)
|
return Response(status_code=400)
|
||||||
try:
|
try:
|
||||||
await app.dp.feed_webhook_update(
|
await app.dp.feed_webhook_update(
|
||||||
app.bot, update, db_session=db_session, app=app
|
app.bot,
|
||||||
|
update,
|
||||||
|
db_session=db_session,
|
||||||
|
app=app,
|
||||||
|
**(request.state if request.state else {}),
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Error processing update", exc_info=True)
|
logger.error("Error processing update", exc_info=True)
|
||||||
|
|||||||
@@ -24,24 +24,11 @@ class Config(BaseSettings):
|
|||||||
def DATABASE_URI(self) -> str:
|
def DATABASE_URI(self) -> str:
|
||||||
return f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
return f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||||||
|
|
||||||
DOMAIN: str = "localhost"
|
|
||||||
|
|
||||||
@computed_field
|
|
||||||
@property
|
|
||||||
def API_DOMAIN(self) -> str:
|
|
||||||
if self.ENVIRONMENT == "local":
|
|
||||||
return self.DOMAIN
|
|
||||||
return f"{self.DOMAIN}"
|
|
||||||
|
|
||||||
@computed_field
|
|
||||||
@property
|
|
||||||
def API_URL(self) -> str:
|
|
||||||
if self.USE_NGROK:
|
|
||||||
return self.NGROK_URL
|
|
||||||
return f"https://{self.API_DOMAIN}"
|
|
||||||
|
|
||||||
API_PORT: int = 8000
|
API_PORT: int = 8000
|
||||||
|
|
||||||
|
TELEGRAM_WEBHOOK_URL: str = "http://localhost:8000"
|
||||||
|
TELEGRAM_BOT_SERVER: str = "https://api.telegram.org"
|
||||||
|
TELEGRAM_BOT_SERVER_IS_LOCAL: bool = False
|
||||||
TELEGRAM_BOT_TOKEN: str = "changethis"
|
TELEGRAM_BOT_TOKEN: str = "changethis"
|
||||||
|
|
||||||
ADMIN_TELEGRAM_ID: int
|
ADMIN_TELEGRAM_ID: int
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from typing import Callable, Any
|
from typing import Callable, Any
|
||||||
from aiogram import Bot, Dispatcher
|
from aiogram import Bot, Dispatcher
|
||||||
|
from aiogram.client.session.aiohttp import AiohttpSession
|
||||||
|
from aiogram.client.telegram import TelegramAPIServer
|
||||||
from aiogram.client.default import DefaultBotProperties
|
from aiogram.client.default import DefaultBotProperties
|
||||||
from aiogram.types import Message, BotCommand as AiogramBotCommand
|
from aiogram.types import Message, BotCommand as AiogramBotCommand
|
||||||
from aiogram.utils.callback_answer import CallbackAnswerMiddleware
|
from aiogram.utils.callback_answer import CallbackAnswerMiddleware
|
||||||
@@ -35,8 +37,8 @@ async def default_lifespan(app: "QBotApp"):
|
|||||||
logger.info("qbot app started")
|
logger.info("qbot app started")
|
||||||
|
|
||||||
if app.lifespan:
|
if app.lifespan:
|
||||||
async with app.lifespan(app):
|
async with app.lifespan(app) as state:
|
||||||
yield
|
yield state
|
||||||
else:
|
else:
|
||||||
yield
|
yield
|
||||||
|
|
||||||
@@ -88,8 +90,14 @@ class QBotApp[UserType: UserBase](FastAPI):
|
|||||||
self.entity_metadata: EntityMetadata = user_class.entity_metadata
|
self.entity_metadata: EntityMetadata = user_class.entity_metadata
|
||||||
self.config = config
|
self.config = config
|
||||||
self.lifespan = lifespan
|
self.lifespan = lifespan
|
||||||
|
api_server = TelegramAPIServer.from_base(
|
||||||
|
self.config.TELEGRAM_BOT_SERVER,
|
||||||
|
is_local=self.config.TELEGRAM_BOT_SERVER_IS_LOCAL,
|
||||||
|
)
|
||||||
|
session = AiohttpSession(api=api_server)
|
||||||
self.bot = Bot(
|
self.bot = Bot(
|
||||||
token=self.config.TELEGRAM_BOT_TOKEN,
|
token=self.config.TELEGRAM_BOT_TOKEN,
|
||||||
|
session=session,
|
||||||
default=DefaultBotProperties(parse_mode="HTML"),
|
default=DefaultBotProperties(parse_mode="HTML"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -124,7 +132,7 @@ class QBotApp[UserType: UserBase](FastAPI):
|
|||||||
|
|
||||||
from .api_route.telegram import router as telegram_router
|
from .api_route.telegram import router as telegram_router
|
||||||
|
|
||||||
self.include_router(telegram_router, prefix="/api/telegram", tags=["telegram"])
|
self.include_router(telegram_router, prefix="/telegram", tags=["telegram"])
|
||||||
self.root_router = Router()
|
self.root_router = Router()
|
||||||
self.root_router._commands = self.bot_commands
|
self.root_router._commands = self.bot_commands
|
||||||
self.command = self.root_router.command
|
self.command = self.root_router.command
|
||||||
@@ -177,6 +185,13 @@ class QBotApp[UserType: UserBase](FastAPI):
|
|||||||
commands_captions[locale] = []
|
commands_captions[locale] = []
|
||||||
commands_captions[locale].append((command_name, description))
|
commands_captions[locale].append((command_name, description))
|
||||||
|
|
||||||
|
await self.bot.set_webhook(
|
||||||
|
url=f"{self.config.TELEGRAM_WEBHOOK_URL}/telegram/webhook",
|
||||||
|
drop_pending_updates=True,
|
||||||
|
allowed_updates=self.allowed_updates,
|
||||||
|
secret_token=self.bot_auth_token,
|
||||||
|
)
|
||||||
|
|
||||||
for locale, commands in commands_captions.items():
|
for locale, commands in commands_captions.items():
|
||||||
await self.bot.set_my_commands(
|
await self.bot.set_my_commands(
|
||||||
[
|
[
|
||||||
@@ -186,12 +201,7 @@ class QBotApp[UserType: UserBase](FastAPI):
|
|||||||
language_code=None if locale == "default" else locale,
|
language_code=None if locale == "default" else locale,
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.bot.set_webhook(
|
|
||||||
url=f"{self.config.API_URL}/api/telegram/webhook",
|
|
||||||
drop_pending_updates=True,
|
|
||||||
allowed_updates=self.allowed_updates,
|
|
||||||
secret_token=self.bot_auth_token,
|
|
||||||
)
|
|
||||||
|
|
||||||
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.close()
|
||||||
|
|||||||
@@ -67,14 +67,31 @@ class BotEntityMetaclass(SQLModelMetaclass):
|
|||||||
descriptor_kwargs = attribute_value.__dict__.copy()
|
descriptor_kwargs = attribute_value.__dict__.copy()
|
||||||
sm_descriptor = descriptor_kwargs.pop("sm_descriptor", None) # type: FieldInfo
|
sm_descriptor = descriptor_kwargs.pop("sm_descriptor", None) # type: FieldInfo
|
||||||
|
|
||||||
if attribute_value.default is not None:
|
if sm_descriptor:
|
||||||
if (
|
if (
|
||||||
sm_descriptor
|
attribute_value.default is not None
|
||||||
and sm_descriptor.default is PydanticUndefined
|
and sm_descriptor.default is PydanticUndefined
|
||||||
):
|
):
|
||||||
sm_descriptor.default = attribute_value.default
|
sm_descriptor.default = attribute_value.default
|
||||||
else:
|
if (
|
||||||
sm_descriptor = Field(default=attribute_value.default)
|
attribute_value.default_factory is not None
|
||||||
|
and sm_descriptor.default_factory is PydanticUndefined
|
||||||
|
):
|
||||||
|
sm_descriptor.default_factory = (
|
||||||
|
attribute_value.default_factory
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if (
|
||||||
|
attribute_value.default is not None
|
||||||
|
or attribute_value.default_factory is not None
|
||||||
|
):
|
||||||
|
sm_descriptor = Field()
|
||||||
|
if attribute_value.default is not None:
|
||||||
|
sm_descriptor.default = attribute_value.default
|
||||||
|
if attribute_value.default_factory is not None:
|
||||||
|
sm_descriptor.default_factory = (
|
||||||
|
attribute_value.default_factory
|
||||||
|
)
|
||||||
|
|
||||||
if sm_descriptor:
|
if sm_descriptor:
|
||||||
namespace[annotation] = sm_descriptor
|
namespace[annotation] = sm_descriptor
|
||||||
@@ -167,23 +184,6 @@ class BotEntityMetaclass(SQLModelMetaclass):
|
|||||||
fields_descriptors=bot_fields_descriptors,
|
fields_descriptors=bot_fields_descriptors,
|
||||||
)
|
)
|
||||||
|
|
||||||
# descriptor_fields_sequence = [
|
|
||||||
# key
|
|
||||||
# for key, val in bot_fields_descriptors.items()
|
|
||||||
# if not (val.is_optional or val.name == "id" or val.name[:-3] == "_id")
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# entity_descriptor: EntityDescriptor = namespace["bot_entity_descriptor"]
|
|
||||||
|
|
||||||
# if entity_descriptor.default_form.edit_field_sequence is None:
|
|
||||||
# entity_descriptor.default_form.edit_field_sequence = (
|
|
||||||
# descriptor_fields_sequence
|
|
||||||
# )
|
|
||||||
|
|
||||||
# for form in entity_descriptor.forms.values():
|
|
||||||
# if form.edit_field_sequence is None:
|
|
||||||
# form.edit_field_sequence = descriptor_fields_sequence
|
|
||||||
|
|
||||||
for field_descriptor in bot_fields_descriptors.values():
|
for field_descriptor in bot_fields_descriptors.values():
|
||||||
field_descriptor.entity_descriptor = namespace["bot_entity_descriptor"]
|
field_descriptor.entity_descriptor = namespace["bot_entity_descriptor"]
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ class _BaseFieldDescriptor:
|
|||||||
ep_child_field: str | None = None
|
ep_child_field: str | None = None
|
||||||
dt_type: Literal["date", "datetime"] = "date"
|
dt_type: Literal["date", "datetime"] = "date"
|
||||||
default: Any = None
|
default: Any = None
|
||||||
|
default_factory: Callable[[], Any] | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
|
|||||||
@@ -227,7 +227,9 @@ class Settings(metaclass=SettingsMetaclass):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
param.default
|
param.default_factory()
|
||||||
|
if param.default_factory
|
||||||
|
else param.default
|
||||||
if param.default
|
if param.default
|
||||||
else (
|
else (
|
||||||
[]
|
[]
|
||||||
@@ -249,7 +251,6 @@ class Settings(metaclass=SettingsMetaclass):
|
|||||||
session=session,
|
session=session,
|
||||||
type_=setting.type_,
|
type_=setting.type_,
|
||||||
value=db_setting.value,
|
value=db_setting.value,
|
||||||
default=setting.default,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cls._loaded = True
|
cls._loaded = True
|
||||||
|
|||||||
Reference in New Issue
Block a user