v1.8.3: добавлены docstrings и комментарии по AGENTS.md ко всем ключевым файлам

This commit is contained in:
2026-06-02 18:53:21 +03:00
parent 4c3026a80f
commit a7a39bdd5d
19 changed files with 212 additions and 0 deletions
+19
View File
@@ -1,3 +1,11 @@
"""
Главный модуль max_bot FastAPI-приложения.
Эндпоинты:
- /webhook: входящие webhook-и от MAX Platform
- /health: healthcheck
- /api/bot/*: CRUD для настроек, KB, заявок, диалогов, пользователей
"""
from __future__ import annotations
import logging
from contextlib import asynccontextmanager
@@ -54,6 +62,7 @@ app.add_middleware(
async def _apply_migrations():
"""Автоматические миграции: добавление колонок/таблиц при старте."""
async with engine.begin() as conn:
try:
await conn.execute(text("""
@@ -101,6 +110,7 @@ async def _apply_migrations():
async def _add_column_if_not_exists(conn, table: str, column: str, col_type: str):
"""Безопасное добавление колонки (idempotent)."""
from sqlalchemy import text as sa_text
_validate_sql_name(table)
_validate_sql_name(column)
@@ -121,6 +131,7 @@ async def _add_column_if_not_exists(conn, table: str, column: str, col_type: str
async def _create_table_if_not_exists(conn, table: str, create_sql: str):
"""Безопасное создание таблицы (idempotent)."""
from sqlalchemy import text as sa_text
try:
await conn.execute(sa_text(f"""
@@ -138,12 +149,14 @@ async def _create_table_if_not_exists(conn, table: str, create_sql: str):
def _validate_sql_name(name: str) -> None:
"""Валидация SQL-идентификатора (только буквы, цифры, подчёркивания)."""
import re
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_ ]*$', name):
raise ValueError(f"Invalid SQL identifier: {name}")
def _validate_sql_type(col_type: str) -> None:
"""Валидация SQL-типа колонки (разрешённые типы)."""
import re
allowed = r'^(VARCHAR\(\d+\)|TEXT|INTEGER( DEFAULT \d+)?|BOOLEAN( DEFAULT (TRUE|FALSE))?|TIMESTAMP)$'
if not re.match(allowed, col_type.strip()):
@@ -151,6 +164,7 @@ def _validate_sql_type(col_type: str) -> None:
async def _log_processing(user_id: int, step: str, status: str = "ok", message: str = None, detail: str = None, conversation_id: int = None):
"""Запись лога обработки в bot_processing_logs."""
try:
async with async_session() as db:
db.add(BotProcessingLog(
@@ -167,6 +181,7 @@ async def _log_processing(user_id: int, step: str, status: str = "ok", message:
async def _seed_default_settings():
"""Заполнение настроек по умолчанию при первом запуске."""
defaults = {
"assistant_name": "София",
"assistant_role": "Представитель компании AegisOne Engineering, помогающий клиентам с запросами по безопасности",
@@ -185,6 +200,7 @@ async def _seed_default_settings():
async def _register_webhook():
"""Регистрация webhook-а в MAX Platform."""
try:
subs = await max_api.get_subscriptions()
logger.info(f"Current subscriptions: {subs}")
@@ -199,6 +215,7 @@ async def _register_webhook():
def _verify_secret(request: Request) -> bool:
"""Проверка webhook-секрета (пустой заголовок = OK для обратной совместимости)."""
secret = request.headers.get("X-Max-Bot-Api-Secret", "")
if not secret:
return True
@@ -206,6 +223,7 @@ def _verify_secret(request: Request) -> bool:
async def _get_active_conv_id(user_id: int) -> int | None:
"""Получение ID активного диалога пользователя."""
try:
async with async_session() as db:
result = await db.execute(
@@ -798,6 +816,7 @@ async def api_delete_conversation(conv_id: int):
@app.delete("/api/bot/users/{user_id}")
async def api_delete_bot_user(user_id: int):
"""Каскадное удаление пользователя: BotUser + BotConversation + BotMessage + BotProcessingLog. Заявки остаются."""
from app.models import BotMessage, BotProcessingLog
from sqlalchemy import delete as sa_delete
async with async_session() as db: