rename bot app class
This commit is contained in:
@@ -69,7 +69,7 @@ class AppEntity(BotEntity):
|
||||
)
|
||||
|
||||
|
||||
app = QBotApp() # bot application based on FastAPI application
|
||||
app = QuickBot() # bot application based on FastAPI application
|
||||
# providing Telegram API webhook handler
|
||||
|
||||
@app.command( # decorator for bot commands definition
|
||||
|
||||
@@ -73,7 +73,7 @@ class AppEntity(BotEntity):
|
||||
)
|
||||
|
||||
|
||||
app = QBotApp() # bot application based on FastAPI application
|
||||
app = QuickBot() # bot application based on FastAPI application
|
||||
# providing Telegram API webhook handler
|
||||
|
||||
@app.command( # decorator for bot commands definition
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "quickbot"
|
||||
version = "0.1.0"
|
||||
description = "QBot - Rapid Application Development Framework for Telegram Bots"
|
||||
description = "quickbot - Rapid Application Development Framework for Telegram Bots"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
classifiers = [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .main import QBotApp as QBotApp, Config as Config
|
||||
from .main import QuickBot as QuickBot, Config as Config
|
||||
from .router import Router as Router
|
||||
from .model.bot_entity import BotEntity as BotEntity
|
||||
from .model.bot_process import BotProcess as BotProcess
|
||||
|
||||
@@ -9,7 +9,7 @@ from quickbot.db import get_db
|
||||
from quickbot.model.user import UserBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot import QBotApp
|
||||
from quickbot import QuickBot
|
||||
|
||||
security_scheme = HTTPBearer(
|
||||
scheme_name="bearerAuth",
|
||||
@@ -27,7 +27,7 @@ async def get_current_user(
|
||||
user_id = payload.get("sub")
|
||||
if user_id is None:
|
||||
raise HTTPException(status_code=401, detail="Invalid token")
|
||||
app: QBotApp = request.app
|
||||
app: QuickBot = request.app
|
||||
user = await app.user_class.get(
|
||||
session=db_session,
|
||||
id=int(user_id),
|
||||
|
||||
@@ -8,7 +8,7 @@ from ..model.descriptors import EntityDescriptor
|
||||
from .depends import get_current_user
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..main import QBotApp
|
||||
from ..main import QuickBot
|
||||
from ..model.user import UserBase
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ async def get_me(
|
||||
request: Request,
|
||||
current_user: Annotated["UserBase", Depends(get_current_user)],
|
||||
):
|
||||
app: "QBotApp" = request.app
|
||||
app: "QuickBot" = request.app
|
||||
user = await app.user_class.bot_entity_descriptor.crud.get_by_id(
|
||||
db_session=db_session,
|
||||
user=current_user,
|
||||
|
||||
@@ -4,7 +4,7 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
from typing import Annotated
|
||||
|
||||
from ..db import get_db
|
||||
from ..main import QBotApp
|
||||
from ..main import QuickBot
|
||||
from ..auth.telegram import check_telegram_auth
|
||||
from ..auth.jwt import create_access_token
|
||||
|
||||
@@ -21,7 +21,7 @@ async def telegram_webhook(
|
||||
request: Request,
|
||||
):
|
||||
logger.debug("Webhook request %s", await request.json())
|
||||
app: QBotApp = request.app
|
||||
app: QuickBot = request.app
|
||||
|
||||
if app.webhook_handler:
|
||||
return await app.webhook_handler(app=app, request=request)
|
||||
|
||||
@@ -20,7 +20,7 @@ from ..editors.entity import render_entity_picker
|
||||
from .routing import route_callback
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
router = Router()
|
||||
@@ -42,7 +42,7 @@ async def view_filter_edit(query: CallbackQuery, **kwargs):
|
||||
cmd = args[1]
|
||||
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
user: UserBase = kwargs["user"]
|
||||
entity_descriptor = get_entity_descriptor(app=app, callback_data=callback_data)
|
||||
|
||||
@@ -129,7 +129,7 @@ async def view_filter_edit_input(message: Message, **kwargs):
|
||||
callback_data = ContextData.unpack(state_data["context_data"])
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
user: UserBase = kwargs["user"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
entity_descriptor = get_entity_descriptor(app=app, callback_data=callback_data)
|
||||
filter = message.text
|
||||
await ViewSetting.set_filter(
|
||||
|
||||
@@ -3,7 +3,7 @@ from aiogram.fsm.context import FSMContext
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot.main import QBotApp
|
||||
from quickbot.main import QuickBot
|
||||
|
||||
from ..context import CallbackCommand
|
||||
|
||||
@@ -51,7 +51,7 @@ async def route_callback(message: Message | CallbackQuery, back: bool = True, **
|
||||
elif context.command == CallbackCommand.FIELD_EDITOR:
|
||||
await editor.field_editor(message, **kwargs)
|
||||
elif context.command == CallbackCommand.USER_COMMAND:
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
cmd = app.bot_commands.get(context.user_command.split("&")[0])
|
||||
|
||||
await user_handler.command_handler(message=message, cmd=cmd, **kwargs)
|
||||
|
||||
@@ -4,7 +4,7 @@ from datetime import datetime, time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot.main import QBotApp
|
||||
from quickbot.main import QuickBot
|
||||
from quickbot.utils.serialization import deserialize
|
||||
|
||||
from ....model.bot_entity import BotEntity
|
||||
@@ -27,7 +27,7 @@ async def show_editor(message: Message | CallbackQuery, **kwargs):
|
||||
callback_data: ContextData = kwargs.get("callback_data", None)
|
||||
state_data: dict = kwargs["state_data"]
|
||||
db_session = kwargs["db_session"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
|
||||
value_type = field_descriptor.type_base
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from ....utils.main import get_send_message, get_field_descriptor
|
||||
from .wrapper import wrap_editor
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
@@ -23,7 +23,7 @@ router = Router()
|
||||
|
||||
@router.callback_query(ContextData.filter(F.command == CallbackCommand.TIME_PICKER))
|
||||
async def time_picker_callback(
|
||||
query: CallbackQuery, callback_data: ContextData, app: "QBotApp", **kwargs
|
||||
query: CallbackQuery, callback_data: ContextData, app: "QuickBot", **kwargs
|
||||
):
|
||||
if not callback_data.data:
|
||||
return
|
||||
@@ -316,7 +316,7 @@ async def date_picker_year(
|
||||
user: UserBase,
|
||||
**kwargs,
|
||||
):
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
start_date = datetime.strptime(callback_data.data, "%Y-%m-%d %H-%M")
|
||||
|
||||
state_data = await state.get_data()
|
||||
@@ -407,7 +407,7 @@ async def date_picker_year(
|
||||
ContextData.filter(F.command == CallbackCommand.DATE_PICKER_MONTH)
|
||||
)
|
||||
async def date_picker_month(query: CallbackQuery, callback_data: ContextData, **kwargs):
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
field_descriptor = get_field_descriptor(app, callback_data)
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data = await state.get_data()
|
||||
|
||||
@@ -31,7 +31,7 @@ from ..common.filtering import add_filter_controls
|
||||
from .wrapper import wrap_editor
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
logger = getLogger(__name__)
|
||||
router = Router()
|
||||
@@ -362,7 +362,7 @@ async def render_entity_picker(
|
||||
send_message = get_send_message(message)
|
||||
await send_message(text=edit_prompt, reply_markup=keyboard_builder.as_markup())
|
||||
else:
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
await app.bot.send_message(
|
||||
chat_id=user.id, text=edit_prompt, reply_markup=keyboard_builder.as_markup()
|
||||
)
|
||||
@@ -378,7 +378,7 @@ async def entity_picker_callback(
|
||||
query: CallbackQuery,
|
||||
callback_data: ContextData,
|
||||
db_session: AsyncSession,
|
||||
app: "QBotApp",
|
||||
app: "QuickBot",
|
||||
state: FSMContext,
|
||||
**kwargs,
|
||||
):
|
||||
|
||||
@@ -34,7 +34,7 @@ from .boolean import router as bool_editor_router
|
||||
from .entity import router as entity_picker_router
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
@@ -54,7 +54,7 @@ async def field_editor(message: Message | CallbackQuery, **kwargs):
|
||||
callback_data: ContextData = kwargs.get("callback_data", None)
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
user: UserBase = kwargs["user"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
state: FSMContext = kwargs["state"]
|
||||
|
||||
state_data: dict = kwargs["state_data"]
|
||||
|
||||
@@ -37,7 +37,7 @@ from ..common.routing import route_callback
|
||||
from .common import show_editor
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -68,7 +68,7 @@ async def _validate_value(
|
||||
ContextData.filter(F.command == CallbackCommand.FIELD_EDITOR_CALLBACK)
|
||||
)
|
||||
async def field_editor_callback(message: Message | CallbackQuery, **kwargs):
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
callback_data: ContextData = kwargs.get("callback_data", None)
|
||||
|
||||
state: FSMContext = kwargs["state"]
|
||||
@@ -205,7 +205,7 @@ async def process_field_edit_callback(message: Message | CallbackQuery, **kwargs
|
||||
CommandContext.ENTITY_FIELD_EDIT,
|
||||
CommandContext.COMMAND_FORM,
|
||||
]:
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
entity_descriptor = get_entity_descriptor(app, callback_data)
|
||||
|
||||
entity_data = state_data.get("entity_data", {})
|
||||
|
||||
@@ -35,7 +35,7 @@ from ....utils.navigation import (
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
@@ -61,7 +61,7 @@ async def entity_item(
|
||||
callback_data: ContextData,
|
||||
db_session: AsyncSession,
|
||||
user: UserBase,
|
||||
app: "QBotApp",
|
||||
app: "QuickBot",
|
||||
navigation_stack: list[ContextData],
|
||||
**kwargs,
|
||||
):
|
||||
|
||||
@@ -20,7 +20,7 @@ from ....utils.main import (
|
||||
from ..common.routing import route_callback
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
router = Router()
|
||||
@@ -31,7 +31,7 @@ async def entity_delete_callback(query: CallbackQuery, **kwargs):
|
||||
callback_data: ContextData = kwargs["callback_data"]
|
||||
user: UserBase = kwargs["user"]
|
||||
db_session: AsyncSession = kwargs["db_session"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data = await state.get_data()
|
||||
kwargs["state_data"] = state_data
|
||||
|
||||
@@ -31,7 +31,7 @@ from ..common.filtering import add_filter_controls
|
||||
from ....utils.navigation import pop_navigation_context, save_navigation_context
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
@@ -65,7 +65,7 @@ async def entity_list(
|
||||
callback_data: ContextData,
|
||||
db_session: AsyncSession,
|
||||
user: UserBase,
|
||||
app: "QBotApp",
|
||||
app: "QuickBot",
|
||||
navigation_stack: list[ContextData],
|
||||
**kwargs,
|
||||
):
|
||||
|
||||
@@ -12,7 +12,7 @@ from ....utils.main import get_send_message, get_callable_str
|
||||
from ....utils.navigation import save_navigation_context, pop_navigation_context
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
from ....main import QuickBot
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
@@ -35,7 +35,7 @@ async def menu_entry_entities(message: CallbackQuery, **kwargs):
|
||||
|
||||
async def entities_menu(
|
||||
message: Message | CallbackQuery,
|
||||
app: "QBotApp",
|
||||
app: "QuickBot",
|
||||
state: FSMContext,
|
||||
navigation_stack: list[ContextData],
|
||||
**kwargs,
|
||||
|
||||
@@ -5,7 +5,7 @@ from aiogram.types import Message
|
||||
from logging import getLogger
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from ...main import QBotApp
|
||||
from ...main import QuickBot
|
||||
from ...model.settings import Settings
|
||||
from ...model.language import LanguageBase
|
||||
from ...model.user import UserBase
|
||||
@@ -18,7 +18,7 @@ router = Router()
|
||||
|
||||
@router.message(CommandStart())
|
||||
async def start(message: Message, **kwargs):
|
||||
app: QBotApp = kwargs["app"]
|
||||
app: QuickBot = kwargs["app"]
|
||||
state: FSMContext = kwargs["state"]
|
||||
|
||||
state_data = await state.get_data()
|
||||
@@ -35,7 +35,7 @@ async def start(message: Message, **kwargs):
|
||||
async def default_start_handler[UserType: UserBase](
|
||||
message: Message,
|
||||
db_session: AsyncSession,
|
||||
app: QBotApp,
|
||||
app: QuickBot,
|
||||
state: FSMContext,
|
||||
**kwargs,
|
||||
) -> tuple[UserType, bool]:
|
||||
|
||||
@@ -15,7 +15,7 @@ from quickbot.model.descriptors import BotCommand, CommandCallbackContext
|
||||
from quickbot.model.settings import Settings
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot.main import QBotApp
|
||||
from quickbot.main import QuickBot
|
||||
from quickbot.model.user import UserBase
|
||||
|
||||
from ..context import ContextData, CallbackCommand, CommandContext
|
||||
@@ -25,7 +25,7 @@ async def command_handler(message: Message | CallbackQuery, cmd: BotCommand, **k
|
||||
callback_data: ContextData = kwargs["callback_data"]
|
||||
state: FSMContext = kwargs["state"]
|
||||
state_data: dict = kwargs["state_data"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
user: "UserBase" = kwargs["user"]
|
||||
|
||||
entity_data_dict: dict = state_data.get("entity_data")
|
||||
|
||||
@@ -7,7 +7,7 @@ from quickbot.utils.main import clear_state
|
||||
from quickbot.utils.navigation import save_navigation_context
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot.main import QBotApp
|
||||
from quickbot.main import QuickBot
|
||||
|
||||
from ..context import ContextData, CallbackCommand
|
||||
from .command_handler import command_handler
|
||||
@@ -43,7 +43,7 @@ async def command_callback(message: CallbackQuery, **kwargs):
|
||||
async def process_command_handler(message: Message | CallbackQuery, **kwargs):
|
||||
state_data: dict = kwargs["state_data"]
|
||||
callback_data: ContextData = kwargs["callback_data"]
|
||||
app: "QBotApp" = kwargs["app"]
|
||||
app: "QuickBot" = kwargs["app"]
|
||||
cmd = app.bot_commands.get(callback_data.user_command.split("&")[0])
|
||||
|
||||
if cmd is None:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
main.py - QuickBot RAD Framework Main Application Module
|
||||
|
||||
Defines QBotApp, the main entry point for the QuickBot rapid application development (RAD) framework for Telegram bots.
|
||||
Defines QuickBot, the main entry point for the QuickBot rapid application development (RAD) framework for Telegram bots.
|
||||
Integrates FastAPI (HTTP API), Aiogram (Telegram bot logic), SQLModel (async DB), and i18n (internationalization).
|
||||
|
||||
Key Features:
|
||||
@@ -66,7 +66,7 @@ ConfigType = TypeVar("ConfigType", bound=Config, default=Config)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def default_lifespan(app: "QBotApp"):
|
||||
async def default_lifespan(app: "QuickBot"):
|
||||
logger.debug("starting qbot app")
|
||||
|
||||
if app.lifespan_bot_init:
|
||||
@@ -88,7 +88,7 @@ async def default_lifespan(app: "QBotApp"):
|
||||
logger.info("qbot app stopped")
|
||||
|
||||
|
||||
class QBotApp(Generic[UserType, ConfigType], FastAPI):
|
||||
class QuickBot(Generic[UserType, ConfigType], FastAPI):
|
||||
"""
|
||||
Main application class for QuickBot RAD framework.
|
||||
|
||||
@@ -121,7 +121,7 @@ class QBotApp(Generic[UserType, ConfigType], FastAPI):
|
||||
lifespan: Lifespan[AppType] | None = None,
|
||||
lifespan_bot_init: bool = True,
|
||||
lifespan_set_webhook: bool = True,
|
||||
webhook_handler: Callable[["QBotApp", Request], Any] = None,
|
||||
webhook_handler: Callable[["QuickBot", Request], Any] = None,
|
||||
allowed_updates: list[str] | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
|
||||
@@ -2,7 +2,7 @@ from fastapi.datastructures import State
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot.main import QBotApp
|
||||
from quickbot.main import QuickBot
|
||||
|
||||
from .descriptors import EntityDescriptor, ProcessDescriptor
|
||||
from ._singleton import Singleton
|
||||
@@ -12,5 +12,5 @@ class BotMetadata(metaclass=Singleton):
|
||||
def __init__(self):
|
||||
self.entity_descriptors: dict[str, EntityDescriptor] = {}
|
||||
self.process_descriptors: dict[str, ProcessDescriptor] = {}
|
||||
self.app: "QBotApp" = None
|
||||
self.app: "QuickBot" = None
|
||||
self.app_state: State = None
|
||||
|
||||
@@ -17,7 +17,7 @@ from ..bot.handlers.context import ContextData
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .bot_entity import BotEntity
|
||||
from ..main import QBotApp
|
||||
from ..main import QuickBot
|
||||
from .user import UserBase
|
||||
from .crud_service import CrudService
|
||||
from .bot_process import BotProcess
|
||||
@@ -328,7 +328,7 @@ class CommandCallbackContext:
|
||||
callback_data: ContextData
|
||||
db_session: AsyncSession
|
||||
user: "UserBase"
|
||||
app: "QBotApp"
|
||||
app: "QuickBot"
|
||||
app_state: State
|
||||
state_data: dict[str, Any]
|
||||
state: FSMContext
|
||||
@@ -340,7 +340,7 @@ class CommandCallbackContext:
|
||||
@dataclass(kw_only=True)
|
||||
class BotContext:
|
||||
db_session: AsyncSession
|
||||
app: "QBotApp"
|
||||
app: "QuickBot"
|
||||
app_state: State
|
||||
user: "UserBase"
|
||||
message: Message | CallbackQuery | None = None
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from typing import TYPE_CHECKING, Protocol, runtime_checkable
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from quickbot import QBotApp
|
||||
from quickbot import QuickBot
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class Registerable(Protocol):
|
||||
def register(self, app: "QBotApp") -> None: ...
|
||||
def register(self, app: "QuickBot") -> None: ...
|
||||
|
||||
@@ -31,7 +31,7 @@ from ..bot.handlers.context import CallbackCommand, ContextData, CommandContext
|
||||
if TYPE_CHECKING:
|
||||
from ..model.bot_entity import BotEntity
|
||||
from ..model.user import UserBase
|
||||
from ..main import QBotApp
|
||||
from ..main import QuickBot
|
||||
|
||||
|
||||
def get_local_text(text: str, locale: str = None) -> str:
|
||||
@@ -179,7 +179,7 @@ async def get_callable_str(
|
||||
|
||||
|
||||
def get_entity_descriptor(
|
||||
app: "QBotApp", callback_data: ContextData
|
||||
app: "QuickBot", callback_data: ContextData
|
||||
) -> EntityDescriptor:
|
||||
if callback_data.entity_name:
|
||||
return app.bot_metadata.entity_descriptors[callback_data.entity_name]
|
||||
@@ -187,7 +187,7 @@ def get_entity_descriptor(
|
||||
|
||||
|
||||
def get_field_descriptor(
|
||||
app: "QBotApp", callback_data: ContextData
|
||||
app: "QuickBot", callback_data: ContextData
|
||||
) -> FieldDescriptor | None:
|
||||
if callback_data.context == CommandContext.SETTING_EDIT:
|
||||
return Settings.list_params()[callback_data.field_name]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from quickbot import (
|
||||
QBotApp,
|
||||
QuickBot,
|
||||
BotEntity,
|
||||
Entity,
|
||||
EntityForm,
|
||||
@@ -116,7 +116,7 @@ class Entity(BotEntity):
|
||||
)
|
||||
|
||||
|
||||
app = QBotApp(
|
||||
app = QuickBot(
|
||||
user_class=User,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user