127 lines
4.8 KiB
Python
127 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from aiogram import F, Router
|
|
from aiogram.filters import Command
|
|
from aiogram.types import Message
|
|
|
|
from bot.access import access_denied_text, is_allowed
|
|
from bot.config import Settings
|
|
from bot.filters import NotLinked
|
|
from bot.ha_client import HaApiError, HaClient
|
|
from bot.storage import Storage
|
|
|
|
router = Router()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def _link_token(message: Message, settings: Settings, storage: Storage, token: str) -> None:
|
|
if not message.from_user:
|
|
return
|
|
|
|
telegram_id = message.from_user.id
|
|
client = HaClient(settings.ha_api_base_url)
|
|
|
|
try:
|
|
login_result = await client.login(token)
|
|
except HaApiError as exc:
|
|
await message.answer(f"Не удалось привязать токен: {exc}")
|
|
return
|
|
except Exception:
|
|
logger.exception("Login failed for telegram_id=%s", telegram_id)
|
|
await message.answer("Ошибка соединения с Home Assistant. Проверь HA_API_BASE_URL на сервере бота.")
|
|
return
|
|
|
|
api_token = str(login_result.get("token") or token).strip()
|
|
user_info = login_result.get("user") or {}
|
|
ha_user_id = int(user_info.get("id") or 0)
|
|
display_name = str(user_info.get("display_name") or user_info.get("username") or "")
|
|
username = str(user_info.get("username") or "")
|
|
|
|
ha_client = HaClient(settings.ha_api_base_url, api_token)
|
|
try:
|
|
session_id = await ha_client.find_or_create_telegram_session()
|
|
except Exception:
|
|
logger.exception("Session setup failed for telegram_id=%s", telegram_id)
|
|
await message.answer("Токен принят, но не удалось создать чат-сессию на сервере.")
|
|
return
|
|
|
|
await storage.link_user(
|
|
telegram_id=telegram_id,
|
|
api_token=api_token,
|
|
ha_user_id=ha_user_id,
|
|
display_name=display_name,
|
|
username=username,
|
|
session_id=session_id,
|
|
)
|
|
|
|
name = display_name or username or f"user #{ha_user_id}"
|
|
await message.answer(
|
|
f"Готово! Привязан аккаунт: {name}\n"
|
|
f"Чат-сессия Telegram: #{session_id}\n\n"
|
|
"Рекомендую удалить сообщение с токеном из истории чата.\n"
|
|
"Можешь писать ассистенту обычными сообщениями."
|
|
)
|
|
|
|
|
|
@router.message(Command("logout"))
|
|
async def cmd_logout(message: Message, settings: Settings, storage: Storage) -> None:
|
|
if not is_allowed(message, settings):
|
|
await message.answer(access_denied_text())
|
|
return
|
|
if not message.from_user:
|
|
return
|
|
|
|
removed = await storage.unlink_user(message.from_user.id)
|
|
if removed:
|
|
await message.answer("API-токен отвязан. Чтобы снова пользоваться ботом, отправь новый токен.")
|
|
else:
|
|
await message.answer("Токен не был привязан.")
|
|
|
|
|
|
@router.message(Command("whoami"))
|
|
async def cmd_whoami(message: Message, settings: Settings, storage: Storage) -> None:
|
|
if not is_allowed(message, settings):
|
|
await message.answer(access_denied_text())
|
|
return
|
|
if not message.from_user:
|
|
return
|
|
|
|
linked = await storage.get_user(message.from_user.id)
|
|
if not linked:
|
|
await message.answer("Токен не привязан. Отправь API-токен или /start.")
|
|
return
|
|
|
|
client = HaClient(settings.ha_api_base_url, linked.api_token)
|
|
try:
|
|
me = await client.me()
|
|
user = me.get("user") or {}
|
|
name = user.get("display_name") or user.get("username") or linked.display_name
|
|
username = user.get("username") or linked.username
|
|
await message.answer(
|
|
f"Home Assistant: {name} (@{username})\n"
|
|
f"HA user id: {linked.ha_user_id}\n"
|
|
f"Telegram-сессия: #{linked.session_id}"
|
|
)
|
|
except Exception:
|
|
await message.answer(
|
|
f"Привязан локально: {linked.display_name or linked.username}\n"
|
|
f"Telegram-сессия: #{linked.session_id}\n"
|
|
"(Не удалось проверить токен на сервере — возможно, он отозван.)"
|
|
)
|
|
|
|
|
|
@router.message(F.text & ~F.text.startswith("/"), NotLinked())
|
|
async def handle_possible_token(message: Message, settings: Settings, storage: Storage) -> None:
|
|
if not is_allowed(message, settings):
|
|
return
|
|
if not message.from_user or not message.text:
|
|
return
|
|
|
|
token = message.text.strip()
|
|
if len(token) < 8:
|
|
return
|
|
|
|
await _link_token(message, settings, storage, token)
|