381 lines
14 KiB
Python
381 lines
14 KiB
Python
import logging.config
|
||
|
||
from aiogram import F, Router
|
||
from aiogram.filters import Command
|
||
from aiogram.fsm.context import FSMContext
|
||
from aiogram.types import CallbackQuery, Message
|
||
|
||
import app.telegram.keyboards.inline as kbi
|
||
import app.telegram.keyboards.reply as kbr
|
||
import database.request as rq
|
||
from app.bybit.profile_bybit import user_profile_bybit
|
||
from app.telegram.functions.profile_tg import user_profile_tg
|
||
from logger_helper.logger_helper import LOGGING_CONFIG
|
||
|
||
logging.config.dictConfig(LOGGING_CONFIG)
|
||
logger = logging.getLogger("handlers_main")
|
||
|
||
router_handlers_main = Router(name="handlers_main")
|
||
|
||
|
||
@router_handlers_main.message(Command("start", "hello"))
|
||
@router_handlers_main.message(F.text.lower() == "привет")
|
||
async def cmd_start(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handle the /start or /hello commands and the text message "привет".
|
||
|
||
Checks if the user exists in the database and sends a user profile or creates a new user
|
||
with default settings and greeting message.
|
||
|
||
Args:
|
||
message (Message): Incoming Telegram message object.
|
||
state (FSMContext): FSMContext for managing user state.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
tg_id = message.from_user.id
|
||
username = message.from_user.username
|
||
full_name = message.from_user.full_name
|
||
user = await rq.get_user(tg_id)
|
||
try:
|
||
if user:
|
||
await user_profile_tg(tg_id=message.from_user.id, message=message)
|
||
logger.debug(
|
||
"Command start processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
else:
|
||
await rq.create_user(tg_id=tg_id, username=username)
|
||
await rq.set_user_symbol(tg_id=tg_id, symbol="BTCUSDT")
|
||
await rq.create_user_additional_settings(tg_id=tg_id)
|
||
await rq.create_user_risk_management(tg_id=tg_id)
|
||
await rq.create_user_conditional_settings(tg_id=tg_id)
|
||
await message.answer(
|
||
text=f"Добро пожаловать, {full_name}!\n\n"
|
||
"Чат-робот для трейдинга - ваш надежный помощник для анализа рынка и принятия взвешенных решений.😉",
|
||
reply_markup=kbi.connect_the_platform,
|
||
)
|
||
logger.debug(
|
||
"Command start processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command start for user %s: %s", message.from_user.id, e
|
||
)
|
||
await message.answer(text="Произошла ошибка. Пожалуйста, попробуйте позже.")
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_handlers_main.message(Command("profile"))
|
||
@router_handlers_main.message(F.text == "Профиль")
|
||
async def cmd_to_main(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handle the /profile command or text "Профиль".
|
||
|
||
Clears the current FSM state and sends the Telegram user profile.
|
||
|
||
Args:
|
||
message (Message): Incoming Telegram message object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await user_profile_tg(tg_id=message.from_user.id, message=message)
|
||
logger.debug(
|
||
"Command to_profile_tg processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command to_profile_tg for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_handlers_main.message(Command("bybit"))
|
||
@router_handlers_main.message(F.text == "Панель Bybit")
|
||
async def profile_bybit(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handle the /bybit command or text "Панель Bybit".
|
||
|
||
Clears FSM state and sends Bybit trading panel profile.
|
||
|
||
Args:
|
||
message (Message): Incoming Telegram message object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
await user_profile_bybit(
|
||
tg_id=message.from_user.id, message=message, state=state
|
||
)
|
||
logger.debug(
|
||
"Command to_profile_bybit processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command to_profile_bybit for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_handlers_main.callback_query(F.data == "profile_bybit")
|
||
async def profile_bybit_callback(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handle callback query with data "profile_bybit".
|
||
|
||
Clears FSM state and sends the Bybit profile in response.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Callback query object from Telegram.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
await user_profile_bybit(
|
||
tg_id=callback_query.from_user.id,
|
||
message=callback_query.message,
|
||
state=state,
|
||
)
|
||
logger.debug(
|
||
"Callback profile_bybit processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
await callback_query.answer()
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing callback profile_bybit for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_handlers_main.callback_query(F.data == "main_settings")
|
||
async def settings(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handle callback query with data "main_settings".
|
||
|
||
Clears FSM state and edits the message to show main settings options.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Callback query object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
msg = await callback_query.message.edit_text(
|
||
text="Выберите, что вы хотите настроить:", reply_markup=kbi.main_settings
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command settings processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command settings for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_handlers_main.message(Command("connect"))
|
||
@router_handlers_main.message(F.text == "Подключить платформу Bybit")
|
||
async def cmd_connect(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handle the /connect command or text "Подключить платформу Bybit".
|
||
|
||
Clears FSM state and sends a connection message.
|
||
|
||
Args:
|
||
message (Message): Incoming Telegram message object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
user = await rq.get_user(tg_id=message.from_user.id)
|
||
if user:
|
||
await message.answer(
|
||
text=(
|
||
"Подключение Bybit аккаунта \n\n"
|
||
"1. Зарегистрируйтесь или войдите в свой аккаунт на Bybit по ссылке: "
|
||
"[Перейти на Bybit](https://www.bybit.com/invite?ref=YME83OJ).\n"
|
||
"2. В личном кабинете выберите раздел API. \n"
|
||
"3. Создание нового API ключа\n"
|
||
" - Нажмите кнопку Create New Key (Создать новый ключ).\n"
|
||
" - Выберите системно-сгенерированный ключ.\n"
|
||
" - Укажите название API ключа (любое). \n"
|
||
" - Выберите права доступа для торговли (Trade). \n"
|
||
" - Можно ограничить доступ по IP для безопасности.\n"
|
||
"4. Подтверждение создания\n"
|
||
" - Подтвердите создание ключа.\n"
|
||
" - Отправьте чат-роботу.\n\n"
|
||
"Важно: сохраните отдельно API Key и Secret Key в надежном месте. Secret ключ отображается только один раз."
|
||
),
|
||
parse_mode="Markdown",
|
||
reply_markup=kbi.add_bybit_api,
|
||
disable_web_page_preview=True,
|
||
)
|
||
else:
|
||
await rq.create_user(
|
||
tg_id=message.from_user.id, username=message.from_user.username
|
||
)
|
||
await rq.set_user_symbol(tg_id=message.from_user.id, symbol="BTCUSDT")
|
||
await rq.create_user_additional_settings(tg_id=message.from_user.id)
|
||
await rq.create_user_risk_management(tg_id=message.from_user.id)
|
||
await rq.create_user_conditional_settings(tg_id=message.from_user.id)
|
||
await cmd_connect(message=message, state=state)
|
||
logger.debug(
|
||
"Command connect processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command connect for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_handlers_main.message(Command("help"))
|
||
async def cmd_help(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handle the /help command.
|
||
|
||
Clears FSM state and sends a help message with available commands and reply keyboard.
|
||
|
||
Args:
|
||
message (Message): Incoming Telegram message object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
await message.answer(
|
||
text="Используйте одну из следующих команд:\n"
|
||
"/start - Запустить бота\n"
|
||
"/profile - Профиль\n"
|
||
"/bybit - Панель Bybit\n"
|
||
"/connect - Подключиться к платформе\n",
|
||
reply_markup=kbr.profile,
|
||
)
|
||
logger.debug(
|
||
"Command help processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command help for user %s: %s", message.from_user.id, e
|
||
)
|
||
await message.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbr.profile,
|
||
)
|
||
|
||
|
||
@router_handlers_main.message(Command("cancel"))
|
||
@router_handlers_main.message(
|
||
lambda message: message.text.casefold() in ["cancel", "отмена"]
|
||
)
|
||
async def cmd_cancel_handler(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handle /cancel command or text 'cancel'/'отмена'.
|
||
|
||
If there is an active FSM state, clears it and informs the user.
|
||
Otherwise, informs that no operation was in progress.
|
||
|
||
Args:
|
||
message (Message): Incoming Telegram message object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
current_state = await state.get_state()
|
||
|
||
if current_state is None:
|
||
await message.reply(
|
||
text="Хорошо, но ничего не происходило.", reply_markup=kbr.profile
|
||
)
|
||
logger.debug(
|
||
"Cancel command received but no active state for user %s.",
|
||
message.from_user.id,
|
||
)
|
||
return
|
||
|
||
try:
|
||
await state.clear()
|
||
await message.reply(text="Команда отменена.", reply_markup=kbr.profile)
|
||
logger.debug(
|
||
"Command cancel executed successfully. State cleared for user %s.",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error while cancelling command for user %s: %s", message.from_user.id, e
|
||
)
|
||
await message.answer(
|
||
text="Произошла ошибка при отмене. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbr.profile,
|
||
)
|
||
|
||
|
||
@router_handlers_main.callback_query(F.data == "cancel")
|
||
async def cmd_cancel(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handle callback query with data "cancel".
|
||
|
||
Clears the FSM state and sends a cancellation message.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Callback query object.
|
||
state (FSMContext): FSM state context.
|
||
|
||
Raises:
|
||
None: Exceptions are caught and logged internally.
|
||
"""
|
||
try:
|
||
await callback_query.message.delete()
|
||
await user_profile_bybit(
|
||
tg_id=callback_query.from_user.id,
|
||
message=callback_query.message,
|
||
state=state,
|
||
)
|
||
logger.debug(
|
||
"Command cancel processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command cancel for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear() |