add ruff format, ruff check, time_picker, project structure and imports reorganized

This commit is contained in:
Alexander Kalinovsky
2025-01-21 23:50:19 +01:00
parent ced47ac993
commit 9dd0708a5b
58 changed files with 3690 additions and 2583 deletions

109
main.py
View File

@@ -1,24 +1,21 @@
from functools import wraps
from typing import Annotated, Callable, Any, Union, override
from typing import Annotated, Callable, Any
from typing_extensions import Doc
from aiogram import Bot, Dispatcher
from aiogram.filters import CommandStart
from aiogram.client.default import DefaultBotProperties
from aiogram.types import Message, BotCommand
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.types import Message
from aiogram.utils.callback_answer import CallbackAnswerMiddleware
from aiogram.utils.i18n import I18n
from fastapi import FastAPI
from fastapi.applications import Lifespan, AppType
from logging import getLogger
from secrets import token_hex
from .config import Config
from .fsm.db_storage import DbStorage
from .middleware.telegram import AuthMiddleware, I18nMiddleware, ResetStateMiddleware
from .middleware.telegram import AuthMiddleware, I18nMiddleware
from .model.user import UserBase
from .model.entity_metadata import EntityMetadata
from .bot.handlers.user_handlers import Command, CommandCallbackContext
from .model.descriptors import BotCommand
from .router import Router
class QBotApp(FastAPI):
@@ -26,47 +23,67 @@ class QBotApp(FastAPI):
Main class for the QBot application
"""
def __init__[UserType: UserBase](self,
user_class: Annotated[type[UserType], Doc(
"User class that will be used in the application"
)] | None = None,
config: Config | None = None,
bot_start: Annotated[Callable[[Annotated[Callable[[Message, Any], None], Doc(
"Default handler for the start command"
)], Message, Any], None], Doc(
"Handler for the start command"
)] | None = None,
bot_commands: list[Command] | None = None,
lifespan: Lifespan[AppType] | None = None,
*args,
**kwargs):
def __init__[UserType: UserBase](
self,
user_class: (
Annotated[
type[UserType], Doc("User class that will be used in the application")
]
| None
) = None,
config: Config | None = None,
bot_start: (
Annotated[
Callable[
[
Annotated[
Callable[[Message, Any], None],
Doc("Default handler for the start command"),
],
Message,
Any,
],
None,
],
Doc("Handler for the start command"),
]
| None
) = None,
lifespan: Lifespan[AppType] | None = None,
*args,
**kwargs,
):
if config is None:
config = Config()
if user_class is None:
from .model.default_user import DefaultUser
user_class = DefaultUser
self.user_class = user_class
self.entity_metadata: EntityMetadata = user_class.entity_metadata
self.config = config
self.lifespan = lifespan
self.bot = Bot(token = self.config.TELEGRAM_BOT_TOKEN, default = DefaultBotProperties(parse_mode = "HTML"))
dp = Dispatcher(storage = DbStorage())
self.bot = Bot(
token=self.config.TELEGRAM_BOT_TOKEN,
default=DefaultBotProperties(parse_mode="HTML"),
)
i18n = I18n(path = "locales", default_locale = "en", domain = "messages")
i18n_middleware = I18nMiddleware(user_class = user_class, i18n = i18n)
dp = Dispatcher(storage=DbStorage())
i18n = I18n(path="locales", default_locale="en", domain="messages")
i18n_middleware = I18nMiddleware(user_class=user_class, i18n=i18n)
i18n_middleware.setup(dp)
# dp.callback_query.middleware(ResetStateMiddleware())
dp.callback_query.middleware(CallbackAnswerMiddleware())
from .bot.handlers.start import router as start_router
dp.include_router(start_router)
from .bot.handlers.menu.main import router as main_menu_router
auth = AuthMiddleware(user_class = user_class)
auth = AuthMiddleware(user_class=user_class)
main_menu_router.message.middleware.register(auth)
main_menu_router.callback_query.middleware.register(auth)
dp.include_router(main_menu_router)
@@ -76,35 +93,17 @@ class QBotApp(FastAPI):
self.bot_auth_token = token_hex(128)
self.start_handler = bot_start
self.bot_commands = {c.name: c for c in bot_commands or []}
self.bot_commands = dict[str, BotCommand]()
from .lifespan import default_lifespan
super().__init__(lifespan = default_lifespan, *args, **kwargs)
super().__init__(lifespan=default_lifespan, *args, **kwargs)
from .api_route.telegram import router as telegram_router
self.include_router(telegram_router, prefix = "/api/telegram", tags = ["telegram"])
@override
def bot_command(self, command: Command): ...
self.include_router(telegram_router, prefix="/api/telegram", tags=["telegram"])
@override
def bot_command(self, command: str, caption: str | dict[str, str] | None = None): ...
def bot_command(self, command: str | Command, caption: str | dict[str, str] | None = None):
"""
Decorator for registering bot commands
"""
def decorator(func: Callable[[CommandCallbackContext], None]):
if isinstance(command, str):
command = Command(name = command, handler = func, caption = caption)
self.bot_commands[command.name] = command
wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorator
def register_routers(self, *routers: Router):
for router in routers:
for command_name, command in router._commands.items():
self.bot_commands[command_name] = command